=pod

=encoding utf-8

=head1 NAME

Alien::Xrepo - Install shared libraries and third-party binaries (tools, interpreters) for FFI, XS, and build systems

=head1 SYNOPSIS

    use v5.40;
    use Alien::Xrepo;
    use Path::Tiny;

    # Initialize
    my $repo = Alien::Xrepo->new( );

    # Add a custom repository (optional)
    # $repo->add_repo( 'my-repo', 'https://github.com/my/repo.git' );
    # Install a shared lib with an automatic configuration
    my $ogg = $repo->install('libvorbis');

    # Install a library with specific configuration
    # equivalent to: xrepo install -p windows -a x86_64 -m debug --configs='shared=true,vs_runtime=MD' libpng
    my $pkg = $repo->install(
        'libpng', '1.6.x',
        plat    => 'windows',
        arch    => 'x64',
        mode    => 'debug',
        configs => { vs_runtime => 'MD' }
    );
    die 'Install failed' unless $pkg;

    # Or install a binary tool and run it (ninja, cmake, python, node, ...)
    my $ninja = $repo->install('ninja');
    my ($ninja_exe) = map { path($_)->child($^O eq 'MSWin32' ? 'ninja.exe' : 'ninja') } $ninja->bin_dir;
    system $ninja_exe, '--version';

    # Wrap a single function from sqlite3 with Affix
    use Affix;
    my $sqlite3 = $repo->install('sqlite3');
    affix $sqlite3->libpath, 'sqlite3_libversion', [], String;
    say 'SQLite version: ' . sqlite3_libversion();

=head1 DESCRIPTION

This module acts as an intelligent bridge between Perl and a wide range of package systems:
L<xrepo|https://packages.xmake.io/>, L<vcpkg|https://vcpkg.io/en/packages>, L<conan|https://conan.io/center>,
L<brew|https://brew.sh/> (homebrew/linuxbrew), L<conda|https://anaconda.org/>, L<dub|https://dub.pm/> (Dlang libs),
L<apt|https://www.debian.org/distrib/packages> on Debian,
L<pacman|https://wiki.archlinux.org/title/Pacman#Installing_packages> (if you use arch, btw),
L<clib|https://github.com/clibs/clib/>, L<Cargo|https://crates.io/> for Rust crates,
L<Portage|https://packages.gentoo.org/> on Gentoo, L<Nimble|https://nimpackages.com/> for nimlang,
L<NuGet|https://www.nuget.org/> for .NET,
L<Zypper|https://documentation.suse.com/smart/systems-management/html/concept-zypper/index.html> on openSUSE, and even
your own custom repositories with smart prerequisite management.

With a single line, you can fetch B<shared libraries> as well as B<binary tools and interpreters> without touching a
system package manager:

=over

=item * B<Libraries> (C<zlib>, C<libpng>, C<sqlite3>, ...) to bind with FFI or link from XS.

=item * B<Tools and interpreters> (C<ninja>, C<cmake>, C<meson>, C<python>, C<node>, C<go>, C<rust>, ...) to run from
your Perl code or to drive your build.

=back

You are free to install B<both kinds into the same store>: C<ninja> next to C<libpng>. Use L<Affix>, L<FFI::Platypus>,
L<Inline>, or plain XS to bind the libraries, and C<bin_dir>/C<installdir> to locate and run the binaries.

While FFI or XS can handle the binding or linking to native functions, Alien::Xrepo handles the B<acquisition> of the
libraries and binaries. It automates the entire dependency lifecycle:

=over

=item 1. Provisioning:

Downloads and installs both libraries (C<libpng>, C<openssl>, ...) and binary tools (C<ninja>, C<python>, ...) via
C<xrepo>, handling version constraints and custom repository lookups.

=item 2. Configuration:

Ensures libraries are compiled with FFI compatible flags (forcing C<shared> libraries instead of static archives) and
supports cross-compilation parameters (platform, architecture, toolchains).

=item 3. Introspection:

Parses the build metadata to locate the exact absolute paths to the runtime binaries (C<.dll>, C<.so>, C<.dylib>) and
header files, the C<bin_dir> of any installed tool, and the C<-I> / C<-L> / C<-l> flags a compiler needs, abstracting
away operating system filesystem differences.

=back

This eliminates the need for manual compilation steps or hard coding paths in your Perl scripts, making your FFI
bindings or XS wrappers portable and reproducible.

=head1 THIRD-PARTY PACKAGE MANAGERS

xrepo can install from external C/C++ 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:

    # 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 xmake-repo package, so your wrapper code does not care where the library came from.

See the C<xmake-repo> integration notes at L<https://github.com/xmake-io/xrepo-docs/blob/master/getting_started.md> for
the corresponding C<add_requires> syntax inside an xmake project.

=head1 CONSTRUCTOR

=head2 C<new( ... )>

    my $repo = Alien::Xrepo->new( verbose => 1 );

Creates a new instance.

=over

=item B<verbose>

Boolean. If true, prints command output and status messages to C<STDOUT>. Defaults to C<0>.

=item B<root>

Optional default installation root (package store) for this instance. Every store-touching method (C<install>,
C<fetch>, C<scan>, C<uninstall>, ...) uses C<installdir =E<gt> $root> unless a per-call C<installdir> is given, so the
instance is confined to its own project-local directory instead of the shared per-user store. Used by
L<Alien::Xrepo::Base> and the dist builder to keep a distribution's native dependencies inside its C<share> directory.

=item B<theme>

Optional xmake output theme, passed to xmake as C<$ENV{XMAKE_THEME}>. Defaults to C<plain>, which suppresses ANSI color
codes from xmake/xrepo output (clean CPAN test reports, CI logs, and captures). Set C<theme =E<gt> 'default'> to
restore xmake's colored output. May be overridden per-call with C<theme =E<gt> ...> on any store-touching method.

=item B<yes>

Boolean. Auto-confirms interactive xmake/xrepo prompts (e.g. "are you sure to install these packages?") by passing
C<-y>, so an install never hangs waiting on C<STDIN>. This is important when output is captured with L<Capture::Tiny>,
which would otherwise swallow the prompt. C<confirm =E<gt> ...> takes precedence when both are set.

=item B<confirm>

Supplies an explicit answer (C<yes>, C<no>, or C<def>) to any prompt, passed through as C<--confirm=...>. Takes
precedence over C<yes =E<gt> 1>. Both may be overridden per-call with C<yes =E<gt> ...> or C<confirm =E<gt> ...> on any
store-touching method.

=back

=head1 METHODS

=head2 C<install( ... )>

    my $pkg_info = $repo->install( $package_name, $version_constraint, %options );

Installs (if missing) and fetches the metadata for a package.

=over

=item B<$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 default.

=item B<%options>

Optional configuration options passed to C<xrepo> (shared by most other methods and missing options are filled in
automatically):

=over

=item B<plat>

Target platform (e.g., C<windows>, C<linux>, C<macosx>, C<android>, C<iphoneos>, C<wasm>).

=item B<arch>

Target architecture (e.g., C<x86_64>, C<arm64>, C<riscv64>).

=item B<mode>

Build mode: C<debug> or C<release>.

=item B<kind>

Library kind: C<shared> (default) or C<static>.

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 B<toolchain>

Specify a toolchain (e.g., C<llvm>, C<zig>, C<mingw>).

=item B<toolchain_host>

Specify the host toolchain for cross compilation.

=item B<vs>, B<vs_toolset>, B<vs_sdkver>

Visual Studio toolset/sdk selection (e.g., C<--vs=2017>, C<--vs_toolset=14.0>).

=item B<ndk>

The Android NDK directory.

=item B<sdk>

The SDK directory of a cross toolchain.

=item B<mingw>

The MinGW SDK directory.

=item B<jobs>, B<linkjobs>

Parallel compilation/link job counts.

=item B<force>

I<install/download>: force reinstall/redownload all packages. I<remove>: force removal even when still depended on.

=item B<shallow>

Do not install/download dependent packages.

=item B<build>

Always build and install from source.

=item B<debugdir>

Source directory used for debugging; enables C<force> and C<shallow> by default.

=item B<configs( ... )>

A hashref or string of package-specific configurations.

    configs => { openssl => 'true', shared => 'true' }
    # becomes --configs='openssl=true,shared=true'

=item B<includes>

A list or string of extra dependencies to include in the environment.

=item B<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 of the shared per-user store, which gives reproducible builds and protects against an
unrelated C<xrepo> run upgrading or removing the packages your wrapper depends on. Pass the same values to C<fetch>,
C<scan>, C<uninstall>, and friends so they operate on the same store.

=item B<theme>

Per-call xmake output theme override. Defaults to the C<theme> constructor value (C<plain>). See L</"new( ... )">.

=item B<yes>, B<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( ...
)">.

=back

=back

Returns an L<Alien::Xrepo::PackageInfo> object.

=head2 C<fetch( $pkg, $version, %options )>

    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 B<cflags>

Fetch C<-I...> include flags as a string.

=item B<ldflags>

Fetch C<-L.../-l...> link flags as a string.

=item B<deps>

Fetch packages together with their dependencies.

=item B<system>

Only fetch the package on the current system.

=item B<external>

Show C<cflags> as external packages (with C<-isystem>).

=item B<installdir>, B<cachedir>

Target the same isolated store used by C<install( ... )> (see there).

=back

=head2 C<info( $pkg, %options )>

    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 can be rendered with C<dot -Tpng dep.dot -o dep.png>.

=head2 C<scan( [$pkg], %options )>

    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( $pkg, $version, %options )>

    $repo->download( 'zlib', undef, outputdir => './dl', shallow => 1 );

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( $pkg, $version, %options )>

    $repo->import_pkg( 'zlib', undef, packagedir => './packages' );

Imports pre-downloaded package archives into the local cache. C<packagedir> selects the source directory.

=head2 C<export( $pkg, $version, %options )>

    $repo->export( 'zlib', undef, packagedir => './packages', shallow => 1 );

Exports installed package files for offline use. C<packagedir> selects the destination directory.

=head2 C<env( [$program], %options )>

    $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 environment config files.

=head2 C<list_repo( )>

    my @repos = $repo->list_repo( );

Lists all configured remote repositories (output lines).

=head2 C<uninstall( $lib, %options )>

    $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 depended upon.

=head2 C<search( $query, %options )>

    $repo->search( $query );
    $repo->search( $query, addon => 1 );

Runs C<xrepo search> and prints the results to STDOUT. C<addon> searches the C<addons/> sub-repository.

=head2 C<clean( %options )>

    $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 xmake repository.

=head2 C<remove_repo( ... )>

    $repo->remove_repo( $name );

Removes a custom repository.

=head2 C<update_repo( [$repo] )>

    $repo->update_repo( );        # Update all
    $repo->update_repo( 'main' ); # Update specific repo

Updates the local package lists from the remote repositories.

=head1 Alien::Xrepo::PackageInfo

Returned by C<install( ... )>, this object contains the results of the dependency resolution.

=head3 Attributes

=over

=item B<libpath>

The absolute path to the main library file (C<.dll>, C<.dylib>, or C<.so>). Returns C<undef> if the package is
header-only or the binary could not be identified.

=item B<includedirs>

List of include paths.

=item B<installdir>

The package install root. Packages that mostly exist as tools or runnable binaries (C<ninja>, C<python>, C<cmake>, ...)
put their executables under C<< installdir/bin >>.

=item B<bin_dir>

List of directories holding executables. Comes from the C<bindirs> fetch metadata, or falls back to C<< installdir/bin
>> when the package is a tool. Run a freshly installed binary like so:

    my $ninja = $repo->install('ninja');
    my ($exe) = grep { -e $_ } map { path($_)->child($^O eq 'MSWin32' ? 'ninja.exe' : 'ninja') } $ninja->bin_dir;
    system $exe, '--version';

=item B<libfiles>

List of all library files associated with the package (may include import libs, static archives, etc.).

=item B<license>

The license identifier.

=item B<version>

The installed version.

=back

=head3 Methods

=head4 C<find_header( ... )>

    my $path = $info->find_header( 'png.h' );

Scans C<includedirs> for the given filename and returns the absolute path if found. Returns C<undef> otherwise.

=head1 Examples

If you just want to use a library, copy one of these. Each one installs whatever is missing on the first run and takes
care of the rest.

=head2 Hello World (install then call)

C<install( ... )> downloads and builds the library for you, then C<libpath> points L<Affix> or L<FFI::Platypus> to the
matching shared C<.dll> / C<.so> / C<.dylib>.

Affix first:

    use v5.40;
    use Alien::Xrepo;
    use Affix;

    my $zlib = Alien::Xrepo->new->install('zlib');
    affix $zlib->libpath, 'zlibVersion', [], String;
    say 'zlib ' . zlibVersion();

The same simple demo with FFI::Platypus:

    use v5.40;
    use Alien::Xrepo;
    use FFI::Platypus;

    my $zlib = Alien::Xrepo->new->install('zlib');

    my $ffi = FFI::Platypus->new;
    $ffi->lib( $zlib->libpath );
    $ffi->attach( zlibVersion => [] => 'string' );
    say 'zlib ' . zlibVersion();

And if you want the whole library wrapped (prototypes generated from the headers) instead of one function at a time,
use L<Affix::Wrap>:

    use v5.40;
    use Alien::Xrepo;
    use Affix::Wrap;

    my $zlib = Alien::Xrepo->new->install('zlib');
    Affix::Wrap->new(
        project_files => [ $zlib->find_header('zlib.h') ],
        include_dirs  => [ $zlib->includedirs ],
        types         => { gzFile_s => Pointer [Void] }
    )->wrap( $zlib->libpath );
    say 'zlib ' . zlibVersion();

=head2 Link an XS extension with Inline::C (multiple libraries)

Same idea for an actual C extension, compiled with L<Inline::C>. Install every library you want to link; merge their
include and link directories, hand them to Inline::C, and write plain C that uses whichever header you need. Here we
bind both C<libpng> and C<zlib> (installed together into one store) into a single XS function:

    use v5.40;
    use Alien::Xrepo;
    use Config;

    my $repo = Alien::Xrepo->new;
    my $png   = $repo->install('libpng');       # shared lib
    my $zlib  = $repo->install('zlib');         # second shared lib

    # The compiled XS loads png.dll / libpng.so at runtime, so put both native
    # "bin" dirs on PATH before calling into it (Windows especially).
    my @png_bins  = $png->bin_dir;
    my @zlib_bins = $zlib->bin_dir;
    local $ENV{PATH} = join $Config{path_sep}, (@png_bins, @zlib_bins, $ENV{PATH});

    # Merge include and link directories into plain flag strings.
    my $incs = join ' ', map { "-I$_" } (@{ $png->includedirs }, @{ $zlib->includedirs });
    my $libs = join ' ',
        map { "-L$_" } (@{ $png->linkdirs }, @{ $zlib->linkdirs }),
        map { "-l$_" } (@{ $png->links },    @{ $zlib->links });

    use Inline ();
    Inline->bind(
        'C',
        <<'C',
    #include <png.h>
    #include <zlib.h>
    const char *versions () {
        return "libpng " PNG_LIBPNG_VER_STRING ", zlib " ZLIB_VERSION;
    }
C
        INC  => $incs,
        LIBS => $libs,
    );
    say versions();

The I<eg/xrepo_inline_c.pl> script is the runnable copy of this example. C<Inline::C> is not installed with this
distribution. Install it once with C<cpanm Inline::C>.

=head2 Install and run a binary tool

C<xrepo> does not build only shared libraries, it also ships ready-to-run binaries (C<ninja>, C<cmake>, C<meson>,
C<node>, C<python>, C<go>, C<rust>, ...). C<install> returns the package C<installdir>, and C<bin_dir> tells you where
the executables live. Run one directly, or stick C<bin_dir> in front of C<PATH> so all the children you spawn find the
tool:

    use v5.40;
    use Alien::Xrepo;
    use Path::Tiny;
    use Config;

    my $repo    = Alien::Xrepo->new;
    my $ninja   = $repo->install('ninja');
    my @bins    = $ninja->bin_dir;

    # Option A: run a single binary from bin_dir
    my ($ninja_exe) = map { path($_)->child($^O eq 'MSWin32' ? 'ninja.exe' : 'ninja') } @bins;
    system $ninja_exe, '--version';

    # Option B: put bin_dir first on PATH, then plain 'ninja' resolves
    local $ENV{PATH} = join $Config{path_sep}, (@bins, $ENV{PATH});
    system 'ninja', '--version';

Use C<installdir> for everything the tool ships, not just C<bin>:

    say 'ninja install root: ' . $ninja->installdir;

=head2 Build a C program against a library

C<install> builds the library once; C<fetch> tells you the C<-I...> and C<-L.../-l...> flags if you are building with
something other than xmake (e.g. MakeMaker or a plain C<cc>):

    use v5.40;
    use Alien::Xrepo;

    my $repo = Alien::Xrepo->new;
    $repo->install( 'libpng' );                       # build it once
    my $cflags  = $repo->fetch( 'libpng', undef, cflags  => 1 );
    my $ldflags = $repo->fetch( 'libpng', undef, ldflags => 1 );
    say "cc $cflags $ldflags pngprog.c -o pngprog";

=head2 What can I install? What do I already have?

    use v5.40;
    use Alien::Xrepo;
    my $repo = Alien::Xrepo->new;

    say '[What is available?]';
    $repo->search('sqlite');

    say '[Already installed:]';
    say for $repo->scan;

C<search> prints matching packages from every configured repository and C<scan> lists everything already on disk.

=head2 Cross-compile without memorizing SDK paths

All of xrepo's platform switches become named options. C<ndk> is just one example, alongside C<toolchain>, C<sdk>,
C<mingw> and the rest.

    use v5.40;
    use Alien::Xrepo;

    my $pkg = Alien::Xrepo->new->install(
        'zlib', '1.3.x',
        plat => 'android',
        arch => 'arm64',
        ndk  => 'C:/Android/Sdk/ndk/26.1.10909125'  # adapt to your NDK
    );
    say $pkg->libpath;

=head2 Drop into a shell inside the library's environment

C<env> sets up the environment for a package (PATH, etc.) and either runs C<$program> inside it (default: the system
shell) or just prints it with C<show>.

    use v5.40;
    use Alien::Xrepo;
    Alien::Xrepo->new->env( 'bash', bind => 'zlib' ); # or env( undef, bind => 'zlib' )
    # Alien::Xrepo->new->env( undef, show => 1 );     # just print the environment

=head2 Guard an install against a package that may not exist

C<search> reports what the configured repositories actually provide. Check before you C<install> so a spec that is
absent (or renamed) in the active repos fails cleanly instead of erroring mid-way:

    use v5.40;
    use Alien::Xrepo;

    my $repo = Alien::Xrepo->new;
    if ( grep {/zlib/} $repo->search('zlib') ) {
        my $zlib = $repo->install('zlib');
        say 'zlib at ' . $zlib->libpath;
    }
    else {
        warn "zlib is unavailable in the configured repositories\n";
    }

=head2 Run a binary tool and check it worked

C<env> wraps the given program with the package's environment (PATH already adjusted) and returns its exit status, so
it doubles as a smoke test that the tool actually runs:

    use v5.40;
    use Alien::Xrepo;

    my $repo = Alien::Xrepo->new;
    my $cmake = $repo->install('cmake');            # kind: binary
    my $rc = $repo->env('cmake', '--version');      # runs cmake with its bin_dir on PATH
    die "cmake failed to run" unless $rc == 0;

=head2 Bundle a package for offline use

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;

=head2 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

=head2 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";

=head2 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, C<force>
removes a package even when others still depend on it. It returns the underlying exit status, so check C<$?>:

    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> dir a distribution ships,
C<uninstall> frees space in the store you manage yourself.

=head1 SEE ALSO

L<https://xrepo.xmake.io>, L<https://packages.xmake.io/>

L<Affix>, L<Affix::Wrap>, L<Alien::Xmake>, L<FFI::Platypus>, L<Inline::C>; subclass the base class with
L<Alien::Xrepo::Base>

=head1 LICENSE

Copyright (C) Sanko Robinson.

This library is free software; you can redistribute it and/or modify it under the terms found in the Artistic License
2. Other copyrights, terms, and conditions may apply to data transmitted through this module.

=head1 AUTHOR

Sanko Robinson L<https://github.com/sanko>

=cut
