Alien-Xrepo
view release on metacpan or search on metacpan
lib/Alien/Xrepo.pod view on Meta::CPAN
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 C<xmake> process startup cost entirely:
=over
=item 1. A warm cache hit replays the memorized fetch result without invoking C<xrepo>. The entry is only trusted while its recorded install directory still exists on disk, and stale entries automatically prune themselves. (See the B<cache> construct...
=item 2. Otherwise, C<fetch --json> is tried first: an already-installed package answers with real paths immediately and the mutating C<xrepo install> is skipped. That single fetch is also memorized for next time.
=item 3. Only when a package truly is missing does C<xrepo install> run, followed by a mandatory fetch to learn where its output landed.
=back
=over
=item C<$package_name>
The name of the package (e.g., C<zlib>, C<opencv>).
=item B<$version_constraint>
Optional semantic version string (C<1.2.x>, C<latest>). Pass C<undef> or an empty string for the default.
=item C<%options>
Optional configuration options passed to C<xrepo> (shared by most other methods; missing options are filled in automatically):
=over
=item C<plat>
Target platform (e.g., C<windows>, C<linux>, C<macosx>, C<android>, C<iphoneos>, C<wasm>).
=item C<arch>
Target architecture (e.g., C<x86_64>, C<arm64>, C<riscv64>).
=item C<mode>
Build mode: C<debug> or C<release>.
=item C<kind>
Library kind: C<shared> or C<static>. If omitted entirely, the package's own default applies, so a bare install behaves exactly like C<xrepo install>.
I<Note: For FFI, you almost always want C<shared>, but C<static> is available if you are linking archives with, say, an XS module.>
=item C<toolchain>
Specify a toolchain (e.g., C<llvm>, C<zig>, C<mingw>).
=item C<toolchain_host>
Specify the host toolchain for cross-compilation.
=item C<vs>, C<vs_toolset>, C<vs_sdkver>
Visual Studio toolset/SDK selection (e.g., C<--vs=2017>, C<--vs_toolset=14.0>).
=item C<ndk>
The Android NDK directory.
=item C<sdk>
The SDK directory of a cross-toolchain.
=item C<mingw>
The MinGW SDK directory.
=item C<jobs>, B<linkjobs>
Parallel compilation/link job counts.
=item C<force>
I<install/download>: force reinstall/redownload all packages. I<remove>: force removal even when still depended on.
=item C<shallow>
Do not install/download dependent packages.
=item C<build>
Always build and install from source.
=item C<debugdir>
Source directory used for debugging; enables C<force> and C<shallow> by default.
=item C<configs( ... )>
A hashref or string of package-specific configurations.
configs => { openssl => 'true', shared => 'true' }
# becomes --configs='openssl=true,shared=true'
Perl's built-in boolean scalars (C<use feature 'true'/'false'>, enabled by C<use v5.36+>) are normalized to the literal strings C<'true'> / C<'false'>, so C<< configs => { shared => true } >> produces C<--configs='shared=true'>.
=item C<includes>
A list or string of extra C<rc> files to include in the environment.
Each include is forwarded to C<xmake> verbatim, so it must be a valid root-scope C<xmake> configuration (e.g., C<add_toolchains>); C<xmake> textually prepends C<rc> contents to the temporary project script. A vendored C<package() {...}> recipe is NOT...
=item C<installdir>, B<cachedir>
Root directories for the installed packages and the download/build cache, applied per-call via the C<XMAKE_PKG_INSTALLDIR> / C<XMAKE_PKG_CACHEDIR> environment variables. This lets each wrapper keep its libraries in a project-local directory instead o...
=item C<theme>
Per-call C<xmake> output theme override. Defaults to the C<theme> constructor value (C<plain>). See L</"new( ... )">.
=item C<yes>, C<confirm>
Per-call auto-confirmation overrides for the constructor C<yes =E<gt> ...> / C<confirm =E<gt> ...> options, applied as C<-y> or C<--confirm=...> to the underlying C<xrepo> invocation. Defaults to the constructor values. See L</"new( ... )">.
lib/Alien/Xrepo.pod view on Meta::CPAN
=back
=back
Returns an L<Alien::Xrepo::PackageInfo> object.
=head2 C<fetch( ..., [ ... ] )>
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 L<Alien::Xrepo::PackageInfo> object, or a raw flag string when C<cflags> or C<ldflags> is requested.
=over
=item C<cflags>
Fetch C<-I...> include flags as a string.
=item C<ldflags>
Fetch C<-L.../-l...> link flags as a string.
=item C<deps>
Fetch packages together with their dependencies.
=item C<system>
Only fetch the package on the current system.
=item C<external>
Show C<cflags> as external packages (with C<-isystem>).
=item C<installdir>, C<cachedir>
Target the same isolated store used by C<install( ... )> (see there).
=back
=head2 C<info( ... )>
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 C<format =E<gt> 'json'> to receive the decoded data structure (array of hashes), C<format =E<gt> 'dot'> for a Graphviz DOT dependency graph, or C<depgraph =E<gt> 1> to include the package dependency tree. A DOT graph c...
=head2 C<scan( [ ... ] )>
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.
=head2 C<download( ... )>
$repo->download( 'zlib', undef, outputdir => './dl', shallow => 1 ); # Downloads the latest version
Only downloads the package source archives without building them. C<outputdir> selects the destination directory (default C<packages>). Supports C<force>, C<shallow>, and the standard C<%options>.
=head2 C<import_pkg( ... )>
$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. C<packagedir> selects the source directory.
=head2 C<export( ... )>
$repo->export( 'zlib', undef, packagedir => './packages', shallow => 1 ); # Export the latest version
Exports installed package files for offline use. C<packagedir> selects the destination directory.
=head2 C<env( [ ..., [ ... ] ] )>
$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 (C<show>) or executes C<$program> (default C<shell>) inside it. C<bind> selects which environment config or package to bind, C<list> lists global configs, and C<add>/C<remove> manage global environ...
=head2 C<list_repo()>
my @repos = $repo->list_repo();
Lists all configured remote repositories (as output lines).
=head2 C<uninstall( ..., [ ... ] )>
$repo->uninstall( 'zlib' );
$repo->uninstall( 'zl*', all => 1 );
Removes the specified package from the local cache. Accepts the same C<%options> as C<install( ... )>. C<all> removes all matching packages (ignoring extra configs, Lua patterns allowed) and C<force> removes addon packages even when they are still de...
=head2 C<search( ..., [ ... ] )>
$repo->search( $query );
$repo->search( $query, addon => 1 );
Runs C<xrepo search> and returns the matching packages as a list of C<name> or C<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 C<->, so the ...
The output is captured, so nothing is printed to C<STDOUT> by this method. On a failed run (nonzero exit, e.g., a missing C<vcpkg::> namespace) it C<warn>s and returns an empty list. C<addon> searches the C<addons/> sub-repository.
=head2 C<clean( [ ... ] )>
$repo->clean();
$repo->clean( installdir => './store' ); # clean an isolated store
Cleans the cached packages and downloads. Pass C<installdir> and/or C<cachedir> to target an isolated store.
=head2 C<add_repo( ... )>
$repo->add_repo( $name, $git_url, $branch );
Adds a custom C<xmake> repository.
=head2 C<remove_repo( ... )>
$repo->remove_repo( $name );
Removes a custom repository.
=head2 C<update_repo( [...] )>
$repo->update_repo(); # Update all
$repo->update_repo( 'main' ); # Update specific repo
Updates the local package lists from the remote repositories.
=head1 Cache System
C<install> avoids paying C<xmake>'s process-startup cost on every call. Each successful resolution is memorized as a small JSON record and replayed on the next launch, so a long-lived demo (e.g., L<eg/webui.pl>) or a build loop running against the sa...
=over
=item * B<What is stored>
The raw C<fetch --json> output plus the resolved install directory, keyed by a SHA-1 fingerprint of the package spec and every option that can move the installed layout (C<kind>, C<plat>, C<arch>, C<mode>, C<configs>). Config values run through the s...
=item * B<Where it lives>
lib/Alien/Xrepo.pod view on Meta::CPAN
C<download> fetches the source archives without building, C<import_pkg> drops them into the local cache, and a subsequent C<install> uses them even on a machine with no network. Handy for air-gapped CI or offline installs:
use v5.40;
use Alien::Xrepo;
my $repo = Alien::Xrepo->new;
$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;
=head3 Render the dependency graph
C<info( ... depgraph => 1, format => 'dot')> emits a Graphviz C<DOT> description of a package and everything it pulls in. Pipe it to C<dot -Tpng dep.dot -o dep.png> to picture how a library's prerequisites resolve:
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
=head3 Cross-compile a library, then read its compiler/link flags
Install a library for another platform/architecture (the same switches C<xrepo> accepts become named options), then C<fetch> the C<-I...> / C<-L.../-l...> flags you would pass to your own compiler:
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";
=head3 Remove a package from the cache
C<uninstall> removes a package from the local store (the same one C<install>/C<fetch>/C<scan> use, or an isolated C<root> you installed into). It accepts the same options as C<install>; C<all> removes every stored variant, and C<force> removes a pack...
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 C<share> directory a distribution ships, C<uninstall> frees space in the store you manage yourself.
=head1 Third-party Package Managers
C<xrepo> can install from external package managers instead of (or alongside) the official C<xmake-repo>. You select the manager with a package-spec namespace and every C<Alien::Xrepo> method takes it verbatim:
# 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:
$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 (C<libpath>, C<includedirs>, C<links>, ...) are decoded into an L<Alien::Xrepo::PackageInfo> exactly like any C<xmake-repo> package, so your wrapper code does not care where the library came from.
See the C<xmake-repo> L<integration notes|https://github.com/xmake-io/xrepo-docs/blob/master/getting_started.md> for the corresponding C<add_requires> syntax inside an C<xmake> project.
=head2 How third-party namespaces are installed
A package in a third-party namespace (C<vcpkg::zlib>) is installed by the I<external> manager, and C<xmake>'s integration does not bootstrap that manager for you: e.g., the C<vcpkg> integration raises B<C<vcpkg not found!>> when it cannot locate the ...
packages => [ { name => 'vcpkg::zlib' }, { name => 'vcpkg' } ]
These two names mean different things, and their order in the recipe is not their install order:
=over
=item * B<Recipe order>: (C<vcpkg::zlib> then C<vcpkg>) is the I<consumer> order. L<Alien::Xrepo::Runtime> resolves C<libpath>, C<find_header>, C<cflags>, and C<libs> against the I<first> package, so the library comes first and the bare tool package ...
=item * B<Install order>: (C<vcpkg> then C<vcpkg::zlib>) is computed by L<Alien::Xrepo::Build>'s C<_install_order()>: any bare package whose name is the namespace of a later C<ns::pkg> entry is installed first, so its store path is known before the n...
=back
Once the bare tool is installed, the engine copies its install dir into the environment of the next namespaced spawn: for C<vcpkg> it sets C<VCPKG_ROOT> (and prepends the tool dir to C<PATH>), so C<xmake>'s C<vcpkg> integration finds the freshly buil...
Two implementation details make that work and are easy to get wrong (see L<Alien::Xrepo::Build>):
=over
=item * C<_pkg_installdir> refuses I<namespaced> (C<::>) packages. The external manager owns the on-disk layout, so a per-package store path such as C<< <share>/vcpkg::zlib >> is meaningless and the store guard would reject a perfectly valid install....
=item * Environment propagation uses a hash-slice C<local>:
local @ENV{ keys %env } = values %env if %env;
The otherwise-obvious form C<< local $ENV{$_} = $env{$_} for keys %env >> silently binds the I<global> C<$_> (not the loop variable) in some builds of Perl, so the values never reach the child process.
=back
Also note that the decoded C<fetch --json> output for third-party packages is not always a tidy list: C<libfiles>, C<bindirs>, C<includedirs>, and C<linkdirs> may each arrive as a plain string when there is exactly one file or directory. The engine n...
=head1 SEE ALSO
L<https://xrepo.xmake.io>, L<https://packages.xmake.io/>
L<Alien::Xmake>, L<Alien::Xrepo::Build>, L<Alien::Xrepo::Runtime>
L<Alien::Xrepo::MB>, L<Alien::Xrepo::MM>, L<Alien::Xrepo::Build::Dist>
( run in 1.089 second using v1.01-cache-2.11-cpan-e623d60df62 )