pperl 0.6.24#

2026-10-15 to 2026-10-25, 457 commits.

JIT and parallelization#

  • Loops over arrays sized with $#a stay compiled: a loop that stores into an array whose size was set with $#a = $n, directly or through a reference, now runs as compiled code. It used to fall back to the interpreter on every element until the JIT gave the loop up, and ran about three times slower than the same loop over an array filled with values first.

  • & | ^ under use v5.28 and later are compiled: with the bitwise feature, which use v5.28 and later versions turn on, the numeric &, | and ^ are separate operations, and a loop holding one of them ran in the interpreter. Such loops are now compiled, signed under use integer and unsigned otherwise, as perl computes them.

  • Index arithmetic no longer decides how a statement computes: in $y[$n] = $C[$i] + $C[$i + 64] over an array of floating-point numbers, the integer $i + 64 made the compiled loop treat the whole statement as integer arithmetic, and every element fell back to the interpreter until the loop was given up. Arithmetic that only computes an array index is now plain integer arithmetic, its overflow checked, whatever the elements hold. Loops of this kind that ran about four times slower when every value they computed was 0.0, such as a reverb fed silence, now run as fast as on any other input.

  • Float arithmetic survives a run of zeros: a loop that computes with arrays of floating-point numbers, such as an audio filter fed silence, kept falling back to the interpreter while every value it saw was zero, and was then replaced by a slower form that also ran the signal after the silence. An array of floats that also holds a value perl keeps as an integer too is now recognised as an array of floats.

  • A copied array element keeps its spelling: in compiled code, copying an array element that holds a number written as a string, such as my $x = $list->[$i] of “-2.0”, “0.10” or “1e1” after it had been compared numerically, gave the number instead: “-2”, “0.1”, “10”. The copy is now the string, as in perl. Complete::Sah’s completions of floating-point values were affected.

  • A next out of a branch that was cold no longer crashes: a loop nest compiled while an if branch holding its own loop and a next had never run, as in if ($four) { while (...) { ... } next }, could crash pperl once that branch ran, when the enclosing sub returned. It runs as under perl now.

  • A loop that increments the position it reads no longer crashes: a loop such as for (my $k = 0; $k < length $s; $k++) { $n += ord substr($s, $k, 1) } aborted pperl once it ran often enough to be compiled. Such loops now run compiled.

  • Negative array indexes stay compiled: $a[-1], or an index such as $n - 100 that goes below zero, counts from the end of the array in compiled code. In a loop over an array of plain numbers, each such access used to fall back to the interpreter, and a loop doing it often was given up.

  • Loops over unsigned 64-bit integers stay compiled: a loop whose numbers go past 9223372036854775807, perl’s unsigned integers as in 64-bit hashes, masks and random numbers, or a C function returning uint64, fell back to the interpreter on every trip until the JIT gave the loop up, and one naming such a number as a constant, such as 0x9E3779B97F4A7C15, was never compiled. Such loops now run compiled with perl’s exact values, under use integer too; a result perl computes as a floating-point number still takes the interpreter’s path. A loop that only reads a large integer, such as an argument of -9223372036854775808, no longer leaves the compiled code each time it starts either.

Language and runtime#

  • END blocks run after an exit during compilation: when a program exits or dies while it is still being compiled, in a BEGIN block or in the import a -MModule=... switch calls, the END blocks compiled so far now run and can set the exit status, as in perl. A failing test file that exited this way reported success, which broke the test suite of Test::Needs and every CPAN distribution that needs it. An END block that sets $? to 0 after exit 5 now makes the exit status 0.

  • Arguments that are not UTF-8: an argument that is not valid UTF-8, such as a file name in Latin-1, made pperl stop with an internal error before running anything. Arguments, -e code, script names and -I directories now reach the program byte for byte, as in perl. And pperl -e CODE a -x hands its program a and -x instead of rejecting -x as an unknown option.

  • A regex match creates no variable: a pattern match no longer creates ${^RE_DEBUG_FLAGS} in main::, and no longer looks that variable up on every match. Code that walks the main symbol table while matching names, such as Devel::Symdump, saw it appear under its iterator and warned “Use of each() on hash after insertion”.

  • The built-in library is a directory on disk: the modules built into pperl are a real directory now, $Config{privlibexp} under ~/.cache/pperl, which @INC, %INC and __FILE__ name. It is written the first time a program looks at it - a file test, opendir, chdir, glob, abs_path or reading a module as a file - never at startup, and holds the modules as perl installs them, documentation included, with perl’s pod/ files and Config.pod. Tools that search @INC as a filesystem, such as Pod::Find, Module::Path and Module::List, find pperl’s own modules now.

  • @INC hooks see built-in modules: a code reference at the front of @INC, as Test::Without::Module and use lib sub {...} put it there, is asked for a built-in module before pperl’s own copy is used, as in perl. Such a hook can hide a built-in module or serve its own version of it. A directory in @INC still never replaces a built-in module.

  • Modules fall back to Perl when their compiled part is missing: a module whose compiled part pperl does not have now fails to load with perl’s message for that case, “Can’t locate loadable object for module … in @INC”, instead of “dynamic loading not available”. Modules that try their compiled part and go on in Perl without it look for exactly that message, so DateTime and others now run in their Perl implementation where they died before.

  • A built-in module’s file runs however it is reached: when a built-in module’s file reaches perl without a plain require - served by an @INC hook such as lib::filter’s or a FatPacker one, read with do FILE, or checked with perl -c - its compiled part now loads, as perl finds the module’s shared object. Such a file used to die “Can’t locate loadable object”, which took Moo down with lib::filter.

  • Installed scripts run with pperl: $Config{perlpath} and $Config{startperl} name the pperl binary that is running. They named /usr/bin/perl, so the commands a distribution installs with pperl --cpan started the system’s perl, or failed on a machine without one.

  • pperl starts faster: a short script runs in about a quarter less time, as the binary has less than half the addresses to fix up when it is loaded and a run no longer reads the CPU topology unless it goes parallel. The binary is also 5.5 MB smaller. A panic inside pperl itself, which is always a bug, no longer names a source file and line.

  • Catching errors from built-in modules no longer leaks memory: a built-in module that died with an error built at run time left a few hundred bytes behind every time, so a program catching such errors in a loop with eval grew without bound. Peta::FFI, Storable, Opcode, POSIX and the other built-in modules now free everything before they die, and opset with an unknown name no longer leaks the set it was building, as it does under perl. The error messages are unchanged.

Modules#

  • DBI 1.655: the built-in DBI is 1.655, up from 1.651. DBD::DBM accepts only a module name as dbm_type and dbm_mldbm, so a file path given there is no longer loaded and run, and DBD::File no longer reads a table linked into a directory whose name merely begins with that of f_dir. These are the fixes for CVE-2026-78030 and CVE-2026-15392.

  • DBI: sql_type_cast and fetchrow_hashref as in DBI under perl: DBI::sql_type_cast returns what DBI’s compiled version returns, so SQL_INTEGER refuses “3.14”, “1e3” and “inf”, DBIstcf_DISCARD_STRING leaves only the number, and the two flags have DBI’s values. A plain number with SQL_INTEGER and DBIstcf_DISCARD_STRING is handled too, where DBI 1.655 aborts perl. fetchrow_hashref with a key name that holds no column list, from FetchHashKeyName or its argument, sets the handle’s error and returns undef instead of dying whatever RaiseError says, and a number as that name is taken as a name.

  • PDL: update_data_from reads the value of a tied source: $pdl->update_data_from($bytes) fetches a tied or otherwise magical $bytes and copies its current value, as PDL does under perl. It used to copy whatever that scalar last held.

  • PDL: the operator overloads are PDL’s own subs: PDL::overload_plus and the other handlers PDL installs for its operators exist under their names and are what overload::Method returns, as with PDL under perl. An error raised through an operator, such as a broadcast mismatch in $a + $b, now names PDL’s own line and the handler in its backtrace, and so does a warning such as “isn’t numeric” for a string operand. A redefined PDL::plus, or a subclass’s own inplace, is now what the operators use.

  • PDL::FFT loads quietly under -w: use PDL::FFT under -w no longer warns “Subroutine PDL::realfft redefined”, as it doesn’t with PDL under perl.

  • Pod::Text and Pod::Man 6.1.1: the POD formatters are those of podlators 6.1.1, up from the 6.0.2 that perl 5.44.0 ships. Formatting a document whose =over nesting brings the margin to the output width no longer loops forever while the output fills memory (CVE-2026-82560). Pod::Man lists with tags now use .TP and the fixed-width font is CR, for groff 1.24.

  • Text::LineFold no longer repeats its input: fold on text holding form feeds, vertical tabs or other special breaks returned the whole text once for every piece between them, so the output grew with the square of the input (CVE-2026-8594). Each piece is folded once now; the Text::LineFold of CPAN still has the fault.

  • Hash::Util::FieldHash is built in: perl’s field hashes for inside-out classes, whose entries vanish with the object they are keyed by, together with id, id_2obj, register and idhashes. It was the one module of perl’s own library that would not load, and B::Hooks::EndOfScope, namespace::clean, namespace::autoclean and Mojolicious, which need it, now install from CPAN and pass their tests.

  • Five more CPAN modules with compiled parts are built in: XString 0.005, Test::LeakTrace 0.17, PerlIO::utf8_strict 0.010, Scalar::Util::Numeric 0.40 and Sub::Identify 0.14. Each passes its own test suite with the results it has under perl. Distributions that need one of them, such as DateTime, Specio, PPI and Template Toolkit, get past it when they are installed from CPAN.

  • Sub::Name is built in: Sub::Name 0.28, which renames a sub for caller and stack traces, passes its own tests as under perl. It runs the code of Sub::Util::set_subname, which perl ships and which was taken from it, so renaming a sub under the debugger no longer leaks a reference to its %DB::sub entry with every call, as Sub::Name does under perl.

  • B::COW is built in: B::COW 0.007 reports whether a string shares its buffer copy-on-write and the share count, with the same answers as under perl, and passes its own tests.

  • Digest::SHA1 is built in: Digest::SHA1 2.13, the SHA-1 module older code uses where newer code uses Digest::SHA, passes its own tests with the results it has under perl. Its digests are computed by the built-in Digest::SHA, with the processor’s SHA instructions where it has them. sha1_transform given more than 64 bytes uses the first 64, where perl aborts.

  • String::CRC32 is built in: String::CRC32 2.100 computes the CRC-32 of a string or of what a filehandle reads, with the results it has under perl, and passes its own tests. The CRC is computed by the zlib of the built-in Compress::Raw::Zlib. A filehandle whose read fails, such as a closed one, gives the CRC of no data, where perl crashes.

  • Crypt::OpenSSL::Random is built in: Crypt::OpenSSL::Random 0.17 draws bytes from OpenSSL’s random-number generator and seeds it, in the builds that include Net::SSLeay, and passes its own tests. It reaches libcrypto through Net::SSLeay, so both draw from one generator. Asking for 0 bytes returns the empty string, where perl returns stray memory; a negative count returns false, and 0 from Net::SSLeay’s RAND_bytes, where perl exits.

  • URL::Encode is built in: URL::Encode 0.03 and its fast half URL::Encode::XS encode and decode URL-encoded strings and split query strings into their parameters, with the results they have under perl, and pass their own tests. The fast half is used, as under perl when it is installed, and is about 17 times as fast as the pure-Perl one.

  • Text::LevenshteinXS is built in: Text::LevenshteinXS 0.03 computes the edit distance of two strings, with the results it has under perl, and passes its own tests. Long strings work: perl needs memory for a table of both lengths multiplied, and crashes when that memory is not there (two strings of 20000 bytes need 1.6 GB).

  • Math::Random::MT is built in: Math::Random::MT 1.17, the Mersenne Twister random-number generator, gives the same sequences as under perl for the same seeds, and passes its own tests.

  • Data::UUID is built in: Data::UUID 1.227 makes time-based and name-based UUIDs and converts them, passing its own tests with the results it has under perl. Its name-based UUIDs are computed by the built-in Digest::MD5. Where perl reads or writes past a string - a binary UUID shorter than 16 bytes, a Base64 UUID that is too short, too long or has bytes above 0x7F, a hex UUID that ends inside a byte - the result is zero-filled, cut to 16 bytes, or an error instead.

  • Params::Util is built in: Params::Util 1.102, whose checks such as _STRING, _HASH and _INSTANCE many CPAN modules validate their arguments with, passes its own tests with the results it has under perl. It did not load at all before, so PPI, Package::DeprecationManager, Config::MVP and the modules that need them could not be installed from CPAN.

  • Class::Load::XS is built in: the compiled is_class_loaded of Class::Load::XS 0.10, which Class::Load uses when it is there, passes its own tests with the results it has under perl. Class::Load itself, which loads it, is installed from CPAN as before.

  • Template::Stash::XS is built in: the compiled stash of Template Toolkit 3.106, which the Template Toolkit uses by default, passes the Template Toolkit’s own tests with the results they have under perl. The Template Toolkit itself, which did not install without it, now installs from CPAN with pperl --cpan. A method that dies “Can’t locate object method” no longer overwrites the caller’s arguments, and set on a value that is not a reference dies with an error where perl crashes.

  • Package::Stash::XS is built in: Package::Stash::XS 0.32, the compiled implementation of Package::Stash that Moose, namespace::clean and many others read and change symbol tables through, passes its own tests with the results it has under perl. Package::Stash itself comes from CPAN and now uses it, as it does under perl, instead of its pure-Perl implementation.

  • List::MoreUtils::XS is built in: the compiled backend of List::MoreUtils 0.430 passes its own tests and those of the front end with the results they have under perl, and List::MoreUtils, installed from CPAN, now uses it instead of its pure-Perl implementation. Where perl crashes or answers wrongly, pperl does not: a block that is a compiled sub, arrays with holes, objects overloading @{} over a hash, and <=> overloading that gives no number. reduce_u, reduce_0 and reduce_1 no longer overwrite the caller’s $_, and frequency no longer leaks.

  • Term::ReadKey is built in: Term::ReadKey 2.38 sets terminal modes, reads keys with a timeout or without blocking, and reports the terminal’s size, speed and control characters as it does under perl; modules that need it, such as CPAN::Uploader, now install from CPAN. Where perl aborts, pperl does not: a timed read on a closed handle or on a descriptor of 1024 or above, and SetTerminalSize with a width or height ten characters long. GetSpeed of a handle that is not a terminal returns 0 for both speeds where perl returns leftover memory.

  • Filter::Util::Exec, Filter::tee and Filter::decrypt are built in: the source filters of Filter 1.65 that run a program through a command (Filter::exec, Filter::sh, Filter::m4), copy it to a file or decrypt it work as they do under perl and pass the dist’s own tests. Where perl crashes, pperl does not: these filters, and filter_add of Filter::Util::Call, called while nothing is being compiled. A command that stops reading early, such as head -n 1 on a long source, no longer kills the program without a word or leaves it empty: what the command wrote is compiled. Filter::cpp is not available, because pperl’s configuration names no C preprocessor.

  • IO::Tty and IO::Pty are built in: IO-Tty 1.31 allocates pseudo-terminals, names them, sets their window sizes and defines the terminal constants as it does under perl, and passes the dist’s own tests. Where perl crashes or reports a length it read from unrelated memory, pperl does not: IO::Tty::unpack_winsize of undef, a number or a reference dies saying the length is 0.

  • Moose loads: the compiled part of Moose 2.4001 is built in, so Moose’s own modules load and pass Moose’s own tests with the results they have under perl. pperl --cpan installs Moose and what is built on it, Catalyst and Dist::Zilla among them: a distribution’s check for a working C compiler (ExtUtils::HasCompiler) answers yes when the compiled part it needs is built in. Where perl crashes on a malformed metaclass or method object, pperl dies with an error or leaves it alone.

  • JSON::XS is built in: JSON-XS 4.04 encodes and decodes JSON, parses it incrementally and calls TO_JSON, FREEZE and THAW as it does under perl, and passes its own tests; Types::Serialiser, whose booleans JSON true and false decode to, is built in with it. Where perl crashes, pperl does not: a method called on something blessed into JSON::XS that new did not make dies with an error, and JSON::XS::CLONE called by hand no longer breaks new.

  • YAML::XS and YAML::PP are built in: YAML-LibYAML 0.910.0 loads and dumps YAML with the settings, objects and output it has under perl and passes its own tests, over YAML::PP 0.43.0, pperl’s YAML engine. YAML is read as the YAML 1.2 specification reads it, so the few documents libyaml reads otherwise, rejects or wrongly accepts follow the specification, and Dump escapes U+2028 and U+2029 so that what it writes loads back unchanged. Where perl crashes or refuses, pperl does not: the object interface loading a flow mapping inside a flow sequence, and dumping strings of latin-1 bytes. A document that does not parse dies with YAML::PP’s account of the problem: nearly always the same document and line, in other words.

  • FFI::Platypus is built in: FFI-Platypus 2.12 calls C functions with every type it offers, from integers, strings and arrays to records by value, closures and custom types, as it does under perl, and no C compiler is needed to install it. Where perl fails, pperl does not: reading an array member of a record no longer leaks memory, an index past an opaque array member warns instead of reading beyond the record, and a hash reference passed for a pointer no longer crashes. A regex capture or a tied scalar passed as an argument passes its value, where perl passes 0, or no string at all, which crashes strlen($1), and a callback that a library calls from a thread of its own stops the program with a message where perl crashes.

  • FFI::Build is built in: a CPAN module that ships C code for FFI::Platypus to call, built at install time with FFI::Build, now installs, passes its tests and runs under pperl when a C compiler is on PATH, as it does under perl. Capture::Tiny, which FFI::Build uses, is built in with it.

  • DynaLoader loads shared libraries: dl_load_file, dl_find_symbol, dl_unload_file, dl_findfile and the rest work on any C library as they do under perl, and FFI::CheckLib, which finds libraries with them, is built in. A module’s compiled part is still never loaded from a file: XSLoader and DynaLoader::bootstrap load only pperl’s built-in modules. Unloading a library that failed to load no longer crashes, as it does under perl when FFI::CheckLib meets a linker script such as libm.so.

  • XSLoader checks the version a module asks for: XSLoader::load($module, $VERSION) dies “… object version … does not match bootstrap parameter …” when the built-in compiled part is of another version, as it does under perl, and loads a built-in module’s compiled part even when nothing has required the module yet.

  • Peta::FFI reaches more of any C library: signatures gain fixed-width integers from i8 to u64, bool, variadic functions such as ioctl and snprintf, strings the caller must free, and C objects as Perl objects whose destructor runs with their last reference. function and attach prepare a C function once and call it as a Perl sub, a function pointer can be called by its address, and errno reports what a call left behind. A callback that a library calls from a thread of its own now stops the program with a message instead of corrupting it, and Peta::FFI::EventSource brings such a library’s events to Perl through a file descriptor that AnyEvent, EV, Mojo::IOLoop or a select loop watches. scan finds the libraries in the directories it is given, or in PETA_FFI_PATH and the dynamic linker’s own, and lists only the files this program can load.

  • Peta::FFI passes C structs, arrays and long doubles: record declares a C struct as a Perl class with an accessor per member, and a signature passes and returns it by value or by pointer, callbacks included. Signatures gain pointers to numbers and strings for out-parameters, arrays the function reads and changes in place, long double and the complex types, and an output buffer that holds what the function wrote. symbol, fetch, store and variable read and write a library’s global variables and any typed value in memory. FFI::Platypus now runs on the same engine, so whatever it can call, Peta::FFI can.

  • Peta::FFI reaches C unions: union declares one as record declares a struct, with every member at its start, to be passed by pointer and read and written in memory, as SDL_PollEvent fills an SDL_Event. Passing a union by value is refused, because on some platforms that would call the function wrongly instead of failing. A record member that is itself a record now reads as an object of its class and is set from one.

  • Peta::FFI takes what C functions hand over: a handle or a string a function stores through a pointer, as sqlite3_open does, becomes the caller’s object or string, and arrays of handles, of records and of pointers ended by NULL can be passed. An array the function allocates itself, its length given by the result, by another argument or by a NULL at its end, comes back as a Perl array of objects, strings, records or numbers. Everything is freed with the library’s own functions once nothing uses it, so a record taken from such an array still reads its strings for as long as it lives.

  • Peta::FFI reads arrays C lends and sets strings in records: an array a function hands out from memory it keeps, as libxkbcommon hands out a keymap’s keysyms, is written &T[r], &T[#k] or &T[0] and is copied without being freed, whether it comes through an argument or, as &T[#k] or &T[0], as the result. A record’s string member can now be set from Perl: the record keeps its own copy for as long as it lives, undef passes NULL, and a string C put there is never freed by Perl. When C moves the strings between records, as sorting an array of them does, each string stays alive with the record that now points to it.

  • Peta::FFI reads byte buffers C allocates: a buffer a function allocates and hands over through a pointer, with its length in the result or in another argument, is written *P[r] or *P[#k]. It arrives as one byte string, NULs and all, and is then freed with the library’s own function, which is how librados’s rados_mon_command returns its reply. Bytes a function only lends, &P[r] or &P[#k], are copied and never freed, and a callback handed bytes with their length, &P[#k], gets them as a string.

  • Peta::FFI::Pool runs C calls that may hang: a function prepared with Peta::FFI runs on one of a pool’s threads, with a deadline, so statfs on a dead NFS mount no longer needs a child process with a timeout. Each call is reported as an event, through a descriptor any event loop can watch as a Peta::FFI::EventSource: done, with its result and what it wrote back; timed out; or busy, when every thread is taken. A call that returns after its deadline changes nothing.

  • Peta::FFI::Queue takes callbacks from a library’s own threads: a closure made with queue => $queue may be called on any thread, as librados calls its monitor log and watch callbacks. It copies its arguments into the queue, returns a value given once, and its sub runs later, when Perl’s event loop takes the queue’s events through a Peta::FFI::EventSource. A queue holds a bounded number of calls and counts those it had to drop.

  • Loops that call C functions run compiled: a loop calling a C function prepared with Peta::FFI or FFI::Platypus used to stay out of the JIT entirely. When the function takes and returns plain integers, pointers or floating-point numbers, the compiled loop now calls it directly; other calls, and any call while C holds a Perl callback, still go through the library as before.

  • C functions called often cost less: a C function prepared with Peta::FFI’s function or attach, or attached with FFI::Platypus, that takes and returns plain numbers or pointers is compiled into machine code of its own once it has been called a few thousand times. A call of labs or ldexp outside a compiled loop then takes about 30% less time, with the same results and the same errors as before. A function that is seldom called is never compiled, so declaring a library’s functions costs no more than it did.

  • Peta::LMDB and Peta::PCRE2 are now Peta::FFI::LMDB and Peta::FFI::PCRE2: pperl’s own modules for C libraries live under Peta::FFI, beside Peta::FFI::UUID. Programs that load Peta::FFI::LMDB or Peta::FFI::PCRE2 work as before, with the class names, error class and $Peta::FFI::LMDB::DBM_WRITE renamed to match; the old names no longer load.

  • Cairo survives a libcairo without a function it calls: when the installed libcairo lacks a function a Cairo method needs, as an older release does, calling the method stopped the whole program. It now dies with a message naming the function, which eval catches, as the other library modules already did.

  • EV and Coro no longer need a system perl: the built-in EV and Coro start with use common::sense, which pperl did not carry, so they loaded only where a system perl’s copy was on @INC, and AnyEvent otherwise fell back to its pure-Perl event loop without a word. common::sense 3.75 is built in now, with the warnings and features it sets under perl 5.44.

  • Event runs on libev, and EV and Event share signals: Event now waits for descriptors, signals and time through libev, the engine behind EV, and reports the same readiness and conditions as before; its timers and event queues are its own, as they were. A signal that both modules watch now reaches the watchers of both. Under perl the module that installed its handler last took it, and an EV loop reading signals through a signalfd hid them from Event entirely.

  • XML::Parser, HTML::TokeParser and PDL::IO::Pic load without a system perl: they need File::ShareDir, HTML::Tagset and File::Which, which pperl did not carry, and loaded only where a system perl’s copy was on @INC. Those three are built in now, with Class::Inspector, which File::ShareDir needs; HTML::LinkExtor is fixed with them.

  • XML::Parser parses with libxml2: XML::Parser and XML::Parser::Expat read documents with libxml2 2.15 or newer, and the expat library is no longer needed. Handlers see what they saw over expat: the same calls with the same arguments, character data split where expat splits it, the same positions and source text from current_byte, recognized_string and original_string, and expat’s error messages. A document with standalone="yes" has the parameter entities of its internal subset read, as XML requires; expat left them unread and then refused the document.

  • Devel::Cover measures coverage: the compiled part of Devel::Cover 1.52 is built in, so with the distribution installed by pperl --cpan Devel::Cover, pperl -MDevel::Cover collects statement, branch, condition and subroutine coverage, and cover reports it, with the same counts as perl. Devel::Cover’s own test suite passes. While it collects, loops are not compiled, since compiled code would bypass the counting.

  • JSON::PP works in compiled code: JSON::PP encodes and decodes with the same compiled engine as JSON::XS, with JSON::PP’s own options, results and error messages, about 6 times faster at encoding and 14 times at decoding. CPAN’s metadata files and everything else that reads or writes JSON through it gain with it. Where JSON::PP went wrong it no longer does: decode_prefix counts characters as documented, what a FREEZE method returns is encoded as JSON, the incremental parser keeps Latin-1 text and the rest of its buffer as they are, and bare keys keep their non-ASCII characters.

  • Text::CSV is built in: Text::CSV 2.06 comes with pperl, and its pure-Perl engine Text::CSV_PP parses, warns and checks its settings as Text::CSV_XS 1.65 does. A CR at the very end of the input after an empty last field is error 2032, as after any other field; a failed print returns “” and warns where it was called; a separator, quote or line end longer than 16 bytes is refused. Installing Text::CSV with pperl --cpan gets the same engine, and Text::CSV_XS installs over it with all of its own tests passing.

Command line#

  • pperl -S finds the program on PATH: pperl -S prove runs the prove installed on the search path, as perl -S does; pperl rejected the switch.

  • A program’s arguments are its own: pperl’s switches, such as --parallel or --no-jit, are read only before the program, as perl reads its own. After it, they reach the program in @ARGV; pperl used to take them out, so tool.pl --parallel 4 list saw only 4 list.

  • pperl -v names the build and credits perl: the first line names what kind of binary it is, its native tier and added features such as dbi, pdl or shell, the second is the copyright, and the text says pperl is “compatible to perl 5.44 by Larry Wall and others”. pperl -V still lists everything. Tests that read -v as perl’s, such as those of IPC::System::Simple and Expect, pass.

  • pperl –cpan no longer asks you to set PPERL5LIB: pperl finds what it installs into your own tree without it, so the advice that ended every install is gone.

  • pperl –cpan –system installs where pperl looks: a system-wide install now goes to /usr/local/share/pperl/site_perl, which every pperl searches, with its scripts and manuals beside it; it used to land in a directory pperl never looked in. It now stops before downloading anything when the account may not write there, and says to run it as root.

  • pperl –cpan applies distribution preferences: a CPAN.pm distroprefs file under ~/.pperl/cpan/prefs that matches a distribution now takes effect, including its patches, which are looked up beside it. A .yml preference used to be read only where the separate YAML distribution happened to be installed, and now uses pperl’s built-in YAML::XS. Any patch a preference named stopped the install, because no patch command was configured.

  • pperl –cpan installs XS distributions it has a substitute for: each run first fetches pperl’s pure-Perl substitutes for distributions with a compiled part from https://perl.petamem.com/downloads/cppan, so a substitute published after your pperl applies to it too. Text::CSV_XS installs and runs on the Perl engine of Text::CSV, true, multidimensional and bareword::filehandles on perl’s own features, Scalar::Readonly, Test::Taint, Regexp::Util, next::XS and Socket6 on its built-in modules, and Crypt::SSLeay (Net::SSL) on its OpenSSL binding, where it no longer builds under perl with OpenSSL 3; the few places where their own tests show a difference are marked as known in them. PPERL_CPPAN_URL names another address, and set empty it skips the fetch.

  • JavaScript::QuickJS runs on QuickJS-NG: pperl --cpan installs JavaScript::QuickJS as a binding over the QuickJS-NG library (libqjs.so.0, on Arch Linux the quickjs-ng package), used where it is installed; without it the module installs, its tests skip and say why, and it works once the library is there. The distributions that need it, such as Data::Sah and the Perinci family, install with it. Where QuickJS-NG differs from the QuickJS the CPAN distribution bundles, its own behaviour shows: its error messages, and a Date’s getTime as a floating-point number.

  • pperl –cpan downloads over https with curl or wget: like perl’s own first-run setup, it now finds make, tar, gzip, gpg, wget or curl and the other tools CPAN.pm uses on your PATH. A pperl built without TLS support therefore fetches from CPAN over https through wget or curl instead of falling back to plain http, and the XS substitutes come the same way.

  • pperl –cpan builds the pure-Perl form of a distribution: it asks every build for the distribution’s Perl-only variant, as PUREPERL_ONLY=1 and --pureperl-only do, so a distribution such as Params::Validate that has a Perl implementation beside its compiled one installs instead of failing for want of a C compiler. A module that does not load without its compiled part is named and kept, not removed: Params::Util switches to its Perl half when its tests ask for it, and those tests now run.

  • Config names the C compiler: $Config{cc}, its flags, its preprocessor and gccversion describe the C compiler found on PATH (cc, gcc or clang), so FFI::Build compiles the C libraries a distribution bundles and Devel::CheckLib’s probes run. usedl and dlsrc say what perl’s say on Linux, as DynaLoader loads shared libraries. Modules with a compiled part still load only when they are built in, and ExtUtils::CBuilder’s have_compiler still says no.

  • @INC includes the architecture directories of PERL5LIB and -I: as under perl, each entry’s x86_64-linux subdirectory, and that of each of its version directories, comes ahead of the entry when it exists. An installer puts a distribution’s Perl files there whenever the distribution carries anything architecture-dependent, so modules installed into a local::lib by cpanm -l, Alien modules among them, are now found. pperl --cpan installs into its tree’s architecture directory as perl’s installers do, and pperl’s own tree is searched the same way.

  • ipps runs programs as functions: with the new autorun setting on, calling a sub that does not exist runs the program of that name and returns its output, a list of lines in list context, as in whoami() or my @files = ls('*.pl'). :programs ls cat makes such names subs that need no parentheses, whether autorun is on or not, and :programs alone lists them. A program that cannot be run is an error, and the exit status is in $? as for backticks.

Documentation#

  • Links in the changelog: the entries of every version link the modules, built-in functions, command-line options, guides and tutorials they name to their pages, in every language of the documentation.