Alien-Xrepo
view release on metacpan or search on metacpan
Default package kind (`shared` or `static`) for every action this instance performs. A per-call `kind => ...` wins. If left unset (the default), `-k` is omitted entirely so installs behave exactly like a bare `xrepo install`. Useful when you know...
- **cache**
Boolean, default on. `install` memorizes each successful fetch result on disk (see ["`install( ... )`"](#install) below) so a repeated launch resolves the package with zero `xrepo` spawns. Entries are LRU-bounded and validated against the recorde...
## `install( ... )`
```perl
my $pkg_info = $repo->install( $package_name, $version_constraint, %options );
```
Installs (if missing) and fetches the metadata for a package.
Resolution is staged so repeated calls avoid the `xmake` process startup cost entirely:
- 1. A warm cache hit replays the memorized fetch result without invoking `xrepo`. The entry is only trusted while its recorded install directory still exists on disk, and stale entries automatically prune themselves. (See the **cache** constructor o...
- 2. Otherwise, `fetch --json` is tried first: an already-installed package answers with real paths immediately and the mutating `xrepo install` is skipped. That single fetch is also memorized for next time.
- 3. Only when a package truly is missing does `xrepo install` run, followed by a mandatory fetch to learn where its output landed.
- `$package_name`
The name of the package (e.g., `zlib`, `opencv`).
- **$version\_constraint**
Optional semantic version string (`1.2.x`, `latest`). Pass `undef` or an empty string for the default.
- `%options`
Optional configuration options passed to `xrepo` (shared by most other methods; missing options are filled in automatically):
- `plat`
Target platform (e.g., `windows`, `linux`, `macosx`, `android`, `iphoneos`, `wasm`).
- `arch`
Target architecture (e.g., `x86_64`, `arm64`, `riscv64`).
- `mode`
Build mode: `debug` or `release`.
- `kind`
Library kind: `shared` or `static`. If omitted entirely, the package's own default applies, so a bare install behaves exactly like `xrepo install`.
_Note: For FFI, you almost always want `shared`, but `static` is available if you are linking archives with, say, an XS module._
- `toolchain`
Specify a toolchain (e.g., `llvm`, `zig`, `mingw`).
- `toolchain_host`
Specify the host toolchain for cross-compilation.
- `vs`, `vs_toolset`, `vs_sdkver`
Visual Studio toolset/SDK selection (e.g., `--vs=2017`, `--vs_toolset=14.0`).
- `ndk`
The Android NDK directory.
- `sdk`
The SDK directory of a cross-toolchain.
- `mingw`
The MinGW SDK directory.
- `jobs`, **linkjobs**
Parallel compilation/link job counts.
- `force`
_install/download_: force reinstall/redownload all packages. _remove_: force removal even when still depended on.
- `shallow`
Do not install/download dependent packages.
- `build`
Always build and install from source.
- `debugdir`
Source directory used for debugging; enables `force` and `shallow` by default.
- `configs( ... )`
A hashref or string of package-specific configurations.
```perl
configs => { openssl => 'true', shared => 'true' }
# becomes --configs='openssl=true,shared=true'
```
Perl's built-in boolean scalars (`use feature 'true'/'false'`, enabled by `use v5.36+`) are normalized to the literal strings `'true'` / `'false'`, so `configs => { shared => true }` produces `--configs='shared=true'`.
- `includes`
A list or string of extra `rc` files to include in the environment.
Each include is forwarded to `xmake` verbatim, so it must be a valid root-scope `xmake` configuration (e.g., `add_toolchains`); `xmake` textually prepends `rc` contents to the temporary project script. A vendored `package() {...}` recipe is N...
- `installdir`, **cachedir**
Root directories for the installed packages and the download/build cache, applied per-call via the `XMAKE_PKG_INSTALLDIR` / `XMAKE_PKG_CACHEDIR` environment variables. This lets each wrapper keep its libraries in a project-local directory ins...
- `theme`
Per-call `xmake` output theme override. Defaults to the `theme` constructor value (`plain`). See ["new( ... )"](#new).
- `yes`, `confirm`
Returns an [Alien::Xrepo::PackageInfo](https://metacpan.org/pod/Alien%3A%3AXrepo%3A%3APackageInfo) object.
## `fetch( ..., [ ... ] )`
```perl
my $pkg_info = $repo->fetch( 'libpng' );
my $cflags = $repo->fetch( 'zlib', undef, cflags => 1 );
```
Fetches metadata for an already-installed package without installing it again. Returns an [Alien::Xrepo::PackageInfo](https://metacpan.org/pod/Alien%3A%3AXrepo%3A%3APackageInfo) object, or a raw flag string when `cflags` or `ldflags` is requested.
- `cflags`
Fetch `-I...` include flags as a string.
- `ldflags`
Fetch `-L.../-l...` link flags as a string.
- `deps`
Fetch packages together with their dependencies.
- `system`
Only fetch the package on the current system.
- `external`
Show `cflags` as external packages (with `-isystem`).
- `installdir`, `cachedir`
Target the same isolated store used by `install( ... )` (see there).
## `info( ... )`
```perl
my $json = $repo->info( 'zlib', format => 'json' );
my $text = $repo->info( 'libpng' );
my $dot = $repo->info( 'libpng', depgraph => 1, format => 'dot' ); # dependency graph (Graphviz)
```
Shows package information. Pass `format => 'json'` to receive the decoded data structure (array of hashes), `format => 'dot'` for a Graphviz DOT dependency graph, or `depgraph => 1` to include the package dependency tree. A DOT graph can be rendered ...
## `scan( [ ... ] )`
```perl
my @installed = $repo->scan( 'libpng' );
my @all = $repo->scan();
```
Lists installed packages (optionally filtered by a Lua pattern). Returns the output lines as a list.
## `download( ... )`
```perl
$repo->download( 'zlib', undef, outputdir => './dl', shallow => 1 ); # Downloads the latest version
```
Only downloads the package source archives without building them. `outputdir` selects the destination directory (default `packages`). Supports `force`, `shallow`, and the standard `%options`.
## `import_pkg( ... )`
```perl
$repo->import_pkg( 'zlib', undef, packagedir => './packages' ); # Latest zlib version
$repo->import_pkg( 'libfake', '1.0.x' ); # A particular version of this fake lib
```
Imports pre-downloaded package archives into the local cache. `packagedir` selects the source directory.
## `export( ... )`
```perl
$repo->export( 'zlib', undef, packagedir => './packages', shallow => 1 ); # Export the latest version
```
Exports installed package files for offline use. `packagedir` selects the destination directory.
## `env( [ ..., [ ... ] ] )`
```perl
$repo->env( 'bash', bind => 'zlib' ); # run a program inside the package env
$repo->env( undef, show => 1 ); # only print the environment
```
Sets up the package environment and either prints it (`show`) or executes `$program` (default `shell`) inside it. `bind` selects which environment config or package to bind, `list` lists global configs, and `add`/`remove` manage global environment co...
## `list_repo()`
```perl
my @repos = $repo->list_repo();
```
Lists all configured remote repositories (as output lines).
## `uninstall( ..., [ ... ] )`
```perl
$repo->uninstall( 'zlib' );
$repo->uninstall( 'zl*', all => 1 );
```
Removes the specified package from the local cache. Accepts the same `%options` as `install( ... )`. `all` removes all matching packages (ignoring extra configs, Lua patterns allowed) and `force` removes addon packages even when they are still depend...
## `search( ..., [ ... ] )`
```perl
$repo->search( $query );
$repo->search( $query, addon => 1 );
```
Runs `xrepo search` and returns the matching packages as a list of `name` or `name-version` tokens (in list context; the match count in scalar context). Name and version are returned together because a package name may itself contain `-`, so the boun...
The output is captured, so nothing is printed to `STDOUT` by this method. On a failed run (nonzero exit, e.g., a missing `vcpkg::` namespace) it `warn`s and returns an empty list. `addon` searches the `addons/` sub-repository.
## `clean( [ ... ] )`
```perl
$repo->clean();
$repo->clean( installdir => './store' ); # clean an isolated store
```
Cleans the cached packages and downloads. Pass `installdir` and/or `cachedir` to target an isolated store.
## `add_repo( ... )`
```
$repo->add_repo( $name, $git_url, $branch );
```
Adds a custom `xmake` repository.
## `remove_repo( ... )`
```
$repo->remove_repo( $name );
```
Removes a custom repository.
## `update_repo( [...] )`
```
$repo->update_repo(); # Update all
$repo->update_repo( 'main' ); # Update specific repo
```
$repo->download( 'zlib', undef, outputdir => './dl', shallow => 1 ); # fetch sources (no build)
$repo->import_pkg( 'zlib', undef, packagedir => './dl' ); # load into the cache
my $zlib = $repo->install('zlib'); # install offline
say 'installed ' . $zlib->version;
```
### Render the dependency graph
`info( ... depgraph =` 1, format => 'dot')> emits a Graphviz `DOT` description of a package and everything it pulls in. Pipe it to `dot -Tpng dep.dot -o dep.png` to picture how a library's prerequisites resolve:
```perl
use v5.40;
use Alien::Xrepo;
my $dot = Alien::Xrepo->new->info( 'libpng', depgraph => 1, format => 'dot' );
say $dot; # e.g. dot -Tpng dep.dot -o dep.png
```
### Cross-compile a library, then read its compiler/link flags
Install a library for another platform/architecture (the same switches `xrepo` accepts become named options), then `fetch` the `-I...` / `-L.../-l...` flags you would pass to your own compiler:
```perl
use v5.40;
use Alien::Xrepo;
my $repo = Alien::Xrepo->new;
$repo->install(
'libpng', '1.6.x',
plat => 'windows',
arch => 'x64',
mode => 'debug',
kind => 'shared'
);
my $cflags = $repo->fetch( 'libpng', undef, cflags => 1 ); # "-Ic:/.../include ..."
my $ldflags = $repo->fetch( 'libpng', undef, ldflags => 1 ); # "-Lc:/.../lib -l... .."
say "CFLAGS: $cflags";
say "LDFLAGS: $ldflags";
```
### Remove a package from the cache
`uninstall` removes a package from the local store (the same one `install`/`fetch`/`scan` use, or an isolated `root` you installed into). It accepts the same options as `install`; `all` removes every stored variant, and `force` removes a package even...
```perl
use v5.40;
use Alien::Xrepo;
my $repo = Alien::Xrepo->new;
$repo->uninstall('freetype'); # remove one package
$repo->uninstall('zl*', all => 1); # every variant matching the pattern
$repo->uninstall('fontconfig', force => 1); # remove even if still depended upon
```
Note that this edits the shared store. Unlike a builder's prune, which slims the `share` directory a distribution ships, `uninstall` frees space in the store you manage yourself.
# Third-party Package Managers
`xrepo` can install from external package managers instead of (or alongside) the official `xmake-repo`. You select the manager with a package-spec namespace and every `Alien::Xrepo` method takes it verbatim:
```perl
# Vcpkg, Homebrew/Linuxbrew, Conan
my $zlib = $repo->install( 'vcpkg::zlib' );
my $zlib = $repo->install( 'brew::zlib' );
my $zlib = $repo->install( 'conan::zlib/1.2.11' );
# Pacman (archlinux/msys2), Clib, Dub, Cargo, Conda, apt
$repo->install( 'pacman::libcurl' );
$repo->install( 'dub::log 0.4.3' );
```
Searching and flag fetching work against them too:
```perl
$repo->search( 'vcpkg::pcre' ); # search the vcpkg namespace
my $flags = $repo->fetch( 'conan::zlib/1.2.11', undef, cflags => 1, ldflags => 1 );
```
The installed results (`libpath`, `includedirs`, `links`, ...) are decoded into an [Alien::Xrepo::PackageInfo](https://metacpan.org/pod/Alien%3A%3AXrepo%3A%3APackageInfo) exactly like any `xmake-repo` package, so your wrapper code does not care where...
See the `xmake-repo` [integration notes](https://github.com/xmake-io/xrepo-docs/blob/master/getting_started.md) for the corresponding `add_requires` syntax inside an `xmake` project.
## How third-party namespaces are installed
A package in a third-party namespace (`vcpkg::zlib`) is installed by the _external_ manager, and `xmake`'s integration does not bootstrap that manager for you: e.g., the `vcpkg` integration raises **`vcpkg not found!`** when it cannot locate the tool...
```perl
packages => [ { name => 'vcpkg::zlib' }, { name => 'vcpkg' } ]
```
These two names mean different things, and their order in the recipe is not their install order:
- **Recipe order**: (`vcpkg::zlib` then `vcpkg`) is the _consumer_ order. [Alien::Xrepo::Runtime](https://metacpan.org/pod/Alien%3A%3AXrepo%3A%3ARuntime) resolves `libpath`, `find_header`, `cflags`, and `libs` against the _first_ package, so the libr...
- **Install order**: (`vcpkg` then `vcpkg::zlib`) is computed by [Alien::Xrepo::Build](https://metacpan.org/pod/Alien%3A%3AXrepo%3A%3ABuild)'s `_install_order()`: any bare package whose name is the namespace of a later `ns::pkg` entry is installed fi...
Once the bare tool is installed, the engine copies its install dir into the environment of the next namespaced spawn: for `vcpkg` it sets `VCPKG_ROOT` (and prepends the tool dir to `PATH`), so `xmake`'s `vcpkg` integration finds the freshly built bin...
Two implementation details make that work and are easy to get wrong (see [Alien::Xrepo::Build](https://metacpan.org/pod/Alien%3A%3AXrepo%3A%3ABuild)):
- `_pkg_installdir` refuses _namespaced_ (`::`) packages. The external manager owns the on-disk layout, so a per-package store path such as `<share>/vcpkg::zlib` is meaningless and the store guard would reject a perfectly valid install. Leaving `inst...
- Environment propagation uses a hash-slice `local`:
```
local @ENV{ keys %env } = values %env if %env;
```
The otherwise-obvious form `local $ENV{$_} = $env{$_} for keys %env` silently binds the _global_ `$_` (not the loop variable) in some builds of Perl, so the values never reach the child process.
Also note that the decoded `fetch --json` output for third-party packages is not always a tidy list: `libfiles`, `bindirs`, `includedirs`, and `linkdirs` may each arrive as a plain string when there is exactly one file or directory. The engine normal...
# SEE ALSO
[https://xrepo.xmake.io](https://xrepo.xmake.io), [https://packages.xmake.io/](https://packages.xmake.io/)
[Alien::Xmake](https://metacpan.org/pod/Alien%3A%3AXmake), [Alien::Xrepo::Build](https://metacpan.org/pod/Alien%3A%3AXrepo%3A%3ABuild), [Alien::Xrepo::Runtime](https://metacpan.org/pod/Alien%3A%3AXrepo%3A%3ARuntime)
[Alien::Xrepo::MB](https://metacpan.org/pod/Alien%3A%3AXrepo%3A%3AMB), [Alien::Xrepo::MM](https://metacpan.org/pod/Alien%3A%3AXrepo%3A%3AMM), [Alien::Xrepo::Build::Dist](https://metacpan.org/pod/Alien%3A%3AXrepo%3A%3ABuild%3A%3ADist)
[Affix](https://metacpan.org/pod/Affix), [Affix::Wrap](https://metacpan.org/pod/Affix%3A%3AWrap), [FFI::Platypus](https://metacpan.org/pod/FFI%3A%3APlatypus), [Inline::C](https://metacpan.org/pod/Inline%3A%3AC)
( run in 0.837 second using v1.01-cache-2.11-cpan-e623d60df62 )