Affix

 view release on metacpan or  search on metacpan

t/017_affix_build.t  view on Meta::CPAN

use v5.40;
use blib;
use Affix qw[wrap Int32];
use Affix::Build;
use Test2::Tools::Affix qw[:all];
use Test2::V0 -no_srand => 1;
use Test2::Require::AuthorTesting;
use Path::Tiny qw[path tempfile tempdir];
use DynaLoader;
use Config;
use File::Spec;
#
my $TMP_DIR = Path::Tiny->tempdir( CLEANUP => 0 );
#
subtest 'Inline Source' => sub {
    skip_all 'No CC' unless bin_path( $Config{cc} );
    my $c = Affix::Build->new( build_dir => $TMP_DIR, name => 'inline_lib' );
    $c->add( \<<~'', lang => 'c' );
        #include <stdio.h>
        #ifdef _WIN32
        __declspec(dllexport)
        #endif
        int inline_add(int a, int b) { return a + b; }

    ok lives { $c->compile_and_link() },                                 'Linked inline source';
    ok my $fn = wrap( $c->link, 'inline_add', [ Int32, Int32 ], Int32 ), 'wrap';
    is $fn->( 65, 43 ), 108, 'call';
};
#
sub bin_path ($bin) {
    return $bin if -x $bin && !-d $bin;    # Check absolute
    for my $dir ( File::Spec->path ) {     # Check PATH
        my $full = File::Spec->catfile( $dir, $bin );
        return $full if -x $full && !-d $full;
        if ( $^O eq 'MSWin32' ) {
            return "$full.exe" if -x "$full.exe";
            return "$full.cmd" if -x "$full.cmd";
            return "$full.bat" if -x "$full.bat";
        }
    }
    return undef;
}

sub check_dotnet () {
    return 0 unless bin_path('dotnet');
    my $out = `dotnet --list-sdks 2>&1`;
    return ( $out =~ /^8\./m );
}

sub check_rust_gnu () {
    return 0 unless bin_path('rustc');

    # If not windows, standard rustc is fine
    return 1 if $^O ne 'MSWin32';

    # On Windows, we need to prove the GNU target works
    my $tmp = Path::Tiny->tempfile( SUFFIX => '.rs' );
    $tmp->spew('fn main() {}');
    my $cmd = "rustc --target x86_64-pc-windows-gnu \"$tmp\" -o \"$tmp.exe\" 2>&1";
    my $out = `$cmd`;
    return ( $? == 0 );
}

sub enjoin( $lib, @symbols ) {
    my $path = $lib->stringify;
    my $dll  = DynaLoader::dl_load_file( $path, 0 );
    unless ($dll) {
        fail( "Failed to load library '$path': " . DynaLoader::dl_error() );
        return;
    }
    for my $sym (@symbols) {
        if ( DynaLoader::dl_find_symbol( $dll, $sym ) ) {
            pass( "Symbol '$sym' found in " . $lib->basename );
        }
        else {
            fail( "Symbol '$sym' NOT found in " . $lib->basename );
        }
    }
    DynaLoader::dl_unload_file($dll) if $^O eq 'MSWin32' && defined &DynaLoader::dl_unload_file;
}

sub run_test ( $lang, $name, $code, $sym, $bin_req, $validator //= () ) {
    subtest "$name compilation" => sub {
        my $bin = ( $lang eq 'c' ) ? $Config{cc} : $bin_req;
        unless ( bin_path($bin) ) {
            skip_all "No $name compiler found ($bin)";
            return;
        }
        if ($validator) {
            unless ( $validator->() ) {
                skip_all "$name toolchain unmet";
                return;
            }
        }
        #
        my $ext
            = $lang eq 'rust'   ? 'rs' :
            $lang eq 'csharp'   ? 'cs' :
            $lang eq 'fsharp'   ? 'fs' :
            $lang eq 'fortran'  ? 'f90' :
            $lang eq 'pascal'   ? 'pas' :



( run in 1.985 second using v1.01-cache-2.11-cpan-d80b1682f3f )