MANUAL
RakuPM Manual
A comprehensive, authoritative reference for raku-pm โ from first install to advanced contributor workflows.
Version 0.77.0 | Quick start | Architecture deep dive | Commands wiki | ไธญๆ็
Table of Contents
1. Overview
RakuPM is a teaching package manager for the Raku programming language. It is a fully functional MVP (~3,700 lines of Raku, 40 library modules + 1 CLI entry point) modelled on the layered, pluggable architecture of zef.
RakuPM can:
Discover, resolve, download, build, test, and install Raku packages from ecosystem indexes (zef, REA, CPAN) and local directories
Install directly from git URLs with full recursive dependency resolution
Manage multiple repository indexes with priority ordering and offline caching
Perform atomic installs with transaction rollback (generations)
Detect system native libraries (
:from<native>) across Windows, macOS, and LinuxAuthor and publish packages via a complete producer-side workflow
Self-upgrade via a two-stage bootstrap mechanism
Key Design Principles
| Principle | Description |
|---|---|
| Layered, pluggable architecture | Modeled on zef; each module has a single, well-defined responsibility |
| zef compatibility | Same META6.json format, spec string syntax, CUR::Installation target, upload protocol |
| Multi-version coexistence | Multiple versions of the same package live side-by-side; use :ver<> selects the right one |
| Atomic installs | All-or-nothing: if any package in the tree fails, the target is restored to its prior state |
| Content-addressed store | Packages are stored with MD5 digests for tamper detection |
| Zero external dependencies (beyond 4) | MD5 is pure-Raku; UI is pure-Raku; no build system beyond META6.json |
2. Prerequisites
| Requirement | Version | Notes |
|---|---|---|
| Rakudo | 6.d or later | The Raku compiler |
| Git | any recent | Required for git installs, self-upgrade |
Runtime dependencies (auto-installed by zef)
| Package | Purpose |
|---|---|
JSON::Fast | JSON parsing/generation |
HTTP::Tinyish | HTTP client (system curl backend) |
URI | URI parsing |
MD5 is implemented in pure Raku (
RakuPM::MD5), so no ecosystem dependency is needed for content digests.
3. Installation
Option A: Run from source (recommended)
This is the most robust method โ it avoids version mismatches when you have multiple Rakudo installs.
git clone https://gitee.com/skyter10086/raku-pm.git
cd raku-pm
raku bin/raku-pm.raku --help # prints help => environment is OKEvery invocation uses raku bin/raku-pm.raku [command] (or raku -Ilib bin/raku-pm.raku [command] if the lib directory is not auto-detected).
Optionally, create a shell wrapper for convenience:
# bash / zsh
cat > ~/.local/bin/raku-pm <<'EOF'
#!/usr/bin/env bash
exec raku "$HOME/raku-pm/bin/raku-pm.raku" "$@"
EOF
chmod +x ~/.local/bin/raku-pmOption B: Install as a global command via zef
git clone https://gitee.com/skyter10086/raku-pm.git
cd raku-pm
zef install .This gives you a raku-pm command on PATH. On Windows, zef generates raku-pm.exe under site/bin.
Gotcha: a legacy zef wrapper swallows
raku-pm --help(its*%named-parameter signature takes--helpfor itself); the wrapper raku-pm generates itself does not (see the section at the end of ยง17). Preferraku-pm help. The default output is a compact command index (one screen);raku-pm help <command>shows one command,raku-pm help <group>shows a whole group (e.g.raku-pm help authorfor the publishing commands), andraku-pm help allthe full manual.
Set environment variables
export RAKUPM_REPO=repo # local repo root
export RAKUPM_TARGET=$HOME/.raku-pm # install root (store/ + site/ + lockfile)Both directories are created automatically on first run.
After installing a package, put inst#<target>/site on the module search path:
export RAKULIB="inst#$HOME/.raku-pm/site"
raku -e 'use File::Temp; say tempfile'Run
raku-pm envto print the exact export lines for your current prefix.
4. Configuration
4.1 Environment Variables
Environment variables control runtime behavior. They are listed in full in Section 19. The most commonly used:
| Variable | Purpose | Default |
|---|---|---|
RAKUPM_TARGET | Install prefix (store / site / lockfile / git-cache) | ~/.raku-pm |
RAKUPM_REPO | Local repository root | . (cwd) |
RAKUPM_ECOSYSTEM | Ecosystem index URL(s), comma/semicolon-separated | (none; when unset, built-in default is zef+cpan+rea+local; setting it overrides the built-in indexes) |
RAKULIB | Module search path (must include inst#<target>/site) | (none) |
RAKUPM_OFFLINE | Offline mode (1/true/yes/on) | (off) |
RAKUPM_NO_COLOR | Disable color output | (off) |
NO_COLOR | Disable color (industry standard) | (off) |
4.2 Config Files
| File | Location | Purpose |
|---|---|---|
repositories.json | <target>/repositories.json | Persisted repository configuration |
installed.json | <target>/installed.json | Ledger of installed packages |
raku-pm.lock | $CWD/raku-pm.lock (default) | Lockfile for reproducible installs |
credentials.json | <target>/credentials.json | API key storage for ecosystem upload |
META6.json | Distribution root | Package identity (name, version, provides, depends) |
4.3 Global Options
Every command recognizes these options:
| Option | Description |
|---|---|
--target=<dir> | Override $RAKUPM_TARGET for this invocation |
--no-lock | Skip the cross-process file lock (dangerous if another process writes) |
--promote-bin / --no-promote-bin | Whether to place the bin wrapper on the global PATH |
--offline | Alias for RAKUPM_OFFLINE=1; no network requests |
5. Core Concepts
5.1 The Target Directory Layout
$RAKUPM_TARGET/ default ~/.raku-pm
โโโ cache/ ecosystem indexes + downloaded tarballs & unpack dirs
โ โโโ index-360.zef.pm.json
โ โโโ dist/<dist>/<version>/
โโโ store/ source snapshots: multiple versions coexist, only grows
โ โโโ <dist>/<version>/
โ โโโ META.json raku-pm's normalised metadata
โ โโโ META6.json Raku standard metadata (what CUR reads)
โ โโโ lib/ sources
โ โโโ resources/ resources (native .so/.dll build output lives here)
โ โโโ build.json build-trace sidecar
โ โโโ .digest content digest (MD5, tamper detection)
โโโ site/ โ
the live CompUnit::Repository::Installation
โ โโโ precomp/ precompilation, managed by Rakudo
โ โโโ dist/ per-distribution metadata (multiple versions coexist)
โโโ installed.json raku-pm's installed ledger
โโโ raku-pm.lock lockfile (in the target by default; also $CWD)
โโโ generations/ generation snapshots (for rollback)
โโโ git-cache/ git clone cache
โโโ log/<dist>/<version>/ test output logsKey distinction: store/ vs site/
store/is the source cache โ one download can be deployed repeatedly; reinstalling after an uninstall never re-downloads from the network.site/is the runtime โ theCompUnit::Repository::Installationthat Rakudo'suseresolves from.
5.2 Multiple Version Coexistence
Raku's use Foo (without a version constraint) always loads the highest installed version. raku-pm's design embraces this:
installed.jsonrecords all installed versions.To use a specific version, write
use Foo:ver<1.2.3>in your code, or use--onlyto remove higher versions.
Downgrade caveat: Installing an older version does not switch
useover by default. It just adds another version alongside. To make the old version active, eitherupgrade Foo --version=X --onlyor use:ver<>in code.
5.3 The Ledger (installed.json)
The ledger is the single source of truth for "what is installed." Every entry carries:
name,version,auth,apiโ identityprovidesโ which modules this distribution providesdigestโ content hash for tamper detectionsource-dirโ the source directory in the store (for reinstalls)reasonโexplicit(user requested) ordependency(pulled in as a dependency)
The reason field powers autoremove: only dependency-reasoned packages are reclaimed when nothing depends on them anymore. Packages you explicitly installed are never reclaimed.
6. Command Reference
6.1 Package Operations
install
Install a package and all its dependencies.
raku-pm install <module|url|path> [options]Targets:
Module name:
install File::TempSpec string:
install 'Foo:ver<1.2.3>:auth<zef:x>'Git URL:
install https://github.com/user/repo.gitLocal directory:
install .orinstall /path/to/dist
Options:
| Flag | Description |
|---|---|
--version=X | Pin an exact version |
--locked | Strict lockfile mode; abort if lock disagrees |
--no-test | Skip the test phase |
--no-build | Skip the build phase |
--no-test-deps | Do not install test dependencies |
--no-native-check | Skip native library detection |
--force | Re-run everything, even if already installed |
--allow-test-failure | Install even if tests fail (use with caution) |
--test-timeout=S | Per-test timeout in seconds (default: 300) |
--dry | Resolve only; do not install |
--lock-file=<path> | Use a specific lockfile |
--pin=Mod@ver[,โฆ] | Pin specific dependency versions |
Spec string precedence: --version > :ver<> in the spec > the positional constraint.
Examples:
raku-pm install File::Temp # latest from ecosystem
raku-pm install 'Concurrent::Stack:ver<1.1>' # exact version
raku-pm install 'Concurrent::[email protected]' # @ shorthand (same thing)
raku-pm install Concurrent::Stack --version=1.1 # flag form
raku-pm install https://github.com/user/repo.git # from git
raku-pm install . # current directory
raku-pm install Web::App --dry # resolve only
raku-pm install File::Temp --no-test # skip testsupgrade
Upgrade installed packages to a newer version.
raku-pm upgrade # upgrade ALL installed packages
raku-pm upgrade <module> # upgrade one to latest
raku-pm upgrade <module> --version=X # upgrade/downgrade to specific version
raku-pm upgrade --only # after upgrade, remove all other versions
raku-pm upgrade --dry # preview only
upgradewithout a package name follows theapt upgrade/zef upgradeconvention.
uninstall
Remove installed packages.
raku-pm uninstall <module> # remove ALL versions
raku-pm uninstall <module> --version=X # remove only that version
raku-pm uninstall <module> --keep-store # keep source snapshot in store
raku-pm uninstall <module> --recursive # also remove reverse dependencies
raku-pm uninstall <module> --force # ignore reverse dependency checksBehavior:
Without
--version: removes all versions fromsite/, the ledger, and the lockfile; deletes associatedstore/snapshots.With
--version=X:Xis either an exact version (removes only that one) or a semver constraint string โ removing every matching version at once: ranges like<1.0/>=1.0, <2.0, the wildcard*, at-least0.2+, and the npm-style sugar^1.0(compatible) /~1.2(approximately). Snapshots of the removed versions are deleted too (add--keep-storeto keep them for instant reinstalls).Reverse dependency check: by default, refuses if other packages depend on it. Use
--recursiveto remove dependents, or--forceto break dependencies.Exit code (since 0.87.3): returns 0 only when something was actually removed. All four cases below return 1 with the reason on stderr, so scripts can tell (
raku-pm uninstall X && โฆ/set -e): package not installed, requested version doesn't exist, range matched no installed version, refused because of reverse dependencies. Before the fix all four printed "uninstalled X" and returned 0 โ a false success is worse than no message at all.
Sugar upper bounds follow npm semantics (one bound was computed too loosely and fixed in 0.87.2):
^1.2.3โ<2.0.0,^0.2.3โ<0.3.0,^0.0.3โ<0.0.4;~1.2and~1.2.3โ<1.3.0,~1โ<2.0.0. The authoritative list is the sugar matrix int/version.t(both bounds asserted).
Pre-release ordering (0.87.3) follows semver 2.0.0 ยง11:
1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-beta < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0. When in doubt,installed <module>shows the resulting order.
reinstall
Remove and re-install the same version.
raku-pm reinstall <module> [--version=X] [--force] [--dry]If the package was never installed, this behaves like a normal install. Options mirror install.
fetch
Download the source without installing.
raku-pm fetch <module> [--to=dir] [--version=X]Useful for populating a local directory repository: fetch to ./my-dists, then repos add ./my-dists.
test
Run tests only (no install).
raku-pm test [path] # defaults to current directorybuild
Run the build phase only (no install).
raku-pm build [path] # defaults to current directory6.2 Query Commands
All query commands are read-only and modify nothing on disk.
| Command | Syntax | Description |
|---|---|---|
list | raku-pm list | List all installable packages across all repos |
search | raku-pm search <keyword> | Search packages (fuzzy match + relevance ranking) |
installed | raku-pm installed [module] | List installed packages and versions |
store | raku-pm store [module] | View the package source store |
version | raku-pm version [module] | Show raku-pm's version, or a module's installed version |
which | raku-pm which [module] | Without args: cross-repo conflict overview; with module: where it loads from |
info | raku-pm info <package> | Detailed package metadata |
browse | raku-pm browse <package> | Open homepage in browser |
locate | raku-pm locate <module> | Find the on-disk file path of a module |
why | raku-pm why <module> | Dependency resolution diagnostics |
depends | raku-pm depends <module> | Forward dependency tree |
rdepends | raku-pm rdepends <package> | Reverse dependencies (who depends on this) |
outdated | raku-pm outdated | List packages with available upgrades |
lock | raku-pm lock | Display lockfile contents |
verify | raku-pm verify [--content] [--fix] | Verify content integrity + install consistency |
native | raku-pm native <lib> [--paths] | Check if a system native library is present |
verify's content check: native MD5 + a manifest cache (0.86.0). Per-file MD5 used to dominate it (pure-Raku MD5 runs at ~0.16 MB/s โ 296 files take 10.9s; parallelism and multiple processes were both measured and do not help). There are now two levels of speed-up: โ NativeCall calls the systemlibcryptoMD5()directly (pure Raku is the fallback on machines without the library); โก each store entry keeps a.files.jsonmanifest so files whose size and mtime are unchanged reuse last time's MD5. Measured: forced full hashing 11.7s โ 2.9s, ~1.9s when the manifest hits. The trade-off, stated plainly: a modification that also restores the original size and mtime is not detected โ for suspected tampering setRAKUPM_VERIFY_NOCACHE=1(andRAKUPM_MD5=rakuto compare against the pure-Raku implementation). No OpenSSL installation is required: the native path uses the systemlibcrypto(bundled on macOS, present on most Linux distros via the curl/git dependency chain, hit-or-miss on Windows โ where it additionally tries the copy shipped with Git for Windows,libcrypto-3-x64.dll) and silently falls back to pure Raku otherwise โ same digests, just slower.--contentmeans "content check only, skip install-consistency".
Spec string support: search, installed, store, version, and fetch all accept spec strings for version/author filtering:
raku-pm search 'JSON::Fast:ver<1.0+>'
raku-pm installed 'Foo:ver<1.0>'
raku-pm installed 'Foo:auth<zef:x>'
raku-pm store '[email protected]'Matching rules:
search: fuzzy match + relevance ranking (name exact > prefix > substring > module)store/installed: exact match (exact dist name or module name)install: indexed exact module-name lookup
6.3 Repository Management
raku-pm repos # list configured repos
raku-pm repos add <alias|url|path> # add a repository
raku-pm repos add <name> --name=X # add with custom alias
raku-pm repos remove <name|url> # remove a repository
raku-pm repos update [name] # force-refresh index cache(es)
raku-pm update [name] # alias for repos updateBuilt-in aliases: zef, rea, cpan, p6c.
See Section 10 for detailed repository system documentation.
6.4 Version & Release Management
bump
Increment the version in META6.json and prepend a Changes entry.
raku-pm bump # default: --patch (0.1.0 โ 0.1.1)
raku-pm bump --minor # 0.1.0 โ 0.2.0
raku-pm bump --major # 0.1.0 โ 1.0.0
raku-pm bump 2.5.0 # exact version
raku-pm bump --to=2.5.0 # same, explicit
raku-pm bump --date=2026-09-15 # set the heading date
raku-pm bump --dry # preview onlygenerations
List install generations (atomic install snapshots).
raku-pm generationsrollback
Roll back to a previous generation.
raku-pm rollback # go back one generation
raku-pm rollback <generation-id> # go back to a specific generationSee Section 13 for how generations work.
6.5 Maintenance & Cleanup
clean / gc
Reclaim cache and unreferenced store entries.
raku-pm clean # dry run (default)
raku-pm clean --yes # actually delete
raku-pm clean --all --yes # also reclaim index + git caches
raku-pm clean --name=Foo # only Foo-related entries
raku-pm clean --older-than=30 # only entries untouched for 30 daysSafety boundary: Only versions referenced by none of these are deleted:
The
installed.jsonledgerThe live
site/directoryThe lockfile
Generation manifests
clean never deletes any "still installed" version โ including old ones you want gone. Use uninstall --version=X to remove old versions (which also cleans their store snapshots).
flush
Wipe the entire prefix (start over).
raku-pm flush # dry run
raku-pm flush --yes # delete everything raku-pm installed in this prefixUnlike clean, flush has no protection โ it removes everything. After a flush, there is no raku-pm command left; reinstall via zef install . or run from source.
autoremove
Reclaim packages that are no longer needed.
raku-pm autoremove --dry # preview
raku-pm autoremove # remove orphaned dependenciesautoremove loops until convergence: removing a package can orphan its own dependencies, which are then also reclaimed. Packages you explicitly installed are never reclaimed.
6.6 Self Management
self-upgrade
Upgrade raku-pm itself.
raku-pm self-upgrade # upgrade if a newer version exists
raku-pm self-upgrade --force # reinstall even if already up to date
raku-pm self-upgrade --from=<git-url> # pull from a specific remote
raku-pm self-upgrade --dry # preview onlySource priority (two paths):
--from-dir <dir>โ install straight from a local source directory (no clone; also the entry point of the bootstrap's second stage)git remote โ
--from <url>, or the default upstreamhttps://gitee.com/skyter10086/raku-pm.git
After upgrading, old versions are automatically pruned from site/, store/, and the ledger (only the newest version is kept).
self-upgradewithout--forceskips pruning when the version is already current. Use--forceto force a reinstall + prune.
self-remove
Uninstall raku-pm itself.
raku-pm self-remove --dry # preview
raku-pm self-remove # remove raku-pm entirelyDoes more than uninstall RakuPM: also removes store/, bin wrappers, and ledger entries.
6.7 Utility Commands
| Command | Description |
|---|---|
env | Print RAKULIB / PATH setup instructions for the current prefix |
shell | Print an eval-able shell environment export line |
doctor | Run a comprehensive health check (RAKULIB, PATH, residual staging, consistency, version) |
completions <shell> | Generate shell completions for bash, zsh, fish, or pwsh |
preflight | Pre-commit gate check (same as CI) |
smoke [packages...] | Fetch source and run tests; without args, smoke all installed distributions |
6.8 Author / Producer Commands
These commands operate on a distribution directory you are developing.
raku-pm new <module> [--into=dir] [--auth=] [--version=] [--with-readme] [--bin=<x>] [--force] [--dry]
raku-pm refresh [path] [--dry]
raku-pm check [path] [--remote]
raku-pm dist [path] [--to=dir] [--no-build] [--dry]
raku-pm bump [path] [--to=X.Y.Z|--major|--minor|--date] [--dry]
raku-pm publish [path] [--remote] [--from=tar.gz] [--to=repo-dir] [--no-build] [--force] [--quiet] [--dry]
raku-pm login [--username=] [--password=] [--api-key=] [--quiet]
raku-pm logoutSee Section 17 for the full authoring workflow.
6.9 Command Aliases
Short forms for convenience:
| Alias | Full Command | Alias | Full Command |
|---|---|---|---|
i | install | un / rm | uninstall |
up | upgrade | upd | update |
ri | reinstall | ls | list |
li | installed | inf | info |
dep | depends | rdep / rdeps | rdepends |
s | search | t | test |
b | build | f | fetch |
doc | doctor | out | outdated |
gen / gens | generations | rb | rollback |
ar | autoremove | nat | native |
vfy | verify | st | store |
w | which | e | env |
sh | shell | loc | locate |
br | browse | wh | why |
su | self-upgrade | sr | self-remove |
repo | repos | lk | lock |
sm | smoke |
7. The Install Pipeline
Every install follows this seven-phase pipeline:
resolve โ fetch โ build โ store โ test โ install (activate) โ lock| Phase | What happens | Can skip with |
|---|---|---|
| resolve | Look up which distributions provide the target module; pick the highest matching version; expand dependencies recursively; topological sort into bottom-up order | โ |
| fetch | Download the tarball (ecosystem) or point at a directory (local/git); unpack into cache/dist/ | โ |
| build | If Build.pm or META6 builder exists, run it in a subprocess | --no-build |
| store | Admit sources into the content-addressed store with MD5 digest | โ |
| test | Run t/*.t and t/*.rakutest against the source directory | --no-test |
| activate | Hand the distribution to CompUnit::Repository::Installation to write into site/; update the ledger | โ |
| lock | Write exact versions + digests into the lockfile | โ |
What is atomic: phases 3โ7 (store through lock) are wrapped in a single transaction. If any package fails, the target is restored to its pre-run state. Only when everything succeeds is a generation recorded.
Git installs follow the same pipeline. The target package's sources come from the clone directory instead of a repository, but all other phases are identical.
Local directory installs (install .) also follow the same pipeline. The directory is appended to the end of the dependency chain.
8. Dependency Resolution
The resolver (RakuPM::Resolver) is the heart of the package manager. It performs:
Recursive DFS over the dependency graph starting from the target module.
Per-version provides checking โ handles the "provides drift" problem where a module moves between distributions across versions (e.g.,
NativeLibsinDBIishbefore 0.6.2, standalone after).Conflict detection โ when the same module is required with incompatible constraints, the error message shows the full chain of requesters.
Cycle detection โ mutual dependencies are noted and warned about, but not fatal. The topological sort places unresolvable cycles at the end.
Topological sort (Kahn's algorithm) โ dependencies are installed before their dependents.
Ranking candidates
When multiple distributions provide the same module:
A distribution whose name matches the module name wins (e.g.,
NativeLibsmodule โNativeLibsdistribution).Then higher version (real semver, not string comparison).
Then name, lexicographically (for stable, reproducible results).
Constraint syntax
| Spelling | Meaning |
|---|---|
Foo:ver<1.2.3> | Exactly 1.2.3 |
[email protected] | @ shorthand, same as above |
Foo --version=1.2.3 | The flag form |
Foo:ver<1.2+> | At least 1.2 (zef's + suffix) |
Foo:ver<>=1.0> | Greater than or equal to 1.0 |
Foo:ver<>1.0> | Greater than 1.0 |
Foo:ver<<=1.0> | Less than or equal to 1.0 |
Foo:ver<<1.0> | Less than 1.0 |
Foo:ver<>=1.0, <2.0> | Range: 1.0 โค x < 2.0 |
Foo:ver<*> / Foo:ver<> | Any version |
Foo:ver<1.2.3>:auth<zef:x> | Version + author filter |
:auth<>actually filters โ it is not parsed and ignored. A mismatched auth is a hard error.
Diagnostic: why
raku-pm why <module>Outputs which distributions were considered, why they were rejected, and what constraint led to the final choice. Uses Resolver.explain-all() for non-fatal diagnostics.
9. Version Management
Multiple versions
raku-pm installs into CompUnit::Repository::Installation, which natively supports multiple coexisting versions. Installing version 2.0.0 does not remove version 1.0.0.
$ raku-pm installed Foo
ยท Foo 1.0.0
* Foo 2.0.0 โ use Foo picks this (highest)The * marker indicates the "active" version โ what use Foo loads.
Pinning
raku-pm install Foo --version=1.0.0 # install a specific version
raku-pm install Foo [email protected] # pin a dependency versionDowngrading
Raku's use Foo always picks the highest version. Installing an older version adds it alongside but does not make it active. To actually switch:
raku-pm upgrade Foo --version=1.0.0 --only # remove higher versions
# or use version constraint in code: use Foo:ver<1.0.0>Lockfile
raku-pm lock # display lockfile contents
raku-pm install Foo --locked # strict mode: abort if lock disagreesThe lockfile is written to $CWD/raku-pm.lock by default (Cargo.lock style), so it can be committed for reproducible installs.
10. Repository System
How repositories work
raku-pm queries an ordered list of repositories for package metadata. When resolving a dependency, it asks every repository and merges the results by the ranking rules in Section 8.
Repository types
| Type | Backend | Description |
|---|---|---|
| Ecosystem | Repository::Ecosystem | Remote JSON index (zef, REA, CPAN, p6c) |
| Local | Repository::Local | Local directory containing distribution subdirectories |
Built-in repository aliases
| Alias | Index URL | Records | Notes |
|---|---|---|---|
zef | https://360.zef.pm | ~8k | Current versions |
rea | โฆ/Raku/REA/main/META.json | ~15k | Archive, includes old versions |
cpan | โฆ/ugexe/Perl6-ecosystems/master/cpan1.json | ~2k | Perl6 modules on CPAN |
p6c | โฆ/ugexe/Perl6-ecosystems/master/p6c1.json | โ | Legacy archive |
922 distributions exist only in REA and not in zef โ a single index cannot install everything.
Configuration precedence (high โ low)
$RAKUPM_TARGET/repositories.jsonโ maintained byrepos add/removeRAKUPM_ECOSYSTEMenv var โ comma/semicolon separated, each entry an URL or aliasDefault: the
zefindex + the local$RAKUPM_REPOdirectory
Adding local directory repos
A local directory repo holds one subdirectory per distribution, each with META6.json + lib/:
raku-pm repos add ~/my-dists # add local directory
raku-pm fetch HTTP::Client --to=~/my-dists # populate itResilient index fetching
If a repository index cannot be fetched:
| Situation | Behavior |
|---|---|
| Fetch failed, old cache exists | Reuse cache, warn "may be stale" |
| Fetch failed, never cached | Treat as empty index, warn "results may be incomplete" |
A warning never silently hides a missing module โ it says the module may exist but is currently unreachable.
Index caching
Indexes are cached locally with conditional GET (ETag / If-None-Match). The TTL is controlled by RAKUPM_INDEX_TTL. Once expired, raku-pm asks the server once (and very likely gets a 304 Not Modified).
11. Lockfile & Reproducibility
The lockfile (raku-pm.lock) records exact versions and content digests:
{
"version": 1,
"entries": [
{ "name": "JSON", "version": "2.0.0", "auth": "demo:raku",
"digest": "d47078e2...", "depends": [] }
]
}Committable lockfile workflow
cd my-project
raku-pm install JSON # pins exact versions into ./raku-pm.lock
git add -f raku-pm.lock # commit it (-f bypasses .gitignore)
# teammate, after cloning:
raku-pm install --locked # strictly reuses locked versions--lock-file=<path>relocates the lockfile (useful in CI).install/reinstall/self-upgrade/lockall accept--lock-file.The lockfile is independent of
--target: even with a separate prefix, the lock stays in the project root.
12. Native Library Detection
raku-pm does not ship system libraries. Before installing, it checks whether the required native libraries are present on the system.
What is checked
:from<native>dependencies in META6.jsonRuntime
is native('...')calls scanned fromlib/andbin/source files:from<bin>and:from<Perl5>external dependencies (reported but never block install)
Per-OS file name mapping
| Logical name | Windows | macOS | Linux |
|---|---|---|---|
sqlite3 | sqlite3.dll | libsqlite3.dylib | libsqlite3.so |
ssl | libssl-3-x64.dll | libssl.dylib | libssl.so |
libffi | libffi-8.dll | libffi.dylib | libffi.so |
zlib | zlib1.dll | libz.dylib | libz.so |
unknown foo | foo.dll | libfoo.dylib | libfoo.so |
Per-OS search paths
| OS | Search paths |
|---|---|
| Windows | PATH โ System32/SysWOW64 โ vcpkg installed/*/bin |
| macOS | DYLD_LIBRARY_PATH โ /opt/homebrew/lib (Apple Silicon) โ /usr/local/lib (Intel) โ /opt/local/lib (MacPorts) โ /usr/lib |
| Linux | LD_LIBRARY_PATH โ /usr/local/lib, /usr/lib โ Debian multiarch dirs โ versioned .so.N |
Per-distro install commands
When a library is missing, raku-pm suggests the install command for your Linux distribution:
| Distro family | Package manager | Example |
|---|---|---|
| Debian/Ubuntu | apt | apt install libsqlite3-dev |
| Fedora/RHEL | dnf | dnf install sqlite-devel |
| Arch | pacman | pacman -S sqlite |
| Alpine | apk | apk add sqlite-dev |
| openSUSE | zypper | zypper install libsqlite3-devel |
Querying native libraries
raku-pm native sqlite3 # check if present
raku-pm native ssl curl --paths # multiple at once, show search paths
raku-pm native --installed # scan lockfile for declared libs
raku-pm native sqlite3 --os=linux --distro=ubuntu # simulate another platformPlatform-conditional dependencies
META6.json can use by-distro.name to declare platform-specific dependencies:
{
"depends": [{
"name": {
"by-distro.name": {
"": "",
"mswin32": "Win32::Registry"
}
}
}]
}Only the branch matching $*DISTRO.name (or the "" fallback) is resolved. On Linux, Win32::Registry is not fetched.
13. Atomic Install & Generations
How atomic install works
All packages are staged into a shared temporary CUR (
target/stage/pending).Tests run against the staging CUR.
If everything passes, packages are promoted to the real
site/+ ledger + bin wrappers.If anything fails, the staging area is discarded โ the real CUR is never touched.
raku-pm install A # A depends on B โ order [B, A]
B installed into staging CUR โ
A's tests fail โ
โ rollback: staging discarded; B removed; target is back to its prior stateGenerations
After a successful atomic install, a generation is recorded in target/generations/:
target/generations/
โโโ current current generation id
โโโ 000001/
โ โโโ before.json ledger snapshot before the transaction
โ โโโ manifest.json ledger after commit
โ โโโ meta.json timestamp, what was installed
โโโ 000002/...The 10 most recent generations are kept. Generations are cheap โ they are a few KB of JSON, not a copy of the entire site/.
Rolling back
raku-pm generations # list available generations
raku-pm rollback # go back one generation
raku-pm rollback 000003 # go back to a specific generationRollback removes the versions installed by the targeted generation from the CUR and restores the ledger. Older versions that were never removed remain intact.
Limitation: Rolling back to a generation whose sources have been removed from the store by
cleanwarns and skips. Don't gc aggressively if you might need to roll back.
14. Caching & Cleanup
What gets cached
| Category | Location | Size impact |
|---|---|---|
| Store snapshots | store/<dist>/<version>/ | Grows over time (every upgrade leaves a snapshot) |
| Download cache | cache/dist/ | Tarballs + unpacked trees |
| Index cache | cache/index-*.json | ~10 MB per index |
| Git clone cache | git-cache/ | Per-repo clones |
| Precompiled artifacts | .precomp inside store entries | Rebuilt on demand |
| Test logs | log/<dist>/<version>/ | Per-test-file output |
Cleanup with clean
clean is protective GC โ it only deletes versions that are not referenced by any of: the ledger, site/, the lockfile, or generation manifests.
raku-pm clean # dry run: see what would be reclaimed
raku-pm clean --yes # actually delete
raku-pm clean --all --yes # also reclaim index + git caches
raku-pm clean --name=Foo # only Foo-related entries
raku-pm clean --older-than=30 # only entries untouched for 30 daysNuclear option: flush
flush wipes everything raku-pm installed in the current prefix with no protection. Use only when starting over from scratch.
Reclaiming orphaned dependencies
raku-pm autoremove # remove packages no longer depended on
raku-pm autoremove --dry # previewLoops until convergence: removing a package can orphan its own dependencies.
15. Concurrency & File Locking
Multiple raku-pm processes running simultaneously can corrupt the store and lockfile. To prevent this, every write command acquires a cross-process file lock:
$ raku-pm install Foo # while another terminal installs something else
โณ Another raku-pm is writing to /home/user/.raku-pm, waiting...Lock details
| Aspect | Behavior |
|---|---|
| Mechanism | flock (OS-reclaims on process death; no stale locks) |
| Lock file | target/.raku-pm.run.lock (holds no state) |
| Timeout | 600s default (RAKUPM_LOCK_TIMEOUT) |
| Re-entrant | Reference-counted within one process; nested calls don't self-deadlock |
| Child-process token | Random token passed to child processes; they skip the lock |
| Escape hatch | --no-lock or RAKUPM_NO_LOCK=1 (dangerous; use only when sure nothing else is running) |
Tests run serially during install
As of 0.80.0, tests run serially (each test file in its own subprocess โ process-
isolated, but not sandboxed). Tests used to run concurrently by default, but keeping
concurrency from harming installs required two extra safety nets (a serial precomp warm-up
plus a serial re-verify of failed cases) โ complexity that does not pay off for a
single-machine teaching tool, so the whole concurrency mechanism has been removed (and the
--test-jobs flag with it).
| Phase | Concurrent? |
|---|---|
| Resolve / download / build / store / stage / promote to site | Serial (one distribution at a time, bottom-up) |
| Running test files | Serial (file by file, process-isolated) |
Cross-process (two raku-pm runs at once) | Serial โ via the file lock above |
The only automatic retry: serial re-verify of failures
A case that failed the first run is re-run serially once, and only counts as a real
failure if it fails again. This is the one concession to flaky upstream tests โ e.g.
Concurrent::Stack 1.3's stress case fails 3 runs out of 10 (an upstream race). That is an
upstream bug, but a user should not be unable to install a package over a probabilistic
failure. The re-verify log is written to <name>.flake.log and does not overwrite the
first-run failure log.
Residual risks (stated honestly)
| Risk | What it means |
|---|---|
| Re-verify also fails โ judged a real failure โ whole chain rolls back | Dependencies already built in this run are discarded too (store versions remain) |
| The upstream test is itself flaky | e.g. Concurrent::Stack 1.3's stress case; fails serially too โ the re-verify absorbs one attempt |
| A single test file is slow | Serial means slow cases add up wall-clock time, possibly hitting --test-timeout (300s default) |
Knobs
raku-pm install Foo --test-timeout=900 # relax the per-file timeout
raku-pm install Foo --allow-test-failure # install even if tests fail (soft pass)
raku-pm install Foo --no-test # skip tests entirelyEnv vars: RAKUPM_TEST_TIMEOUT.
Two further soft-pass paths: explicit
--allow-test-failure, and failures recognised as a known Windows upstream bug (a deliberately narrow match: specific dist + specific test file + failure signature) โ the latter does not hide real bugs.
16. HTTP Layer
All network traffic goes through the RakuPM::HTTP facade, which delegates to the single backend:
| Backend | Under the hood | Notes |
|---|---|---|
RakuPM::HTTP::Tinyish | HTTP::Tinyish (system curl) | the only backend; best TLS/proxy support |
As of 0.82.0 there is a single backend: the pure-Raku
HTTP::Tinyfallback and theRAKUPM_HTTP_BACKEND/register-backendpluggable machinery have been removed.
Features
Retry with exponential backoff + jitter on transient failures
Proxy support via
HTTPS_PROXY/HTTP_PROXYenvironment variablesConditional GET with
ETag/If-None-Match(304 reuses cache)Debug observability via
RAKUPM_HTTP_DEBUGMultipart upload for ecosystem publishing
17. Authoring & Publishing
The producer-side workflow follows this sequence:
new โ refresh โ check โ dist โ publish1. Scaffold a new distribution
raku-pm new Foo::Bar # create Foo-Bar/
raku-pm new Foo::Bar --into=MyProj # custom directory name
raku-pm new Foo::Bar --with-readme --bin=foo --auth=github:me --version=0.2.0
raku-pm new Foo::Bar --dry # preview onlyCreates: META6.json, lib/Foo/Bar.rakumod, t/01-basic.rakutest, Changes, .gitignore, optionally README.md and bin/<x>.raku.
2. Rebuild provides from disk
raku-pm refresh # rebuild provides for the current directory
raku-pm refresh ./some-dist # target a specific directory
raku-pm refresh --dry # preview onlyAfter adding/renaming modules under lib/, the provides in META6.json may no longer match. refresh scans lib/ and rebuilds provides automatically. It only touches provides โ everything else is preserved verbatim.
3. Pre-flight check
raku-pm check # local-only, instant, offline
raku-pm check ./some-dist # target a specific directory
raku-pm check --remote # also check if the version is already published onlineChecks: META6.json valid, name present, version โ *, auth matches RAKUPM_AUTHOR_AUTH, provides matches disk, bin scripts exist, dependencies parseable.
Any hard error ([โ]) exits non-zero, so this drops directly into a CI publish gate.
4. Package the sdist
raku-pm dist # package current directory
raku-pm dist ./some-dist # target a specific directory
raku-pm dist --no-build # skip the build phase
raku-pm dist --to=../out # place the tarball under ../out
raku-pm dist --dry # preview onlyRuns the check gate first (any hard error is rejected). If a Build.pm exists, it is executed inline (native extension compilations land in the tarball). The output is a source distribution tarball (no precompiled bytecode).
5. Deploy
Local directory repo:
raku-pm publish --to=../my-dists # deploy to local repo
raku-pm publish --from=../out/Foo-1.0.0.tar.gz --to=../my-dists # reuse existing package
raku-pm publish --dry # preview onlyRemote ecosystem:
raku-pm login --api-key=<key> # store the API key
raku-pm login --username=me --password=secret # online login to 42.zef.pm
raku-pm publish --remote --dry # preview the upload request
raku-pm publish --remote # actually uploadAfter publishing, another machine can raku-pm repos add <repo> and raku-pm install <name>.
18. Troubleshooting
Module not found
ๅจๆๆๅทฒ้
็ฝฎ็ไปๅบ้้ฝๆพไธๅฐๆจกๅ 'Foo'Possible causes:
The module isn't in the default
zefindex. Tryraku-pm repos add reafor broader coverage.A repository index couldn't be fetched. Check for
โwarning lines above the error.Typo in the module name. Try
raku-pm search <partial-name>.
"Another raku-pm is writing" timeout
A previous raku-pm process may be hanging. The lock is auto-released when the process exits (or is killed). If the lock file is stale:
rm $RAKUPM_TARGET/.raku-pm.run.lockOr wait up to 600s for the lock to time out.
Native library not found
โ sqlite3 ๆชๆพๅฐ โ ๆฌ็ณป็ป้่ฆ libsqlite3.so / libsqlite3.so.0
ๅฎ่ฃ
๏ผapt install libsqlite3-devInstall the system library using the suggested command, or use --no-native-check to skip the check (the library will still fail to load at runtime).
RAKULIB shadowing
If RAKULIB is exported globally (from your shell profile), plain raku will load raku-pm's own copy of RakuPM from site/. If that copy is old, tests may appear to fail on the current code.
Safe habits:
Run tests via
raku tools/run-suite.raku(it passes-I<worktree>/liband self-checks).Run a single file as
raku -Ilib t/<x>.t(-Icomes beforeRAKULIB).Check which copy loads:
raku-pm which RakuPM::Version
use Foo:ver<1.2.3> loads the wrong version
The inst# prefix is mandatory in RAKULIB. Without it, Rakudo treats site/ as an ordinary filesystem repository and ignores version metadata:
export RAKULIB="inst#$HOME/.raku-pm/site" # correct
# NOT: export RAKULIB="$HOME/.raku-pm/site" # wrongraku-pm --help may be swallowed under PowerShell
Bottom line first: --help works with the wrapper raku-pm generates itself โ
measured, raku-pm --help and raku-pm -h both print help and exit 0 (the local
wrapper is site/bin/raku-pm.ps1, which forwards @args verbatim to the entry).
Only a legacy zef wrapper (raku-pm.exe, whose *% named-parameter signature
claims --help for itself) swallows it โ that .exe is renamed to <name>.zef-old
at install/upgrade time, see the next section.
Prefer raku-pm help: it works under every wrapper flavour and supports the
levels (raku-pm help <command> / raku-pm help <group> / raku-pm help all).
raku-pm version shows the old version after upgrade
The zef-era raku-pm.exe (.EXE outranks .BAT in PATHEXT) may shadow the new wrapper. The entry check at install/upgrade renames it to <name>.zef-old. If the issue persists, run raku-pm env to see which entry point actually executes.
Debug mode
RAKUPM_DEBUG=1 raku-pm <command> # full backtrace on failure
RAKUPM_HTTP_DEBUG=1 raku-pm <command> # HTTP request/response details19. Environment Variables Reference
| Variable | Purpose | Default |
|---|---|---|
RAKUPM_TARGET | Install prefix (store/site/lockfile) | ~/.raku-pm |
RAKUPM_REPO | Local repository root | . (cwd) |
RAKUPM_ECOSYSTEM | Ecosystem index URL(s), comma/semicolon-separated | (none; when unset, built-in default is zef+cpan+rea+local; setting it overrides the built-in indexes) |
RAKULIB | Module search path | (none) |
RAKUPM_OFFLINE | Offline mode (1/true/yes/on) | (off) |
RAKUPM_NO_COLOR | Disable color output | (off) |
NO_COLOR | Disable color (industry standard) | (off) |
RAKUPM_HTTP_DEBUG | HTTP debug logging | (off) |
RAKUPM_INDEX_TTL | Index cache TTL | (configurable) |
RAKUPM_LOCK_TIMEOUT | Cross-process lock timeout (seconds) | 600 |
RAKUPM_NO_LOCK | Skip write lock (1) | (off) |
RAKUPM_LOCK_TOKEN | Internal: child-process lock token | (auto) |
RAKUPM_TEST_TIMEOUT | Per-test timeout (seconds) | 300 |
RAKUPM_TEST_LOG_DIR | Test log root directory | <target> |
RAKUPM_TEST_PROGRESS | Test progress display (0=off, 1=on) | auto (TTY detection) |
RAKUPM_PUBLISH_REPO | Default publish target directory | (none) |
RAKUPM_API_KEY | Ecosystem upload API key | (none) |
RAKUPM_AUTHOR_AUTH | Author identity for publishing | zef:skyter10086 |
RAKUPM_CURL | Override curl binary path | system curl |
RAKUPM_DEBUG | Full backtrace on failure | (off) |
RAKUPM_CI_XT | CI: set to 0 to skip extended tests | (on) |
HTTPS_PROXY / HTTP_PROXY | Proxy settings for HTTP requests | (none) |
DYLD_LIBRARY_PATH | macOS library search path | (none) |
LD_LIBRARY_PATH | Linux library search path | (none) |
20. Config Files Reference
repositories.json
Located at $RAKUPM_TARGET/repositories.json. Maintained by repos add/remove. Structure:
[
{ "name": "zef", "url": "https://360.zef.pm", "type": "ecosystem" },
{ "name": "local", "url": "/path/to/local-repo", "type": "local" }
]installed.json
Located at $RAKUPM_TARGET/installed.json. The ledger of all installed packages. Each entry includes identity, provides, digest, source directory, and install reason.
raku-pm.lock
Located at $CWD/raku-pm.lock (default). Records exact versions and content digests for reproducible installs. Committable to version control.
credentials.json
Located at $RAKUPM_TARGET/credentials.json. Stores API keys for ecosystem upload. Created by raku-pm login.
META6.json
The distribution manifest. Key fields:
{
"name": "My-Dist",
"version": "1.0.0",
"auth": "github:me",
"api": "1",
"description": "A brief description",
"license": "Artistic-2.0",
"provides": { "My::Dist": "lib/My/Dist.rakumod" },
"depends": [ "JSON::Fast" ],
"test-depends": [ "Test" ],
"build-depends": [],
"bin": { "my-tool": "bin/my-tool.raku" },
"source-url": "https://github.com/me/my-dist"
}21. Contributing
Running tests
# Full test suite (same code path as CI):
raku tools/run-suite.raku
# Without extended tests (no network/heavy tests):
raku tools/run-suite.raku --no-xt
# Docs-only check:
raku tools/run-suite.raku --docs-only
# Filter by name:
raku tools/run-suite.raku --filter=native
# Do not print per-test timings / slowest list (for clean CI logs):
raku tools/run-suite.raku --no-timings
# Single test file:
raku -Ilib t/version.tDo NOT use
prove6for test verdicts โ it false-flags harmless warnings. The only reliable signal israku tools/run-suite.raku.
To find out "why the gate is slow", run the full suite and read the timing summary at the end: by default the script prints each test's wall clock, the 15 slowest, the actual
t/xt/wall clock, the parallel speedup, and theraku -e ''startup baseline with its share of the total. Read it from both ends: a high startup share means the bottleneck is process count (merging test files helps); a low share means the bottleneck is the heavy tests themselves and how they are scheduled โ look at the top of the slowest list. Measured on this machine (8 jobs, 135 tests): the 0.22s startup baseline is just 2% of the total while the average test takes 14.2s, so this project falls in the latter case. Also, a speedup well below the--jobsvalue usually means "long tests sitting at the tail of a batch while only one or two still run", not that parallelism failed.
How the suite is scheduled:
t/andxt/sit in a single pool and are dispatched by descending historical wall clock (LPT) โ the longest test starts first and short tests fill the gaps it leaves; the pool is then split across lanes that run independently (there is no "wait for the whole layer" barrier โ whoever runs dry first picks up the next test). As a result tests appear interleaved in the log (a per-directory summary is printed at the end). The old "per-directory batches by filename" scheme let long tests land at the tail of a batch while only one or two were still running: measured 2.83x with 8 jobs. Timings are cached at~/.raku-pm/suite-timings.jsonand only affect dispatch order.
Pre-commit hook
raku tools/install-hooks.raku # install the git pre-commit hookThe hook runs tools/run-suite.raku --no-xt (same gate as CI).
CI pipeline
The Gitee Go pipeline (.workflow/master-pipeline.yml) triggers on push to master, runs on a self-hosted agent, and executes raku tools/run-suite.raku.
Code structure
bin/raku-pm.raku CLI entry point (argument parsing, command dispatch)
lib/RakuPM/Client.rakumod Orchestrator (coordinates all other modules)
lib/RakuPM/Resolver.rakumod Dependency resolver
lib/RakuPM/Installer.rakumod Store โ CUR activation
lib/RakuPM/Repository/ Pluggable repository backends
lib/RakuPM/HTTP/ Dual-backend HTTP layer
lib/RakuPM/UI.rakumod Terminal display (colors, tables, CJK alignment)
lib/RakuPM/Version.rakumod Semver parsing and comparison
lib/RakuPM/Spec.rakumod Install spec string parser
lib/RakuPM/Author.rakumod Producer-side commandsArchitecture overview
bin/raku-pm.raku (CLI)
โ RakuPM::Client (Orchestrator)
โ RakuPM::Resolver (Dependency Resolution)
โ RakuPM::Repository (role, pluggable backends)
โ Repository::Local
โ Repository::Ecosystem
โ RakuPM::Store (Content-Addressed Storage)
โ RakuPM::Installer (Activation into CUR::Installation)
โ RakuPM::Builder (Build Phase)
โ RakuPM::Lock (Lockfile)See architecture.en.md for the full deep dive.
22. FAQ
Q: How is raku-pm different from zef?
raku-pm is modelled on zef's architecture but implemented from scratch as a teaching tool. Key differences: raku-pm is ~3,700 lines (zef is much larger), has atomic installs with generation rollback, includes a native library detector with per-OS probing, and implements the full authoring workflow. zef is the production-grade package manager; raku-pm is designed to teach how one works.
Q: Can raku-pm and zef coexist?
Yes. They install into separate locations (~/.raku for zef vs $RAKUPM_TARGET/site for raku-pm). Raku's multi-version design means two versions of the same module can live side by side.
Q: What happens if I install a package that zef already installed?
They coexist. If both install the same version, use picks the one on RAKULIB first (raku-pm's site). raku-pm which shows which copy actually loads.
Q: Why are there two copies in store/ and site/?
store/ is a download cache (one download, many deployments; reinstalling never re-downloads). site/ is the runtime (what use resolves from). This mirrors Cargo's registry/cache + src design.
Q: Can I use a spec string with query commands?
Yes. search, installed, store, version, and fetch all accept spec strings like Foo:ver<1.2+> or [email protected] for version/author filtering.
Q: What does --only do on upgrade?
It removes all versions higher than the target after upgrading. This is how you make a downgrade actually take effect (Raku's use always picks the highest version).
Q: How do I contribute?
See Section 21: Contributing. The project uses Gitee for hosting; contributions follow standard fork โ branch โ PR workflow. All PRs must pass raku tools/run-suite.raku.
A. Appendix: Exit Codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Business failure (test failed, native lib missing, usage error, etc.) |
Business failures print a clean user-facing message and exit 1 without printing internal stack traces. Set RAKUPM_DEBUG=1 to see full backtraces.
B. Appendix: Spec String Syntax
Spec strings are the zef-compatible way to specify a module with version and/or author constraints. They are accepted by install, search, installed, store, version, and fetch.
Supported forms
| Form | Example | Meaning |
|---|---|---|
| Module only | Foo | Any version |
With :ver<> | Foo:ver<1.2.3> | Exactly 1.2.3 |
With :ver<> + + | Foo:ver<1.2+> | At least 1.2 |
With @ shorthand | [email protected] | Exactly 1.2.3 |
With :auth<> | Foo:auth<zef:x> | Specific author |
| Combined | Foo:ver<1.2.3>:auth<zef:x>:api<1> | Version + author + API |
Shell quoting
The <> in :ver<> is a shell redirection operator. Quote the entire string:
bash/zsh:
search 'Foo:ver<1.2+>'Windows cmd: Use the
@shorthand instead:search [email protected]+PowerShell: Same as bash โ quote the string
Fallback
If the ver part is not a valid constraint (e.g., search Foo@bar), the whole input falls back to a plain keyword search.
C. Appendix: Platform Behavior Matrix
| Feature | Windows | macOS | Linux |
|---|---|---|---|
| Native lib suffix | .dll | .dylib | .so |
| Native lib prefix | (none) | lib | lib |
| Shell wrapper | .bat + .ps1 | bash | bash |
| Default search paths | PATH, System32, vcpkg | DYLD_LIBRARY_PATH, Homebrew, MacPorts | LD_LIBRARY_PATH, multiarch dirs |
sort -V support | N/A (uses bash) | No (fallback to lexicographic) | Yes |
site/bin promotion | .exe โ .bat rename check | Direct copy | Direct copy |
| File locking | LockFileEx (mandatory) | flock | flock |
PATHEXT | .EXE outranks .BAT | N/A | N/A |
This manual covers raku-pm version 0.77.0. For the latest changes, see Changes. For questions and issues: https://gitee.com/skyter10086/raku-pm/issues