diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index db218d4a7..24c92e58e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,7 +22,6 @@ cd PerlOnJava # Build and run tests make # Build + run all unit tests -make dev # Build only, skip tests (for quick iteration during debugging) # Run comprehensive tests make test-all @@ -103,9 +102,6 @@ perl5_t/ (at project root) # Build + run all unit tests (default) make -# Build only, skip tests (for quick iteration during debugging) -make dev - # Run all tests including Perl 5 core tests make test-all diff --git a/Configure.pl b/Configure.pl index 6c298725d..63f22b8c7 100755 --- a/Configure.pl +++ b/Configure.pl @@ -10,13 +10,13 @@ # PerlOnJava Configuration Script # # This script manages configuration settings and dependencies for the PerlOnJava project. -# It updates Configuration.java (the single source of truth for version info) and +# It updates Configuration.java.in (the single source of truth for version info) and # propagates version changes to all relevant files in the repository. # # USAGE: # # ./Configure.pl # Show current configuration -# ./Configure.pl -D version=5.43.0 # Update version everywhere +# ./Configure.pl -D version=5.44.0 # Update version everywhere # ./Configure.pl --upgrade # Upgrade dependencies to latest versions # # VERSION UPDATE BEHAVIOR: @@ -50,7 +50,7 @@ my %config; # Hash to store key-value pairs for configuration updates my $help = 0; # Flag to show help message -my $java_config_filename = 'src/main/java/org/perlonjava/core/Configuration.java'; +my $java_config_filename = 'src/main/java/org/perlonjava/core/Configuration.java.in'; # Parse command-line options Getopt::Long::Configure("no_ignore_case"); @@ -88,8 +88,8 @@ sub show_help { -D key=value Set configuration value Supported configuration keys: - version - PerlOnJava version (e.g., 5.43.0) - Updates Configuration.java, build files, and all JAR references + version - PerlOnJava version (e.g., 5.44.0) + Updates Configuration.java.in, build files, and all JAR references Read-only keys (managed by build system): gitCommitId - Git commit hash (set during build) @@ -103,7 +103,7 @@ sub show_help { Examples: ./Configure.pl # Show current configuration - ./Configure.pl -D version=5.43.0 # Update version everywhere + ./Configure.pl -D version=5.44.0 # Update version everywhere ./Configure.pl --search org.h2.Driver # Search for JDBC driver ./Configure.pl --direct com.h2database:h2:2.2.224 ./Configure.pl --upgrade # Upgrade all dependencies @@ -170,9 +170,31 @@ sub update_configuration { } write_file($file, $content); + sync_generated_configuration($config); print "\nConfiguration updated successfully\n"; } +# Keep an existing local generated file in sync with the tracked template. +# The build recreates this file on a fresh checkout, but developers commonly +# retain it between builds. +sub sync_generated_configuration { + my ($config) = @_; + (my $generated_file = $java_config_filename) =~ s/\.in$//; + return if $generated_file eq $java_config_filename || !-f $generated_file; + + my $content = read_file($generated_file); + my $updated = 0; + for my $key (keys %$config) { + next if $key eq 'gitCommitId' || $key eq 'gitCommitDate'; + my $value = $config->{$key}; + my $quoted_value = $value =~ /^(?:true|false|\d+)$/ ? $value : qq{"$value"}; + $updated = 1 + if $content =~ s/(public static final \w+\s+\Q$key\E\s*=\s*)("[^"]*"|[^;]+);/${1}$quoted_value;/; + } + + write_file($generated_file, $content) if $updated; +} + # Function to validate version changes before applying them sub validate_version_change { my ($old_version, $new_version) = @_; @@ -206,6 +228,7 @@ sub update_version_everywhere { my @excluded_dirs = ( './src/main/perl', # Perl modules with historical version docs './dev', # Design documents and development notes + './perl5', # Nested upstream Perl checkout ); # Files to exclude from version updates (relative to project root) @@ -217,7 +240,7 @@ sub update_version_everywhere { # First pass: Update JAR filename references in ALL files (always safe) # This includes: jperl, jperl.bat, docs, examples, src/main/perl comments, etc. # Matches both perlonjava-X.Y.Z.jar and perlonjava-X.Y.Z-all.jar - my @all_files = `find . -type f -not -path "*/\\.*" -not -path "*/build/*" -not -path "*/target/*"`; + my @all_files = `find . -type f -not -path "*/\\.*" -not -path "*/build/*" -not -path "*/target/*" -not -path "./perl5/*"`; foreach my $file (@all_files) { chomp $file; next if -B $file; # Skip binary files @@ -246,7 +269,7 @@ sub update_version_everywhere { my $updated = 0; # Update version in build.gradle (project version only) - if ($file =~ /build\.gradle$/ && $file_content =~ s/^(version\s*=\s*')$old_version(')\s*$/$1$new_version$2/m) { + if ($file =~ /build\.gradle$/ && $file_content =~ s/^(version\s*=\s*')$old_version(')[ \t]*$/$1$new_version$2/m) { $updated = 1; print "Updated version in $file\n"; } @@ -262,7 +285,9 @@ sub update_version_everywhere { # Update version in README.md (feature support line) if ($file =~ /README\.md$/) { - if ($file_content =~ s/(Supports most Perl )$old_version( features)/$1$new_version$2/g) { + (my $old_feature_version = $old_version) =~ s/\.0$//; + (my $new_feature_version = $new_version) =~ s/\.0$//; + if ($file_content =~ s/(Perl )\Q$old_feature_version\E( language compatibility)/$1$new_feature_version$2/g) { $updated = 1; print "Updated version in $file\n"; } @@ -316,7 +341,7 @@ sub update_config_pm { $updated = 1; } - # Pattern: path components like /5.42.0/ + # Pattern: path components like /X.Y.Z/ if ($content =~ s|(/perl5/)$old_version(/)|$1$new_version$2|g) { $updated = 1; } @@ -326,6 +351,34 @@ sub update_config_pm { if ($content =~ s|(/vendor_perl/)$old_version(/)|$1$new_version$2|g) { $updated = 1; } + + # Config.pm also contains versioned paths assembled from quoted components + # and paths whose version is immediately followed by a quote. + if ($content =~ s|('perl5',\s*')$old_version(')|$1$new_version$2|g) { + $updated = 1; + } + if ($content =~ s{((?:site|vendor)_perl/)\Q$old_version\E(?=['/])}{$1$new_version}g) { + $updated = 1; + } + + my ($new_major, $new_minor, $new_patch) = split /\./, $new_version; + $new_patch //= 0; + my $new_decimal_version = sprintf '%d.%03d%03d', $new_major, $new_minor, $new_patch; + if ($content =~ s/(\$VERSION\s*=\s*")\d+\.\d+(")/$1$new_decimal_version$2/) { + $updated = 1; + } + if ($content =~ s/(version_patchlevel_string\s*=>\s*'version\s+)\d+(\s+patchlevel\s+)\d+(')/$1$new_minor$2$new_patch$3/) { + $updated = 1; + } + if ($content =~ s/(api_version\s*=>\s*')\d+(')/$1$new_minor$2/) { + $updated = 1; + } + if ($content =~ s/(api_subversion\s*=>\s*')\d+(')/$1$new_patch$2/) { + $updated = 1; + } + if ($content =~ s/(revision\s+)\d+(\s+version\s+)\d+(\s+subversion\s+)\d+/$1$new_major$2$new_minor$3$new_patch/) { + $updated = 1; + } if ($updated) { write_file($config_pm, $content); diff --git a/Dockerfile b/Dockerfile index dc9042e49..f0350f73b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,7 +24,7 @@ FROM eclipse-temurin:22-jdk WORKDIR /app # Copy the built JAR file from the Maven container -COPY --from=build /app/target/perlonjava-5.42.0.jar /app/perlonjava-5.42.0.jar +COPY --from=build /app/target/perlonjava-5.44.0.jar /app/perlonjava-5.44.0.jar # Copy the wrapper scripts COPY --from=build /app/jperl /app/jperl diff --git a/QUICKSTART.md b/QUICKSTART.md index 987190aa4..48279686f 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -40,7 +40,7 @@ cd PerlOnJava make ``` -The `make` command builds the project and runs all unit tests. The complete build with tests typically completes in ~30 seconds. +The `make` command builds the runnable JAR and runs the fast unit test suite. **Build troubleshooting:** @@ -67,7 +67,8 @@ make clean make ``` -The project uses Gradle 9.0+ (configured in the wrapper) which supports Java 22-25+. +Use the Gradle version configured in `gradle/wrapper/gradle-wrapper.properties`; +the checked-in wrapper is kept aligned with the project's JDK requirement. For more troubleshooting: See [Installation Guide](docs/getting-started/installation.md#troubleshooting) diff --git a/README.md b/README.md index 34fa0a24d..858033078 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ PerlOnJava compiles Perl to JVM bytecode — run existing Perl scripts on any pl - **Install more with jcpan** — [pure-Perl CPAN modules](docs/guides/using-cpan-modules.md) work out of the box - **JDBC database access** — [PostgreSQL, MySQL, SQLite, Oracle](docs/guides/database-access.md) via standard JDBC drivers - **Embed in Java apps** — [JSR-223 ScriptEngine](docs/guides/java-integration.md) integration -- **Perl 5.42 language compatibility** — [see feature matrix](docs/reference/feature-matrix.md) +- **Perl 5.44 language compatibility** — [see feature matrix](docs/reference/feature-matrix.md) ## Quick Start diff --git a/build.gradle b/build.gradle index 6e913b1fe..42d4b352d 100644 --- a/build.gradle +++ b/build.gradle @@ -69,7 +69,7 @@ tasks.buildDeb { // Project metadata group = 'org.perlonjava' -version = '5.42.0' +version = '5.44.0' // CycloneDX SBOM generation configuration cyclonedxBom { diff --git a/dev/design/bytecode_debugging.md b/dev/design/bytecode_debugging.md index 8a869d04d..220114db3 100644 --- a/dev/design/bytecode_debugging.md +++ b/dev/design/bytecode_debugging.md @@ -139,5 +139,5 @@ Fix strategy: ## Notes -- `jperl` runs `target/perlonjava-5.42.0.jar`. Rebuild after changes, otherwise you may be debugging stale code. +- `jperl` runs `target/perlonjava-5.44.0.jar`. Rebuild after changes, otherwise you may be debugging stale code. - `JPERL_ASM_DEBUG_CLASS` is useful to avoid massive logs during large tests. diff --git a/dev/design/debugger.md b/dev/design/debugger.md index 81243f399..82759c3ff 100644 --- a/dev/design/debugger.md +++ b/dev/design/debugger.md @@ -28,7 +28,7 @@ This client would use JPDA to communicate with the JVM, but would present the de ## Run PerlOnJava with Debug Flags ```bash -java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005 -jar target/perlonjava-5.42.0.jar myscript.pl +java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005 -jar target/perlonjava-5.44.0.jar myscript.pl ``` ## Start Debugging diff --git a/dev/design/getting_started.md b/dev/design/getting_started.md index c0607f375..bcc29e20b 100644 --- a/dev/design/getting_started.md +++ b/dev/design/getting_started.md @@ -8,12 +8,12 @@ This guide helps you start using PerlOnJava to run Perl code on the Java Virtual 1. Download the JAR file: ```bash -java -jar target/perlonjava-5.42.0.jar +java -jar target/perlonjava-5.44.0.jar ``` 2. Run your first Perl script: ```bash -java -jar target/perlonjava-5.42.0.jar -E 'print "Hello from Perl on JVM!\n"' +java -jar target/perlonjava-5.44.0.jar -E 'print "Hello from Perl on JVM!\n"' ``` ## Basic Usage Examples @@ -22,12 +22,12 @@ java -jar target/perlonjava-5.42.0.jar -E 'print "Hello from Perl on JVM!\n"' Run a Perl file: ```bash -java -jar target/perlonjava-5.42.0.jar script.pl +java -jar target/perlonjava-5.44.0.jar script.pl ``` Run Perl code directly: ```bash -java -jar target/perlonjava-5.42.0.jar -E 'for (1..3) { print "$_\n" }' +java -jar target/perlonjava-5.44.0.jar -E 'for (1..3) { print "$_\n" }' ``` ### 2. Using Modules @@ -90,12 +90,12 @@ Common switches: Enable debugging output: ```bash -java -jar target/perlonjava-5.42.0.jar --debug script.pl +java -jar target/perlonjava-5.44.0.jar --debug script.pl ``` View generated bytecode: ```bash -java -jar target/perlonjava-5.42.0.jar --disassemble script.pl +java -jar target/perlonjava-5.44.0.jar --disassemble script.pl ``` ## Next Steps diff --git a/dev/design/graalvm.md b/dev/design/graalvm.md index 5712fcca5..7850e9e3c 100644 --- a/dev/design/graalvm.md +++ b/dev/design/graalvm.md @@ -42,7 +42,7 @@ Added GraalVM support to pom.xml in a dedicated profile: Used GraalVM tracing agent to capture required runtime methods: ```bash -java -agentlib:native-image-agent=config-output-dir=src/main/resources/META-INF/native-image -jar target/perlonjava-5.42.0.jar examples/life.pl +java -agentlib:native-image-agent=config-output-dir=src/main/resources/META-INF/native-image -jar target/perlonjava-5.44.0.jar examples/life.pl ``` ## Results diff --git a/dev/design/maven-central-publishing.md b/dev/design/maven-central-publishing.md index 5e6986d59..bd0eb9cdd 100644 --- a/dev/design/maven-central-publishing.md +++ b/dev/design/maven-central-publishing.md @@ -25,7 +25,7 @@ Publishing to Maven Central provides: |-------------|--------| | GroupId (`org.perlonjava`) | ✅ Valid | | ArtifactId (`perlonjava`) | ✅ Valid | -| Version (`5.42.0`) | ✅ Valid (not -SNAPSHOT) | +| Version (`5.44.0`) | ✅ Valid (not -SNAPSHOT) | | POM `` | ✅ Present | | POM `` | ❌ **Missing** | | POM `` | ⚠️ Placeholder (`http://maven.apache.org`) | @@ -55,7 +55,7 @@ Reference: [Sonatype Requirements](https://central.sonatype.org/publish/requirem org.perlonjava perlonjava -5.42.0 +5.44.0 jar @@ -100,10 +100,10 @@ For each release, Maven Central requires: | Artifact | Description | |----------|-------------| -| `perlonjava-5.42.0.jar` | Main JAR (already built) | -| `perlonjava-5.42.0.pom` | POM file with metadata | -| `perlonjava-5.42.0-sources.jar` | Source code JAR | -| `perlonjava-5.42.0-javadoc.jar` | Javadoc JAR | +| `perlonjava-5.44.0.jar` | Main JAR (already built) | +| `perlonjava-5.44.0.pom` | POM file with metadata | +| `perlonjava-5.44.0-sources.jar` | Source code JAR | +| `perlonjava-5.44.0-javadoc.jar` | Javadoc JAR | | `*.asc` | GPG signatures for all above | | `*.md5`, `*.sha1` | Checksums for all above | diff --git a/dev/design/sbom.md b/dev/design/sbom.md index 4cc12d20a..81f9d8d27 100644 --- a/dev/design/sbom.md +++ b/dev/design/sbom.md @@ -203,7 +203,7 @@ my $bom = SBOM::CycloneDX->new(spec_version => '1.6'); my $root = SBOM::CycloneDX::Component->new( type => COMPONENT_TYPE_APPLICATION, name => 'perlonjava-perl-modules', - version => $ENV{VERSION} // '5.42.0', + version => $ENV{VERSION} // '5.44.0', licenses => [SBOM::CycloneDX::License->new(id => 'Artistic-2.0')], bom_ref => 'perlonjava-perl' ); @@ -302,7 +302,7 @@ During build, SBOMs are generated to: SBOMs can be embedded inside the JAR for easy discovery: ``` -perlonjava-5.42.0.jar +perlonjava-5.44.0.jar ├── META-INF/ │ ├── MANIFEST.MF │ └── sbom/ @@ -335,7 +335,7 @@ For Debian packages, SBOMs go in the standard documentation directory: ├── bin/ │ └── jperl ├── lib/ -│ └── perlonjava-5.42.0.jar +│ └── perlonjava-5.44.0.jar └── share/ └── sbom/ ├── bom.json @@ -370,11 +370,11 @@ ospackage { SBOMs should also be attached as separate release artifacts: ``` -Release v5.42.0 -├── perlonjava-5.42.0.jar -├── perlonjava_5.42.0_amd64.deb -├── perlonjava-5.42.0-sbom.json # Standalone SBOM -└── perlonjava-5.42.0-sbom.xml # Standalone SBOM (XML) +Release v5.44.0 +├── perlonjava-5.44.0.jar +├── perlonjava_5.44.0_amd64.deb +├── perlonjava-5.44.0-sbom.json # Standalone SBOM +└── perlonjava-5.44.0-sbom.xml # Standalone SBOM (XML) ``` This allows consumers to inspect the SBOM without downloading/extracting the full package. @@ -542,7 +542,7 @@ The generated SBOM must include: PerlOnJava ships as a **shaded/uber JAR** containing everything: ``` -perlonjava-5.42.0.jar +perlonjava-5.44.0.jar ├── org/perlonjava/... (PerlOnJava Java classes) ├── org/ow2/asm/... (shaded ASM library) ├── com/ibm/icu/... (shaded ICU4J library) @@ -590,17 +590,17 @@ The Perl SBOM should include: The final distribution artifacts should have accompanying hash files: ``` -Release v5.42.0/ -├── perlonjava-5.42.0.jar -├── perlonjava-5.42.0.jar.sha256 # echo "abc123... perlonjava-5.42.0.jar" -├── perlonjava_5.42.0_amd64.deb -├── perlonjava_5.42.0_amd64.deb.sha256 -└── perlonjava-5.42.0-sbom.json # SBOM (contains component hashes) +Release v5.44.0/ +├── perlonjava-5.44.0.jar +├── perlonjava-5.44.0.jar.sha256 # echo "abc123... perlonjava-5.44.0.jar" +├── perlonjava_5.44.0_amd64.deb +├── perlonjava_5.44.0_amd64.deb.sha256 +└── perlonjava-5.44.0-sbom.json # SBOM (contains component hashes) ``` Generate with: ```bash -sha256sum perlonjava-5.42.0.jar > perlonjava-5.42.0.jar.sha256 +sha256sum perlonjava-5.44.0.jar > perlonjava-5.44.0.jar.sha256 ``` ### Supported Hash Algorithms diff --git a/dev/design/scriptingapi.md b/dev/design/scriptingapi.md index 5f814f936..974c5effc 100644 --- a/dev/design/scriptingapi.md +++ b/dev/design/scriptingapi.md @@ -7,7 +7,7 @@ - Note that `jrunscript` creates a new scope every time, so it doesn't keep lexical variables from one line to the next. ```sh - $ jrunscript -cp target/perlonjava-5.42.0.jar -l perl + $ jrunscript -cp target/perlonjava-5.44.0.jar -l perl Perl5> my $sub = sub { say $_[0] }; $sub->($_) for 4,5,6; 4 5 @@ -54,4 +54,3 @@ public class Main { } } ``` - diff --git a/dev/design/windows_installer.md b/dev/design/windows_installer.md index f0c0378d8..f83cf0812 100644 --- a/dev/design/windows_installer.md +++ b/dev/design/windows_installer.md @@ -84,7 +84,7 @@ C:\Program Files\PerlOnJava\ ├── bin\ │ └── jperl.exe ├── lib\ -│ └── perlonjava-5.42.0.jar +│ └── perlonjava-5.44.0.jar └── runtime\ └── [JRE files] ``` \ No newline at end of file diff --git a/dev/modules/dynamic_loading.md b/dev/modules/dynamic_loading.md index 27338ebd5..4b880e6a5 100644 --- a/dev/modules/dynamic_loading.md +++ b/dev/modules/dynamic_loading.md @@ -325,7 +325,7 @@ The build creates multiple JAR files in target/: ``` target/ - perlonjava-5.42.0.jar # Core runtime + perlonjava-5.44.0.jar # Core runtime perlonjava-module-dbi-3.0.0.jar # DBI module ``` diff --git a/dev/modules/gtk2.md b/dev/modules/gtk2.md index 41edcb657..cbeab6adf 100644 --- a/dev/modules/gtk2.md +++ b/dev/modules/gtk2.md @@ -392,7 +392,7 @@ set FX_LIBS=%SCRIPT_DIR%lib\javafx java %JVM_OPTS% %JPERL_OPTS% ^ --module-path "%FX_LIBS%" ^ --add-modules javafx.controls,javafx.graphics,javafx.base ^ - -cp "%SCRIPT_DIR%target\perlonjava-5.42.0.jar" ^ + -cp "%SCRIPT_DIR%target\perlonjava-5.44.0.jar" ^ org.perlonjava.app.cli.Main %* ``` diff --git a/dev/presentations/German_Perl_Raku_Workshop_2026/presentation_plan.md b/dev/presentations/German_Perl_Raku_Workshop_2026/presentation_plan.md index b0d76142c..3f9802899 100644 --- a/dev/presentations/German_Perl_Raku_Workshop_2026/presentation_plan.md +++ b/dev/presentations/German_Perl_Raku_Workshop_2026/presentation_plan.md @@ -594,7 +594,7 @@ Object result = perl.eval("process_data($data)"); ### 5.2 Current Development & Roadmap (3 minutes) -**Recently Completed (v5.42.3)**: +**Recently Completed (v5.44.0)**: - ✅ Interpreter backend production-ready - ✅ Full Perl 5.38+ class features - ✅ System V IPC operators (msgctl, semctl, shmctl) diff --git a/dev/presentations/German_Perl_Raku_Workshop_2026/slide-deck-plan.md b/dev/presentations/German_Perl_Raku_Workshop_2026/slide-deck-plan.md index b9972a85b..bb950872c 100644 --- a/dev/presentations/German_Perl_Raku_Workshop_2026/slide-deck-plan.md +++ b/dev/presentations/German_Perl_Raku_Workshop_2026/slide-deck-plan.md @@ -63,7 +63,7 @@ - Interactive debugger (`-d`) **Slide 6 — One JAR, Everything Included** -- `perlonjava-5.42.0.jar` — 25 MB, zero external dependencies +- `perlonjava-5.44.0.jar` — 25 MB, zero external dependencies - Diagram: 392 compiled classes + 341 Perl modules + bundled Java libs - `java -jar perlonjava.jar script.pl` — that's it - _Establishes simplicity before going deeper_ diff --git a/dev/presentations/German_Perl_Raku_Workshop_2026/slides-part1-intro.md b/dev/presentations/German_Perl_Raku_Workshop_2026/slides-part1-intro.md index f2093bda2..b2beb9c22 100644 --- a/dev/presentations/German_Perl_Raku_Workshop_2026/slides-part1-intro.md +++ b/dev/presentations/German_Perl_Raku_Workshop_2026/slides-part1-intro.md @@ -68,7 +68,7 @@ JSR-223 is the standard Java scripting API, available since Java 6. It allows bi ## One JAR, Everything Included -**`perlonjava-5.42.0.jar`** — 25 MB, zero external dependencies +**`perlonjava-5.44.0.jar`** — 25 MB, zero external dependencies ```text perlonjava.jar diff --git a/dev/presentations/German_Perl_Raku_Workshop_2026/slides.md b/dev/presentations/German_Perl_Raku_Workshop_2026/slides.md index bf575e75b..fbba0bd93 100644 --- a/dev/presentations/German_Perl_Raku_Workshop_2026/slides.md +++ b/dev/presentations/German_Perl_Raku_Workshop_2026/slides.md @@ -69,7 +69,7 @@ JSR-223 is the standard Java scripting API, available since Java 6. Bidirectiona ## One JAR, Everything Included -**`perlonjava-5.42.0.jar`** — 25 MB, zero external dependencies +**`perlonjava-5.44.0.jar`** — 25 MB, zero external dependencies ```text perlonjava.jar diff --git a/dev/presentations/blogs_perl_org_jcpan_2026/blog-post-long.md b/dev/presentations/blogs_perl_org_jcpan_2026/blog-post-long.md index 76dcedecb..659966ce5 100644 --- a/dev/presentations/blogs_perl_org_jcpan_2026/blog-post-long.md +++ b/dev/presentations/blogs_perl_org_jcpan_2026/blog-post-long.md @@ -212,4 +212,4 @@ The project is at [github.com/fglock/PerlOnJava](https://github.com/fglock/PerlO --- -*PerlOnJava implements Perl 5.42 semantics and is validated against the Perl test suite. It's been in development since 2024, building on nearly 30 years of prior work on Perl-JVM integration.* +*PerlOnJava implements Perl 5.44 semantics and is validated against the Perl test suite. It's been in development since 2024, building on nearly 30 years of prior work on Perl-JVM integration.* diff --git a/dev/sandbox/command_line.pl b/dev/sandbox/command_line.pl index 204975369..e7e7bb623 100644 --- a/dev/sandbox/command_line.pl +++ b/dev/sandbox/command_line.pl @@ -8,7 +8,7 @@ my $perl; $perl = 'perl'; -$perl = 'java -jar target/perlonjava-5.42.0.jar'; +$perl = 'java -jar target/perlonjava-5.44.0.jar'; # Test -c (compile only) { diff --git a/dev/tools/generate-perl-sbom.pl b/dev/tools/generate-perl-sbom.pl index f4bc5187a..11febae3d 100755 --- a/dev/tools/generate-perl-sbom.pl +++ b/dev/tools/generate-perl-sbom.pl @@ -9,7 +9,7 @@ # perl dev/tools/generate-perl-sbom.pl > build/reports/perl-bom.json # # Environment variables: -# VERSION - Override the version string (default: 5.42.0) +# VERSION - Override the version string (default: 5.44.0) use strict; use warnings; @@ -26,7 +26,7 @@ die "Error: Perl library directory not found: $lib_dir\n" unless -d $lib_dir; # Configuration -my $version = $ENV{VERSION} // '5.42.0'; +my $version = $ENV{VERSION} // '5.44.0'; my $timestamp = strftime('%Y-%m-%dT%H:%M:%SZ', gmtime()); my $serial_number = generate_uuid(); diff --git a/dev/tools/merge-sbom.pl b/dev/tools/merge-sbom.pl index 2805d99a5..f4a744360 100755 --- a/dev/tools/merge-sbom.pl +++ b/dev/tools/merge-sbom.pl @@ -30,7 +30,7 @@ my $serial_number = generate_uuid(); # Get version from Java BOM metadata -my $version = $java_bom->{metadata}{component}{version} // '5.42.0'; +my $version = $java_bom->{metadata}{component}{version} // '5.44.0'; # Build merged SBOM my $merged = { diff --git a/docs/about/changelog.md b/docs/about/changelog.md index e3d1365cc..a8fe30d35 100644 --- a/docs/about/changelog.md +++ b/docs/about/changelog.md @@ -3,8 +3,9 @@ Release history of PerlOnJava. See [Roadmap](roadmap.md) for future plans. -## v5.42.3: Unreleased - Next minor version +## v5.44.0: Named Parameters in Signatures +- Add named parameters in method and subroutine signatures. - Security: added `SECURITY.md` and CycloneDX SBOM generation (`make sbom`) - Tools: added `jcpan`, `jperldoc`, and `jprove` - Perl debugger with `-d` command line option @@ -35,8 +36,6 @@ Release history of PerlOnJava. See [Roadmap](roadmap.md) for future plans. - New command line option: `--interpreter` to run PerlOnJava as an interpreter instead of JVM compiler. - `./jperl --interpreter --disassemble -e 'print "Hello, World!\n"'` - The interpreter mode excels at dynamic eval STRING operations (46x faster than compilation for unique strings, matching Perl 5 performance). For general code, it runs only 15% slower than Perl 5. It is also useful for implementing debugging, handling "Method too large" errors, and enabling Android and GraalVM compatibility. -- Planned release date: 2026-04-10. - - Add `attributes` pragma with `MODIFY_*_ATTRIBUTES`/`FETCH_*_ATTRIBUTES` callbacks for subroutines and variables. - Add modules: `Filter::Simple` with `FILTER` and `FILTER_ONLY` support. - Add `DESTROY` method support with selective reference counting on blessed objects, cascading destruction, closure capture tracking, and global destruction phase. @@ -71,10 +70,8 @@ Release history of PerlOnJava. See [Roadmap](roadmap.md) for future plans. - utf8 pragma - bytes pragma - threads pragma - - warnings pragma - vmsish pragma - Constant folding - in ConstantFoldingVisitor.java - - `method` keyword - Overload operators: `++`, `--`. - String interpolation fixes. - Command line option `-C` @@ -369,5 +366,3 @@ Release history of PerlOnJava. See [Roadmap](roadmap.md) for future plans. - Enhanced statements, data types, and call context ## v1.0.0: Initial proof of concept for the parser and execution engine. - - diff --git a/docs/about/support.md b/docs/about/support.md index 22a04f021..a1732769b 100644 --- a/docs/about/support.md +++ b/docs/about/support.md @@ -13,17 +13,16 @@ - GitHub Discussions: General questions and community interaction - Stack Overflow: Use the tags `perl` and eventually `perlonjava` -## Long-term Support +## Version Support -PerlOnJava follows semantic versioning (MAJOR.MINOR.PATCH): -- Major versions (X.0.0): Significant features or breaking changes -- Minor versions (X.Y.0): New features and enhancements -- Patch versions (X.Y.Z): Bug fixes and minor improvements +PerlOnJava version numbers track the compatible Perl language version. For +example, PerlOnJava 5.44.0 targets Perl 5.44, and later patch releases use the +final component for PerlOnJava fixes. -### Version Support Timeline -- Current stable version receives regular updates and bug fixes -- Previous major version receives security updates for 12 months -- LTS versions are marked explicitly and supported for 24 months +The project does not currently publish a formal LTS or fixed-duration support +policy. Bug fixes and security updates target the current development and +release branches; see the [Security Policy](../../SECURITY.md) for reporting a +vulnerability. ## Contributing Guidelines @@ -70,17 +69,9 @@ Include: ## Release Process -### Release Channels -- Main: Stable releases -- Development: Preview features -- LTS: Long-term support versions - -### Version Lifecycle -1. Development in feature branches -2. Integration into development branch -3. Testing and documentation -4. Release candidate -5. Stable release +Changes are developed on feature branches, reviewed through pull requests, and +merged after testing. Release notes are maintained in the +[Changelog](changelog.md). ## Security diff --git a/docs/about/why-perlonjava.md b/docs/about/why-perlonjava.md index 8ec0cfd66..b67076e25 100644 --- a/docs/about/why-perlonjava.md +++ b/docs/about/why-perlonjava.md @@ -27,10 +27,10 @@ PerlOnJava offers a unique solution for JVM-based environments or use cases wher ### Why Not Use PerlOnJava? 1. **Mature Ecosystem of Traditional Perl**: - Perl’s implementation in C is stable, mature, and battle-tested over decades, offering extensive support for CPAN modules, including XS (C extensions), which are not supported by PerlOnJava. + Perl’s implementation in C is stable, mature, and battle-tested over decades, offering extensive CPAN support. PerlOnJava cannot load native XS (C extension) binaries directly, although it bundles Java implementations for a growing set of commonly used XS modules. 2. **Feature Limitations**: - PerlOnJava currently does not support some advanced Perl features, modules, and syntax extensions. For instance, CPAN compatibility is limited, and XS modules are unavailable. + PerlOnJava does not yet support every advanced Perl feature or CPAN module. Pure-Perl modules have the best compatibility; XS modules require a bundled or separately developed Java implementation. 3. **Portability Concerns**: While JVM provides cross-platform support, running PerlOnJava requires a JVM installation, which might not be available in lightweight or resource-constrained environments where traditional Perl could run natively. @@ -41,4 +41,3 @@ PerlOnJava offers a unique solution for JVM-based environments or use cases wher 5. **Community and Ecosystem**: The community and ecosystem around PerlOnJava are smaller than those of traditional Perl, potentially limiting support and available resources. - diff --git a/docs/getting-started/docker.md b/docs/getting-started/docker.md index 76c589cc8..2cb2002f1 100644 --- a/docs/getting-started/docker.md +++ b/docs/getting-started/docker.md @@ -86,7 +86,7 @@ Modify the `Dockerfile` to include additional dependencies: ```dockerfile # Add JDBC driver FROM eclipse-temurin:22-jdk -COPY --from=build /app/target/perlonjava-5.42.0.jar /app/perlonjava.jar +COPY --from=build /app/target/perlonjava-5.44.0.jar /app/perlonjava.jar COPY path/to/driver.jar /app/drivers/ ENV CLASSPATH=/app/drivers/driver.jar ENTRYPOINT ["java", "-jar", "/app/perlonjava.jar"] diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md index bd8d32072..3fd059e50 100644 --- a/docs/getting-started/installation.md +++ b/docs/getting-started/installation.md @@ -24,8 +24,8 @@ 10. [Troubleshooting](#troubleshooting) ## Prerequisites -- Java 22 or higher (Java 22, 23, 24, 25+ are all supported) -- Maven or Gradle (Gradle wrapper included - recommended) +- JDK 22 or later +- Maven, or the included Gradle wrapper (recommended) - Optional: JDBC drivers for database connectivity ## Build Options @@ -36,7 +36,6 @@ The project includes a Makefile that wraps Gradle commands for a familiar build ```bash make # same as 'make build' make build # builds the project and runs unit tests -make dev # force clean rebuild (use during active development) make test # runs fast unit tests make clean # cleans build artifacts make deb # creates a Debian package (Linux only) @@ -64,8 +63,8 @@ make deb ``` This creates a Debian package in `build/distributions/` with: -- PerlOnJava JAR installed to `/usr/share/perlonjava/` -- `jperl` command installed to `/usr/bin/` +- PerlOnJava installed under `/opt/perlonjava/` +- `jperl`, `jcpan`, `jperldoc`, and `jprove` linked into `/usr/local/bin/` - All dependencies bundled - Systemwide availability @@ -128,7 +127,7 @@ jperl myscript.pl 1. Using Configure.pl: ```bash -./jperl Configure.pl --search mysql-connector-java +./Configure.pl --search mysql-connector-java ``` 2. Using Java classpath (shown in platform-specific examples above) @@ -149,7 +148,7 @@ See [Database Access Guide](../guides/database-access.md) for detailed connectio ## Build Notes - Maven builds use `maven-shade-plugin` for creating the shaded JAR -- Gradle builds use `com.github.johnrengelman.shadow` plugin +- Gradle builds use the Shadow plugin - Both configurations target Java 22 ## Java Library Upgrades @@ -166,37 +165,37 @@ See [Database Access Guide](../guides/database-access.md) for detailed connectio The `Configure.pl` script manages configuration settings and dependencies for PerlOnJava. -> **Tip:** Using `./jperl` to run Configure.pl is recommended because it includes -> built-in HTTPS support. System Perl may require additional modules -> (`IO::Socket::SSL`, `Net::SSLeay`) for the Maven Central search to work. +Run `Configure.pl` directly from the repository root. It uses the system Perl +specified by its shebang and requires the Perl modules imported at the top of the +script. ### Common Tasks **View current configuration:** ```bash -./jperl Configure.pl +./Configure.pl ``` **Add JDBC driver (search):** ```bash -./jperl Configure.pl --search mysql +./Configure.pl --search mysql make # Rebuild to include driver ``` **Add JDBC driver (direct):** ```bash -./jperl Configure.pl --direct com.mysql:mysql-connector-j:8.2.0 +./Configure.pl --direct com.mysql:mysql-connector-j:8.2.0 make # Rebuild to include driver ``` **Update configuration:** ```bash -./jperl Configure.pl -D perlVersion=v5.42.0 +./Configure.pl -D version=5.44.0 ``` **Upgrade all dependencies:** ```bash -./jperl Configure.pl --upgrade +./Configure.pl --upgrade ``` ### Available Options @@ -220,7 +219,7 @@ make # Rebuild to include driver ## Troubleshooting -### "Unsupported class file major version 69" (Java 25+) +### "Unsupported class file major version" errors **Problem:** When building with Java 25 or later, you see: ``` @@ -228,37 +227,28 @@ BUG! exception in phase 'semantic analysis' in source unit '_BuildScript_' Unsup > Unsupported class file major version 69 ``` -**Cause:** An old cached Gradle version (8.x) doesn't support Java 25. Java 25 uses class file version 69, which requires Gradle 9.0+. +**Cause:** The build is using an older Gradle installation that cannot run on +your JDK. -**Solution:** Clear the old Gradle cache and rebuild: +**Solution:** Use the repository's Gradle wrapper instead of a system-installed +Gradle. Confirm the configured version, then rebuild: ```bash -# Linux/macOS -rm -rf ~/.gradle/wrapper/dists/gradle-8.* +./gradlew --version +make wrapper make clean make - -# Windows (PowerShell) -Remove-Item -Recurse -Force "$env:USERPROFILE\.gradle\wrapper\dists\gradle-8.*" -gradlew.bat clean -make ``` -The project includes a Gradle wrapper configured for Gradle 9.0+, which supports Java 22 through Java 26. +On Windows, use `gradlew.bat --version`. The wrapper version is defined in +`gradle/wrapper/gradle-wrapper.properties`; that file is the source of truth. ### Java Version Compatibility -Based on [Gradle's official compatibility matrix](https://docs.gradle.org/current/userguide/compatibility.html): - -| Java Version | Class File Version | Gradle Required | -|--------------|-------------------|-----------------| -| Java 22 | 66 | 8.8+ | -| Java 23 | 67 | 8.10+ | -| Java 24 | 68 | 8.14+ | -| Java 25 | 69 | 9.1.0+ | -| Java 26 | 70 | 9.4.0+ | - -The Makefile automatically detects Java 25+ and upgrades the Gradle wrapper to 9.1.0 if needed. It also clears any incompatible cached Gradle distributions (8.x and 9.0.x). +PerlOnJava compiles for Java 22 and requires JDK 22 or later. Use the included +wrapper so the Gradle version stays aligned with the project. For compatibility +details beyond the checked-in wrapper, consult Gradle's +[Java compatibility matrix](https://docs.gradle.org/current/userguide/compatibility.html). ### "JAVA_HOME is not set" @@ -274,8 +264,6 @@ set JAVA_HOME=C:\path\to\jdk ### Build Takes Too Long -Use `make dev` instead of `make` for faster builds during development - it skips tests: - -```bash -make dev # Compiles only, no tests -``` +The default `make` target builds the runnable JAR and runs the fast unit suite. +For a targeted test during development, run the relevant `.t` file with +`./jperl`, then run `make` before committing. diff --git a/docs/guides/database-access.md b/docs/guides/database-access.md index b435e4f4c..60a80dc2b 100644 --- a/docs/guides/database-access.md +++ b/docs/guides/database-access.md @@ -24,15 +24,15 @@ SQLite works out of the box. For other databases, JDBC drivers can be added in t Examples: ```bash -./jperl Configure.pl --search mysql-connector-java -./jperl Configure.pl --search aws-mysql-jdbc +./Configure.pl --search mysql-connector-java +./Configure.pl --search aws-mysql-jdbc ``` Then build with the drivers included: ```bash mvn clean package # or -gradle clean build +./gradlew clean build ``` 2. Using Java classpath: @@ -52,7 +52,7 @@ gradle clean build Calling java directly with the classpath is also possible: ```bash - java --enable-native-access=ALL-UNNAMED -cp "jdbc-drivers/mysql-connector-j-8.2.0.jar:target/perlonjava-5.42.0.jar" org.perlonjava.app.cli.Main myscript.pl + java --enable-native-access=ALL-UNNAMED -cp "jdbc-drivers/mysql-connector-j-8.2.0.jar:target/perlonjava-5.44.0.jar" org.perlonjava.app.cli.Main myscript.pl ``` ## Database Connection Examples diff --git a/docs/guides/java-integration.md b/docs/guides/java-integration.md index d7d9df4e7..79d6a035e 100644 --- a/docs/guides/java-integration.md +++ b/docs/guides/java-integration.md @@ -143,23 +143,34 @@ public class DirectExample { ## Building with PerlOnJava +PerlOnJava is not yet published to Maven Central. You can use the runnable JAR +directly, or install the artifact into your local Maven repository: + +```bash +mvn clean install +``` + ### Maven -Add PerlOnJava as a dependency: +After installing it locally, add PerlOnJava as a dependency: ```xml org.perlonjava perlonjava - 5.42.2 + 5.44.0 ``` ### Gradle ```gradle +repositories { + mavenLocal() +} + dependencies { - implementation 'org.perlonjava:perlonjava:5.42.2' + implementation 'org.perlonjava:perlonjava:5.44.0' } ``` @@ -170,12 +181,12 @@ dependencies { make ``` -2. Find JAR in `build/libs/perlonjava-*-all.jar` +2. Find the runnable JAR in `target/perlonjava-*.jar` 3. Add to your classpath: ```bash - javac -cp perlonjava-5.42.0-all.jar YourApp.java - java --enable-native-access=ALL-UNNAMED -cp .:perlonjava-5.42.0-all.jar YourApp + javac -cp target/perlonjava-5.44.0.jar YourApp.java + java --enable-native-access=ALL-UNNAMED -cp .:target/perlonjava-5.44.0.jar YourApp ``` ## Use Cases diff --git a/docs/guides/module-porting.md b/docs/guides/module-porting.md index 15ffe6d2d..73705752b 100644 --- a/docs/guides/module-porting.md +++ b/docs/guides/module-porting.md @@ -164,8 +164,7 @@ This is transparent to users — they just `use Module::Name` and it works. ### Build and Test ```bash -make dev # Quick build (no tests) — for iteration -make # Full build + all unit tests — before committing +make # Build and run the fast unit suite ./jperl -e 'use Module::Name; ...' # Quick smoke test ``` @@ -212,7 +211,6 @@ To add tests for a new bundled module: - [ ] Preserve original author/copyright attribution - [ ] Register all methods in `initialize()` - [ ] Create `src/test/resources/module/Module-Name/t/` with test files -- [ ] `make dev` compiles without errors - [ ] Compare output with system Perl - [ ] `make` passes all unit tests - [ ] `make test-bundled-modules` passes module-specific tests @@ -515,7 +513,6 @@ Files: Create test files in `src/test/resources/` for bundled modules: ```bash -make dev # Quick build ./jperl src/test/resources/module_name.t make # Full build + all tests ``` diff --git a/docs/reference/architecture.md b/docs/reference/architecture.md index a761dee10..55c547212 100644 --- a/docs/reference/architecture.md +++ b/docs/reference/architecture.md @@ -13,7 +13,7 @@ Both backends share 100% of the same runtime APIs and can call each other seamle - Compile-time transformation from Perl to JVM bytecode - Direct bytecode interpretation with register-based VM - Direct access to Java libraries via JDBC, JSR-223, and standard JVM tools -- Implements most Perl 5.40+ features including references, closures, and regular expressions +- Targets Perl 5.44 language compatibility, including references, closures, and regular expressions - Includes 150+ core Perl modules - Bidirectional calling between compiled and interpreted code diff --git a/docs/reference/bundled-modules.md b/docs/reference/bundled-modules.md index bb2a15d23..a6785a79c 100644 --- a/docs/reference/bundled-modules.md +++ b/docs/reference/bundled-modules.md @@ -29,9 +29,9 @@ guide: **[Database Access Guide](../guides/database-access.md)**. | Database | Driver setup | |------------|-------------| | SQLite | Built-in — nothing to install | -| MySQL | `./jperl Configure.pl --search mysql-connector-java` | -| PostgreSQL | `./jperl Configure.pl --search postgresql` | -| Oracle | `./jperl Configure.pl --search ojdbc` | +| MySQL | `./Configure.pl --search mysql-connector-java` | +| PostgreSQL | `./Configure.pl --search postgresql` | +| Oracle | `./Configure.pl --search ojdbc` | ### Image::Magick — Image Processing diff --git a/docs/reference/configure.md b/docs/reference/configure.md index cd4a40eae..7878d92fe 100644 --- a/docs/reference/configure.md +++ b/docs/reference/configure.md @@ -5,17 +5,15 @@ The `Configure.pl` script manages configuration settings and dependencies for Pe ## Synopsis ```bash -./jperl Configure.pl [options] -./jperl Configure.pl -D key=value -./jperl Configure.pl --search keyword -./jperl Configure.pl --direct group:artifact:version -./jperl Configure.pl --upgrade +./Configure.pl [options] +./Configure.pl -D key=value +./Configure.pl --search keyword +./Configure.pl --direct group:artifact:version +./Configure.pl --upgrade ``` -> **Tip:** `Configure.pl` can be run with either `./jperl` or `perl`. Using `./jperl` is -> recommended because it includes built-in HTTPS support, while system Perl may -> require additional modules (`IO::Socket::SSL`, `Net::SSLeay`) for the Maven -> Central search to work. +Run the script directly from the repository root. Its shebang selects the system +Perl, and its required Perl modules are listed at the top of the script. ## Options @@ -25,30 +23,26 @@ The `Configure.pl` script manages configuration settings and dependencies for Pe - Show help message and usage instructions ```bash -./jperl Configure.pl --help +./Configure.pl --help ``` ### Configuration Management **`-D key=value`** -- Set configuration values in `Configuration.java` -- Can specify multiple key-value pairs +- Set the project version in `Configuration.java.in` - String values are automatically quoted -- Boolean/numeric values are used as-is ```bash -./jperl Configure.pl -D perlVersion=v5.40.0 -./jperl Configure.pl -D jarVersion=3.0.1 -./jperl Configure.pl -D strict_mode=true -D enable_optimizations=false +./Configure.pl -D version=5.44.0 ``` -**Special behavior for `jarVersion`:** +**Special behavior for `version`:** - Automatically updates all references to the JAR filename throughout the repository - Updates from `perlonjava-OLD.jar` to `perlonjava-NEW.jar` in all text files **View current configuration:** ```bash -./jperl Configure.pl +./Configure.pl ``` ### Dependency Management @@ -60,15 +54,15 @@ The `Configure.pl` script manages configuration settings and dependencies for Pe ```bash # Search by keyword -./jperl Configure.pl --search mysql -./jperl Configure.pl --search postgresql +./Configure.pl --search mysql +./Configure.pl --search postgresql # Search by driver class name -./jperl Configure.pl --search com.mysql.cj.jdbc.Driver -./jperl Configure.pl --search org.postgresql.Driver +./Configure.pl --search com.mysql.cj.jdbc.Driver +./Configure.pl --search org.postgresql.Driver # Search by group:artifact -./jperl Configure.pl --search org.postgresql:postgresql +./Configure.pl --search org.postgresql:postgresql ``` **Search behavior:** @@ -84,8 +78,8 @@ The `Configure.pl` script manages configuration settings and dependencies for Pe - Format must be: `group:artifact:version` ```bash -./jperl Configure.pl --direct com.mysql:mysql-connector-j:8.2.0 -./jperl Configure.pl --direct org.postgresql:postgresql:42.7.1 +./Configure.pl --direct com.mysql:mysql-connector-j:8.2.0 +./Configure.pl --direct org.postgresql:postgresql:42.7.1 ``` **`--verbose`** @@ -95,7 +89,7 @@ The `Configure.pl` script manages configuration settings and dependencies for Pe - Useful for troubleshooting search issues ```bash -./jperl Configure.pl --search mysql --verbose +./Configure.pl --search mysql --verbose ``` ### Dependency Upgrades @@ -107,7 +101,7 @@ The `Configure.pl` script manages configuration settings and dependencies for Pe - Uses `./gradlew versionCatalogUpdate` for Gradle ```bash -./jperl Configure.pl --upgrade +./Configure.pl --upgrade ``` **Requirements:** @@ -122,12 +116,12 @@ The `Configure.pl` script manages configuration settings and dependencies for Pe 1. Search for the driver: ```bash -./jperl Configure.pl --search mysql-connector-java +./Configure.pl --search mysql-connector-java ``` 2. Or use direct coordinates if you know them: ```bash -./jperl Configure.pl --direct com.mysql:mysql-connector-j:8.2.0 +./Configure.pl --direct com.mysql:mysql-connector-j:8.2.0 ``` 3. Rebuild the project to include the driver: @@ -180,12 +174,12 @@ This ensures JDBC drivers appear first in search results. When you set configuration with `-D`: -1. Reads `src/main/java/org/perlonjava/Configuration.java` +1. Reads `src/main/java/org/perlonjava/core/Configuration.java.in` 2. Finds `public static final Type key = value;` declarations 3. Replaces value with new value 4. Writes updated file back -For `jarVersion` updates, also: +For `version` updates, also: - Scans all text files in the repository - Replaces old JAR filename with new one - Skips binary files and hidden directories @@ -195,29 +189,27 @@ For `jarVersion` updates, also: ### View Current Configuration ```bash -./jperl Configure.pl +./Configure.pl ``` Output: ``` Current configuration: -perlVersion = "v5.40.0" -jarVersion = "3.0.1" -strict_mode = true +version = "5.44.0" ``` ### Update Configuration ```bash -./jperl Configure.pl -D perlVersion=v5.42.0 -D jarVersion=3.1.0 +./Configure.pl -D version=5.44.0 ``` ### Search and Add JDBC Driver ```bash # Search for PostgreSQL driver -./jperl Configure.pl --search postgresql +./Configure.pl --search postgresql # Output shows: # Multiple matches found: @@ -238,7 +230,7 @@ make ```bash # Add MySQL database driver -./jperl Configure.pl --direct com.mysql:mysql-connector-j:8.2.0 +./Configure.pl --direct com.mysql:mysql-connector-j:8.2.0 # Rebuild make @@ -247,7 +239,7 @@ make ### Upgrade All Dependencies ```bash -./jperl Configure.pl --upgrade +./Configure.pl --upgrade ``` Output: @@ -265,11 +257,11 @@ Gradle dependencies updated successfully. ```bash # Option 1: Search and select -./jperl Configure.pl --search mysql +./Configure.pl --search mysql make # Option 2: Direct coordinates -./jperl Configure.pl --direct com.mysql:mysql-connector-j:8.2.0 +./Configure.pl --direct com.mysql:mysql-connector-j:8.2.0 make # Option 3: Manual CLASSPATH (no rebuild needed) @@ -279,29 +271,29 @@ CLASSPATH=/path/to/mysql-connector.jar ./jperl script.pl ### Updating Project Version ```bash -./jperl Configure.pl -D jarVersion=4.0.0 -# This updates Configuration.java and all references to perlonjava-*.jar +./Configure.pl -D version=5.44.0 +# This updates Configuration.java.in and all references to perlonjava-*.jar ``` ### Finding Available Drivers ```bash # Search by database name -./jperl Configure.pl --search postgresql --verbose +./Configure.pl --search postgresql --verbose # Search by driver class -./jperl Configure.pl --search org.postgresql.Driver --verbose +./Configure.pl --search org.postgresql.Driver --verbose ``` ## Troubleshooting ### Search Returns No Results -**Problem**: `./jperl Configure.pl --search keyword` finds nothing +**Problem**: `./Configure.pl --search keyword` finds nothing **Solutions**: - Try broader keywords: `mysql` instead of `mysql-connector-java-8.2.0` -- Search by driver class: `./jperl Configure.pl --search com.mysql.cj.jdbc.Driver` +- Search by driver class: `./Configure.pl --search com.mysql.cj.jdbc.Driver` - Use `--verbose` to see search URL and results - Use `--direct` if you know the exact coordinates @@ -311,7 +303,7 @@ CLASSPATH=/path/to/mysql-connector.jar ./jperl script.pl **Solution**: You must rebuild after adding dependencies: ```bash -./jperl Configure.pl --direct group:artifact:version +./Configure.pl --direct group:artifact:version make # This downloads and bundles the dependency ``` diff --git a/docs/reference/feature-matrix.md b/docs/reference/feature-matrix.md index 617ce9c95..1b2f066d6 100644 --- a/docs/reference/feature-matrix.md +++ b/docs/reference/feature-matrix.md @@ -374,7 +374,7 @@ my @copy = @{$z}; # ERROR - ✅ **Relative Backreferences**: Using `\g{-n}` for relative backreferences. - ✅ **Unicode Properties**: Matching with `\p{...}` and `\P{...}` (e.g., `\p{L}` for letters). - ✅ **Unicode Properties**: Add regex properties supported by Perl but missing in Java regex. -- ✅ **Possessive Quantifiers**: Quantifiers like `*+`, `++`, `?+`, or `{n,m}+`, which disable backtracking, are not supported. +- ✅ **Possessive Quantifiers**: Quantifiers like `*+`, `++`, `?+`, and `{n,m}+`, which disable backtracking, are supported. - ✅ **Atomic Grouping**: Use of `(?>...)` for atomic groups is supported. - ✅ **`\K` assertion**: Keep left — in `s///`, text before `\K` is preserved; match variables reflect only the portion after `\K`. - ✅ **Preprocessor**: `\Q`, `\L`, `\U`, `\l`, `\u`, `\E` are preprocessed in regex. @@ -384,7 +384,7 @@ my @copy = @{$z}; # ERROR - ❌ **Dynamically-scoped regex variables**: Regex variables are not dynamically-scoped. - ❌ **Recursive Patterns**: Features like `(?R)`, `(?0)` or `(??{ code })` for recursive matching are not supported. -- ❌ **Backtracking Control**: Features like `(?>...)`, `(?(DEFINE)...)`, or `(?>.*)` to prevent or control backtracking are not supported. +- ❌ **Backtracking Control Verbs and Definitions**: Features such as `(*PRUNE)`, `(*SKIP)`, and `(?(DEFINE)...)` are not supported. Atomic groups `(?>...)` are supported as noted above. - ❌ **Lookbehind Assertions**: Variable-length negative or positive lookbehind assertions, e.g., `(?<=...)` or `(?/dev/null || echo "$SCRIPT_DIR/j # Export environment variable for PerlOnJava to use as $^X export PERLONJAVA_EXECUTABLE="$JPERL_PATH" -# Check development environment first (target directory) -if [ -f "$SCRIPT_DIR/target/perlonjava-5.42.0.jar" ]; then - JAR_PATH="$SCRIPT_DIR/target/perlonjava-5.42.0.jar" -elif [ -f "$SCRIPT_DIR/perlonjava-5.42.0.jar" ]; then +# Check development environment first (target directory). During Maven's test +# phase the packaged JAR does not exist yet, so use compiled classes plus the +# runtime dependency classpath generated by maven-dependency-plugin. +if [ -f "$SCRIPT_DIR/target/perlonjava-5.44.0.jar" ]; then + PERLONJAVA_CP="$SCRIPT_DIR/target/perlonjava-5.44.0.jar" +elif [ -d "$SCRIPT_DIR/target/classes" ] && [ -f "$SCRIPT_DIR/target/jperl-test-classpath.txt" ]; then + MAVEN_RUNTIME_CP=$(tr -d '\r\n' < "$SCRIPT_DIR/target/jperl-test-classpath.txt") + PERLONJAVA_CP="$SCRIPT_DIR/target/classes" + if [ -n "$MAVEN_RUNTIME_CP" ]; then + PERLONJAVA_CP="$PERLONJAVA_CP:$MAVEN_RUNTIME_CP" + fi +elif [ -f "$SCRIPT_DIR/perlonjava-5.44.0.jar" ]; then # Docker or local installation with jar in same directory - JAR_PATH="$SCRIPT_DIR/perlonjava-5.42.0.jar" + PERLONJAVA_CP="$SCRIPT_DIR/perlonjava-5.44.0.jar" else # Use installed package path (when installed via deb package) - JAR_PATH="$SCRIPT_DIR/../lib/perlonjava-5.42.0.jar" + PERLONJAVA_CP="$SCRIPT_DIR/../lib/perlonjava-5.44.0.jar" fi # Determine JVM options based on Java version @@ -50,9 +58,8 @@ fi # Note: Only include CLASSPATH if set, to avoid empty prefix that would add current dir to path if [ -n "$CLASSPATH" ]; then - CP="$CLASSPATH:$JAR_PATH" + CP="$CLASSPATH:$PERLONJAVA_CP" else - CP="$JAR_PATH" + CP="$PERLONJAVA_CP" fi exec java $JVM_OPTS ${JPERL_OPTS} -cp "$CP" org.perlonjava.app.cli.Main "$@" - diff --git a/jperl.bat b/jperl.bat index 42c5c1cbb..3b9cb2b34 100755 --- a/jperl.bat +++ b/jperl.bat @@ -34,5 +34,19 @@ for /f "tokens=3" %%v in ('java -version 2^>^&1 ^| findstr /i "version"') do ( ) ) +rem During Maven tests the packaged JAR does not exist yet. Use compiled +rem classes plus the runtime classpath generated by maven-dependency-plugin. +set "PERLONJAVA_CP=%SCRIPT_DIR%..\lib\perlonjava-5.44.0.jar" +if exist "%SCRIPT_DIR%target\perlonjava-5.44.0.jar" ( + set "PERLONJAVA_CP=%SCRIPT_DIR%target\perlonjava-5.44.0.jar" +) else ( + if exist "%SCRIPT_DIR%target\classes" ( + if exist "%SCRIPT_DIR%target\jperl-test-classpath.txt" ( + set /p MAVEN_RUNTIME_CP=<"%SCRIPT_DIR%target\jperl-test-classpath.txt" + set "PERLONJAVA_CP=%SCRIPT_DIR%target\classes;%MAVEN_RUNTIME_CP%" + ) + ) +) + rem Launch Java -java %JVM_OPTS% %JPERL_OPTS% -cp "%CLASSPATH%;%SCRIPT_DIR%target\perlonjava-5.42.0.jar" org.perlonjava.app.cli.Main %* +java %JVM_OPTS% %JPERL_OPTS% -cp "%CLASSPATH%;%PERLONJAVA_CP%" org.perlonjava.app.cli.Main %* diff --git a/pom.xml b/pom.xml index 78c2dbd0e..a8aa3c4da 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.perlonjava perlonjava - 5.42.0 + 5.44.0 jar perlonjava @@ -14,6 +14,7 @@ 22 22 + ${project.basedir}/jperl @@ -114,6 +115,27 @@ + + + org.apache.maven.plugins + maven-dependency-plugin + 3.8.1 + + + write-jperl-test-classpath + generate-test-resources + + build-classpath + + + runtime + ${project.build.directory}/jperl-test-classpath.txt + + + + org.apache.maven.plugins maven-enforcer-plugin @@ -204,8 +226,14 @@ --enable-native-access=ALL-UNNAMED unit full - - 0 + + 1 + true + + ${jperl.launcher} + ${project.basedir}${path.separator}${env.PATH} + @@ -370,6 +398,9 @@ fi windows + + ${project.basedir}/jperl.bat + @@ -400,4 +431,3 @@ fi - diff --git a/src/main/java/org/perlonjava/app/cli/ArgumentParser.java b/src/main/java/org/perlonjava/app/cli/ArgumentParser.java index baec4abbf..93240d5a0 100644 --- a/src/main/java/org/perlonjava/app/cli/ArgumentParser.java +++ b/src/main/java/org/perlonjava/app/cli/ArgumentParser.java @@ -9,6 +9,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; @@ -816,7 +817,7 @@ private static void printVersionInfo() { System.out.println("This is perl " + major + ", version " + minor + ", subversion " + subversion + " (v" + versionNoV + ") built for JVM" + gitInfo); System.out.println(); - System.out.println("Copyright 1987-2025, Larry Wall"); + System.out.println("Copyright 1987-2026, Larry Wall"); System.out.println(); System.out.println("Perl may be copied only under the terms of either the Artistic License or the"); System.out.println("GNU General Public License, which may be found in the Perl 5 source kit."); @@ -1405,6 +1406,13 @@ private static void printHelp() { * @param parsedArgs The CompilerOptions object to configure. */ private static void processRudimentarySwitch(String arg, CompilerOptions parsedArgs) { + // PerlOnJava carries raw process-argument bytes in the corresponding + // Latin-1 code points. -CA asks Perl to decode those bytes as UTF-8; + // without it, the byte-oriented representation must remain unchanged. + if (parsedArgs.unicodeArgs) { + arg = new String(arg.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8); + } + String varName; String varValue = "1"; // Default value @@ -1434,12 +1442,34 @@ private static void processRudimentarySwitch(String arg, CompilerOptions parsedA if (parsedArgs.rudimentarySwitchAssignments == null) { parsedArgs.rudimentarySwitchAssignments = new StringBuilder(); } - parsedArgs.rudimentarySwitchAssignments - .append("$main::") - .append(varName) - .append(" = '") - .append(varValue.replace("'", "\\'")) - .append("';\n"); + if (varName.codePoints().anyMatch(codePoint -> codePoint > 0x7f)) { + parsedArgs.rudimentarySwitchAssignments + .append("${") + .append(toPerlHexString("main::" + varName)) + .append("}"); + } else { + parsedArgs.rudimentarySwitchAssignments.append("$main::").append(varName); + } + + parsedArgs.rudimentarySwitchAssignments.append(" = "); + if (varValue.codePoints().anyMatch(codePoint -> codePoint > 0x7f)) { + parsedArgs.rudimentarySwitchAssignments.append(toPerlHexString(varValue)); + } else { + parsedArgs.rudimentarySwitchAssignments + .append("'") + .append(varValue.replace("'", "\\'")) + .append("'"); + } + parsedArgs.rudimentarySwitchAssignments.append(";\n"); + } + + private static String toPerlHexString(String value) { + StringBuilder expression = new StringBuilder("qq("); + value.codePoints().forEach(codePoint -> expression + .append("\\x{") + .append(Integer.toHexString(codePoint)) + .append("}")); + return expression.append(")").toString(); } private static void processRudimentarySwitchArguments(String[] args, CompilerOptions parsedArgs, int startIndex) { diff --git a/src/main/java/org/perlonjava/core/Configuration.java.in b/src/main/java/org/perlonjava/core/Configuration.java.in index a05b2f6d8..2621763ee 100644 --- a/src/main/java/org/perlonjava/core/Configuration.java.in +++ b/src/main/java/org/perlonjava/core/Configuration.java.in @@ -9,7 +9,7 @@ import org.perlonjava.runtime.runtimetypes.RuntimeScalarType; *

* Configuration values are managed using the Configure.pl script: *

- * ./Configure.pl -D version=5.43.0 # Update version everywhere + * ./Configure.pl -D version=5.44.0 # Update version everywhere * ./Configure.pl # Show current configuration *

* This will update the version constant in this class and replace all @@ -33,7 +33,7 @@ public final class Configuration { * This version is used for both the JAR artifact and Perl compatibility version. * Updated via: ./Configure.pl -D version=X.Y.Z */ - public static final String version = "5.42.0"; + public static final String version = "5.44.0"; /** * Git commit ID (short hash) of the build. @@ -63,7 +63,7 @@ public final class Configuration { /** * Returns the version for use with "use VERSION" feature bundles. - * For version 5.42.0, returns ":5.42" + * For version 5.44.0, returns ":5.44" */ public static String getPerlVersionBundle() { int lastDot = version.lastIndexOf('.'); @@ -79,7 +79,7 @@ public final class Configuration { } /** - * Returns the version in old Perl $] format (e.g., "5.042000" for 5.42.0). + * Returns the version in old Perl $] format (e.g., "5.044000" for 5.44.0). */ public static String getPerlVersionOld() { String versionNoV = getPerlVersionNoV(); @@ -99,7 +99,7 @@ public final class Configuration { /** * Returns the Perl version as a vstring RuntimeScalar. - * For example, 5.42.0 becomes a vstring with bytes \u0005*\u0000 + * For example, 5.44.0 becomes a vstring with bytes \u0005,\u0000 * where each version component is represented as a character. * * @return RuntimeScalar with type VSTRING containing the version diff --git a/src/main/perl/lib/Config.pm b/src/main/perl/lib/Config.pm index b7c8898a8..c17d4e2d0 100644 --- a/src/main/perl/lib/Config.pm +++ b/src/main/perl/lib/Config.pm @@ -16,7 +16,7 @@ use Java::System qw(getProperty getenv); our ( %Config, $VERSION ); -$VERSION = "5.042000"; +$VERSION = "5.044000"; # Skip @Config::EXPORT because it only contains %Config, which we special # case below as it's not a function. @Config::EXPORT won't change in the @@ -49,11 +49,11 @@ sub import { return; } -die "$0: Perl lib version (5.42.0) doesn't match executable '$^X' version ($])" +die "$0: Perl lib version (5.44.0) doesn't match executable '$^X' version ($])" unless $^V; -$^V eq 5.42.0 - or die sprintf "%s: Perl lib version (5.42.0) doesn't match executable '$^X' version (%vd)", $0, $^V; +$^V eq 5.44.0 + or die sprintf "%s: Perl lib version (5.44.0) doesn't match executable '$^X' version (%vd)", $0, $^V; # Get Java system properties using Java::System module @@ -71,7 +71,7 @@ my $user_name = getProperty('user.name') || 'unknown'; my $perlonjava_home = $user_home ? _catdir($file_separator, $user_home, '.perlonjava') : '.perlonjava'; -my $core_privlib = _catdir($file_separator, $perlonjava_home, 'core', 'lib', 'perl5', '5.42.0'); +my $core_privlib = _catdir($file_separator, $perlonjava_home, 'core', 'lib', 'perl5', '5.44.0'); my $core_archlib = _catdir($file_separator, $core_privlib, "java-$java_version-$os_arch"); _ensure_dir(_catdir($file_separator, $core_archlib, 'CORE')); _ensure_core_probe_file( @@ -164,7 +164,7 @@ my $startperl = $is_windows osvers => $os_version, # PerlOnJava specific - perlonjava => '5.42.0', + perlonjava => '5.44.0', java_version => $java_version, java_vendor => $java_vendor, java_home => $java_home, @@ -208,10 +208,10 @@ my $startperl = $is_windows # CPAN build helpers such as ExtUtils::CBuilder probe $archlibexp/CORE. archlibexp => $core_archlib, privlibexp => $core_privlib, - sitearchexp => 'perlonjava/lib/perl5/site_perl/5.42.0/' . "java-$java_version-$os_arch", - sitelibexp => 'perlonjava/lib/perl5/site_perl/5.42.0', - vendorarchexp => 'perlonjava/lib/perl5/vendor_perl/5.42.0/' . "java-$java_version-$os_arch", - vendorlibexp => 'perlonjava/lib/perl5/vendor_perl/5.42.0', + sitearchexp => 'perlonjava/lib/perl5/site_perl/5.44.0/' . "java-$java_version-$os_arch", + sitelibexp => 'perlonjava/lib/perl5/site_perl/5.44.0', + vendorarchexp => 'perlonjava/lib/perl5/vendor_perl/5.44.0/' . "java-$java_version-$os_arch", + vendorlibexp => 'perlonjava/lib/perl5/vendor_perl/5.44.0', # Script directory (JAR-embedded scripts at /bin/) scriptdir => 'jar:PERL5BIN', @@ -326,11 +326,11 @@ my $startperl = $is_windows eunicefix => ':', # No-op fixer (only used on EUNICE) # Version info - version => '5.42.0', - version_patchlevel_string => 'version 42 patchlevel 0', - api_version => '42', + version => '5.44.0', + version_patchlevel_string => 'version 44 patchlevel 0', + api_version => '44', api_subversion => '0', - api_versionstring => '5.42.0', + api_versionstring => '5.44.0', # Build configuration dont_use_nlink => undef, @@ -446,7 +446,7 @@ sub _ensure_core_probe_file { # Return a string describing the perl configuration (like perl -V) sub myconfig { - my $config = "Summary of my perl5 (revision 5 version 42 subversion 0) configuration:\n"; + my $config = "Summary of my perl5 (revision 5 version 44 subversion 0) configuration:\n"; $config .= " \n"; # Blank line with leading spaces (matches Perl format) $config .= " Platform:\n"; $config .= " osname=$Config{osname}\n"; diff --git a/src/main/perl/lib/DBI.pm b/src/main/perl/lib/DBI.pm index 5d581f201..8809ab9a8 100644 --- a/src/main/perl/lib/DBI.pm +++ b/src/main/perl/lib/DBI.pm @@ -731,7 +731,7 @@ use constant { # Example: # -# java -cp "h2-2.2.224.jar:target/perlonjava-5.42.0.jar" org.perlonjava.app.cli.Main dbi.pl +# java -cp "h2-2.2.224.jar:target/perlonjava-5.44.0.jar" org.perlonjava.app.cli.Main dbi.pl # # # Connect to H2 database # my $dbh = DBI->connect( diff --git a/src/test/java/org/perlonjava/ArgumentParserTest.java b/src/test/java/org/perlonjava/ArgumentParserTest.java index 1090eab57..1e53388e7 100644 --- a/src/test/java/org/perlonjava/ArgumentParserTest.java +++ b/src/test/java/org/perlonjava/ArgumentParserTest.java @@ -30,4 +30,29 @@ void rudimentarySwitchParsingContinuesAfterDoubleDashForEvalCode() { assertEquals(0, options.argumentList.elements.size()); assertEquals("$main::_ = 'Just another Perl Hacker';\nprint", options.code); } + + @Test + void rudimentarySwitchParsingPreservesUtf8BytesWithoutUnicodeArgs() { + CompilerOptions options = ArgumentParser.parseArguments(new String[] { + "-C0", "-se1", "--", "-\u00c5\u00b8", "-\u00c3\u00a1=\u00e2\u0082\u00ac" + }); + + assertEquals( + "${qq(\\x{6d}\\x{61}\\x{69}\\x{6e}\\x{3a}\\x{3a}\\x{c5}\\x{b8})} = '1';\n" + + "${qq(\\x{6d}\\x{61}\\x{69}\\x{6e}\\x{3a}\\x{3a}\\x{c3}\\x{a1})} = " + + "qq(\\x{e2}\\x{82}\\x{ac});\n1", + options.code); + } + + @Test + void rudimentarySwitchParsingDecodesUtf8WithUnicodeArgs() { + CompilerOptions options = ArgumentParser.parseArguments(new String[] { + "-CA", "-se1", "--", "-\u00c5\u00b8", "-\u00c3\u00a1=\u00e2\u0082\u00ac" + }); + + assertEquals( + "${qq(\\x{6d}\\x{61}\\x{69}\\x{6e}\\x{3a}\\x{3a}\\x{178})} = '1';\n" + + "${qq(\\x{6d}\\x{61}\\x{69}\\x{6e}\\x{3a}\\x{3a}\\x{e1})} = qq(\\x{20ac});\n1", + options.code); + } } diff --git a/src/test/resources/unit/cli_warning_overrides.t b/src/test/resources/unit/cli_warning_overrides.t index cedf907da..0f43ec643 100644 --- a/src/test/resources/unit/cli_warning_overrides.t +++ b/src/test/resources/unit/cli_warning_overrides.t @@ -4,7 +4,7 @@ use Test::More; use File::Temp qw(tempdir); use IPC::Open3; -my $skip_launcher = $^X eq 'jperl' && !-f 'target/perlonjava-5.42.0.jar'; +my $skip_launcher = $^X eq 'jperl' && !-f 'target/perlonjava-5.44.0.jar'; my $tmpdir = tempdir(CLEANUP => 1); my $seq = 0; diff --git a/src/test/resources/unit/interpreter_dbic_regressions.t b/src/test/resources/unit/interpreter_dbic_regressions.t index c2656f81a..6a813addd 100644 --- a/src/test/resources/unit/interpreter_dbic_regressions.t +++ b/src/test/resources/unit/interpreter_dbic_regressions.t @@ -4,7 +4,7 @@ use Test::More; use File::Temp qw(tempfile); my $skip_launcher = $^O eq 'MSWin32' - || ($^X eq 'jperl' && !-f 'target/perlonjava-5.42.0.jar'); + || ($^X eq 'jperl' && !-f 'target/perlonjava-5.44.0.jar'); sub run_interpreter_child { my ($code) = @_;