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 )