Affix

 view release on metacpan or  search on metacpan

builder/Affix/Builder.pm  view on Meta::CPAN

                .= ' -DNDEBUG -DBOOST_DISABLE_ASSERTS -Ofast -ftree-vectorize -ffast-math -fno-align-functions -fno-align-loops -fno-omit-frame-pointer -flto=auto';
        }

        # Threading support (Critical for shm_open/librt on Linux)
        if ( !$is_win ) {
            $cflags  .= ' -pthread';
            $ldflags .= ' -pthread';
        }
    }
    method write_file( $filename, $content ) { path($filename)->spew_raw($content) or die "Could not open $filename: $!\n" }
    method read_file ($filename)             { path($filename)->slurp_utf8         or die "Could not open $filename: $!\n" }

    method step_build() {
        $self->step_affix;
        my %modules       = map { $_ => catfile( 'blib', $_ ) } find( qr/\.pm$/,  'lib' );
        my %docs          = map { $_ => catfile( 'blib', $_ ) } find( qr/\.pod$/, 'lib' );
        my %scripts       = map { $_ => catfile( 'blib', $_ ) } find( qr/(?:)/,   'script' );
        my %sdocs         = map { $_ => delete $scripts{$_} } grep {/.pod$/} keys %scripts;
        my %dist_shared   = map { $_ => catfile( qw[blib lib auto share dist],   $meta->name, abs2rel( $_, 'share' ) ) } find( qr/(?:)/, 'share' );
        my %module_shared = map { $_ => catfile( qw[blib lib auto share module], abs2rel( $_, 'module-share' ) ) } find( qr/(?:)/, 'module-share' );
        pm_to_blib( { %modules, %docs, %scripts, %dist_shared, %module_shared }, catdir(qw[blib lib auto]) );

lib/Affix.c  view on Meta::CPAN

        UV uv = (UV)*s++;

        // Handle Windows Surrogate Pairs (UTF-16LE)
        if (sizeof(wchar_t) == 2 && uv >= 0xD800 && uv <= 0xDBFF) {
            if (*s >= 0xDC00 && *s <= 0xDFFF) {
                UV low = (UV)*s++;
                uv = ((uv - 0xD800) << 10) + (low - 0xDC00) + 0x10000;
            }
        }

        d = (char *)uvchr_to_utf8((U8 *)d, uv);
    }
    *d = 0;

    // Set Perl SV properties
    SvCUR_set(sv, d - SvPVX(sv));
    SvPOK_on(sv);
    SvUTF8_on(sv);
}

// Direct marshalling experiment

lib/Affix.c  view on Meta::CPAN

                step->executor(aTHX_ affix, step, &ST(0), args_buffer, c_args, ret_buffer);                  \
            DISPATCH();                                                                                      \
        }                                                                                                    \
CASE_OP_PUSH_PTR_WCHAR:                                                                                      \
        {                                                                                                    \
            SV * sv = ST(step->data.index);                                                                  \
            void * ptr = (char *)args_buffer + step->data.c_arg_offset;                                      \
            c_args[step->data.index] = ptr;                                                                  \
            if (SvPOK(sv)) {                                                                                 \
                STRLEN len;                                                                                  \
                U8 * s = (U8 *)SvPVutf8(sv, len);                                                            \
                U8 * e = s + len;                                                                            \
                Newx(*(void **)ptr, len + 1, wchar_t);                                                       \
                wchar_t * d = *(void **)ptr;                                                                 \
                while (s < e) {                                                                              \
                    UV uv = utf8_to_uvchr_buf(s, e, nullptr);                                                \
                    if (sizeof(wchar_t) == 2 && uv > 0xFFFF) {                                               \
                        uv -= 0x10000;                                                                       \
                        *d++ = (wchar_t)((uv >> 10) + 0xD800);                                               \
                        *d++ = (wchar_t)((uv & 0x3FF) + 0xDC00);                                             \
                    }                                                                                        \
                    else                                                                                     \
                        *d++ = (wchar_t)uv;                                                                  \
                    s += UTF8SKIP(s);                                                                        \
                }                                                                                            \
                *d = 0;                                                                                      \

lib/Affix/Build.pm  view on Meta::CPAN

            $_lib = ();                        # Reset cached library handle
            my ( $path, $lang );
            if ( ref $input eq 'SCALAR' ) {    # Inline source code
                $args{lang} // croak q[Parameter 'lang' (extension) is required for inline source];
                $lang = lc $args{lang};

                # Generate a unique filename in the build dir
                state $counter = 0;
                my $fname = sprintf( "source_%03d.%s", ++$counter, $lang );
                $path = $build_dir->child($fname);
                $path->spew_utf8($$input);
            }
            else {                             #  File path
                $path = Path::Tiny::path($input)->absolute;
                croak "File not found: $path" unless $path->exists;
                ($lang) = $path =~ /\.([^.]+)$/;
                $lang = lc( $lang // '' );
            }

            # Handle local flags
            my $local_flags = $args{flags} // [];

lib/Affix/Build.pm  view on Meta::CPAN

        method _build_dotnet ( $src, $out, $mode, $lang ) {
            my $file     = $src->{path};
            my $dotnet   = $self->_can_run('dotnet') // croak "Dotnet not found";
            my $proj_dir = $build_dir->child( "dotnet_${lang}_" . $self->_base($file) );
            $proj_dir->mkpath;
            $file->copy( $proj_dir->child( $file->basename ) );
            my $ext      = $lang eq 'fs' ? 'fsproj' : 'csproj';
            my $proj     = $proj_dir->child("Build.$ext");
            my $lib_type = ( $mode eq 'dynamic' ) ? 'Shared'                                               : 'Static';
            my $items    = $lang eq 'fs'          ? '<ItemGroup><Compile Include="**/*.fs" /></ItemGroup>' : '';
            $proj->spew_utf8(<<"XML");
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<PublishAot>true</PublishAot>
<NativeLib>$lib_type</NativeLib>
<SelfContained>true</SelfContained>
</PropertyGroup>
$items
</Project>
XML

lib/Affix/Wrap.pm  view on Meta::CPAN

                args         => \@args,
                doc          => $self->_doc_w_trail( $f, $s, $e ),
                start_offset => $s,
                end_offset   => $e
                );
        }

        method _get_content($f) {
            my $abs = $self->_normalize($f);
            return $file_cache->{$abs} if exists $file_cache->{$abs};
            if ( -e $abs ) { return $file_cache->{$abs} = Path::Tiny::path($abs)->slurp_utf8; }
            return '';
        }

        method _extract_doc( $f, $off ) {
            return undef unless defined $off;
            my $content = $self->_get_content($f);
            return undef unless length($content);
            my $pre   = substr( $content, 0, $off );
            my @lines = split /\n/, $pre;
            my @d;

lib/Affix/Wrap.pm  view on Meta::CPAN

                if ( $f =~ /\.h(pp|xx)?$/i ) { $self->_scan( $f, \@objs ); $self->_scan_funcs( $f, \@objs ); }
                else                         { $self->_scan_funcs( $f, \@objs ); }
            }
            @objs = sort { ( $a->file cmp $b->file ) || ( $a->start_offset <=> $b->start_offset ) } @objs;
            @objs;
        }

        method _read($f) {
            my $abs = $self->_normalize($f);
            return $file_cache->{$abs} if exists $file_cache->{$abs};
            return $file_cache->{$abs} = Path::Tiny::path($f)->slurp_utf8;
        }

        method _scan( $f, $acc ) {
            my $c = $self->_read($f);

            # Macros
            while ( $c =~ /^\s*#\s*define\s+(\w+)(?:[ \t]+(.*?))?$/gm ) {
                my $name = $1;
                my $val  = $2 // '';
                my $s    = $-[0];

lib/Affix/Wrap.pm  view on Meta::CPAN

            }
            for my $node (@nodes) {
                if ( ( $node isa Affix::Wrap::Typedef || $node isa Affix::Wrap::Struct || $node isa Affix::Wrap::Enum ) &&
                    exists $types->{ $node->name } ) {
                    next;
                }
                my $code = $node->affix_type;
                if ($code) { $out .= "$code;\n"; }
            }
            $out .= "\n};\n1;\n";
            Path::Tiny::path($file)->spew_utf8($out);
        }

        method wrap ( $lib, $target //= [caller]->[0] ) {

            # Pre-register User Types
            # This ensures they are available in the Affix registry before signatures are parsed,
            # and allows using them in recursive definitions or opaque handles.
            for my $name ( keys %$types ) {
                my $type     = $types->{$name};
                my $type_str = builtin::blessed($type) ? $type : "$type";

lib/Test2/Tools/Affix.pm  view on Meta::CPAN

        else {
            $opt = tempfile(
                UNLINK => !$keep,
                SUFFIX => '_' . path( [ caller() ]->[1] )->basename . ( $name =~ m[^\s*//\s*ext:\s*\.c$]ms ? '.c' : '.cxx' )
            )->absolute;
            push @cleanup, $opt unless $keep;
            my ( $package, $filename, $line ) = caller;
            $filename = path($filename)->canonpath;
            $line++;
            $filename =~ s[\\][\\\\]g;    # Windows...
            $opt->spew_utf8(qq[#line $line "$filename"\r\n$name]);
        }
        if ( !$opt ) {
            $c->fail('Failed to locate test source');
            $c->release;
            return ();
        }
        $aggs->{cflags} .= ' -I' . $Inc;
        my $compiler = Affix::Build->new( debug => 0, name => 'testing', version => '1.0', flags => $aggs );
        $compiler->add( $opt->canonpath );
        $compiler->link;

lib/Test2/Tools/Affix.pm  view on Meta::CPAN

            # $out =~ s[# Seeded srand with seed .+$][]m;
            # $err =~ s[# Tests were run .+$][];
            if ( $out =~ m[\S] ) {
                $out =~ s[^((?:[ \t]*))(?=\S)][$1  ]gm;
                print $out;
            }
            if ( $err =~ m[\S] ) {
                $err =~ s[^((?:[ \t]*))(?=\S)][$1  ]gm;
                print STDERR $err;
            }
            my $parsed = parse_xml( $report->slurp_utf8 );

            # use Data::Dump;
            # ddx $parsed;
            # diag 'exit: '. $exit;
            # Test2::API::test2_stack()->top->{count}++;
            ok !$exit && !$parsed->{valgrindoutput}{errorcounts}, $name;
        }
    }

    END {

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

            = $lang eq 'rust'   ? 'rs' :
            $lang eq 'csharp'   ? 'cs' :
            $lang eq 'fsharp'   ? 'fs' :
            $lang eq 'fortran'  ? 'f90' :
            $lang eq 'pascal'   ? 'pas' :
            $lang eq 'crystal'  ? 'cr' :
            $lang eq 'assembly' ? 'asm' :
            $lang eq 'cobol'    ? 'cbl' :
            $lang;
        my $src = $TMP_DIR->child("test_$lang.$ext");
        $src->spew_utf8($code);
        #
        my $c = Affix::Build->new( build_dir => $TMP_DIR, name => "${lang}_lib" );
        $c->add($src);
        try { $c->compile_and_link() }
        catch ($err) {
            skip_all 'Link failed (toolchain issue?): ' . $err;
            return;
        }
        pass 'Linked successfully';
        #

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

           PROCEDURE DIVISION USING A, B, R.
               ADD A TO B GIVING R.
               GOBACK.
           END PROGRAM add_cob.

subtest 'Polyglot: Number Cruncher (C + Fortran + ASM)' => sub {
    skip_all "Missing compilers" unless bin_path( $Config{cc} ) && bin_path('gfortran');

    # C is our orchestrator
    my $c_src = $TMP_DIR->child('math_core.c');
    $c_src->spew_utf8(<<~'C');
        #include <stdio.h>
        #ifdef _WIN32
        __declspec(dllexport)
        #endif
        int core_version() { return 1; }
        C

    # Fortran does the math
    my $f_src = $TMP_DIR->child('math_algos.f90');
    $f_src->spew_utf8(<<~'F90');
        function fortran_add(a, b) bind(c, name='fortran_add')
            use iso_c_binding
            integer(c_int), value :: a, b
            integer(c_int) :: fortran_add
            fortran_add = a + b
        end function
        F90

    # Assembly for optimization
    my $asm_bin;

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

        $asm_src       = <<~'' }
            global asm_inc
            section .text
            asm_inc:
                mov eax, edi
                inc eax
                ret

    skip_all "Missing Assembler ($asm_bin)" unless bin_path($asm_bin);
    my $asm_file = $TMP_DIR->child($asm_file_name);
    $asm_file->spew_utf8($asm_src);
    #
    my $compiler = Affix::Build->new( name => 'number_cruncher', build_dir => $TMP_DIR );
    $compiler->add($c_src);
    $compiler->add($f_src);
    $compiler->add($asm_file);
    ok( lives { $compiler->link() }, 'Linked Number Cruncher' ) or note $@;
    ok( $compiler->libname->exists,  'Library exists' );
    enjoin( $compiler->libname, 'core_version', 'fortran_add', 'asm_inc' );
};
subtest 'Polyglot: Modern Stack (C++ + Rust + Zig)' => sub {
    skip_all 'Missing compilers'         unless bin_path('g++') && bin_path('rustc') && bin_path('zig');
    skip_all 'Rust/MinGW target missing' unless check_rust_gnu();

    # C++ for ease of ABI
    my $cpp_src = $TMP_DIR->child('interface.cpp');
    $cpp_src->spew_utf8(<<~'');
        extern "C" {
        #ifdef _WIN32
        __declspec(dllexport)
        #endif
            int cpp_interface() { return 2025; }
        }


    # Rust for safety
    my $rs_src = $TMP_DIR->child('safety.rs');
    $rs_src->spew_utf8(<<~'');
        #[no_mangle]
        pub extern "C" fn rust_safe_add(a: i32, b: i32) -> i32 {
            a + b
        }


    # Zig for logic
    my $zig_src = $TMP_DIR->child('logic.zig');
    $zig_src->spew_utf8(<<~'');
        export fn zig_calc() i32 {
            return 42;
        }

    #
    my $compiler = Affix::Build->new( name => 'modern_stack', build_dir => $TMP_DIR );
    $compiler->add($cpp_src);
    $compiler->add($rs_src);
    $compiler->add($zig_src);
    ok( lives { $compiler->link() }, 'Linked Modern Stack' ) or note $@;

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

    push @reqs, $Config{cc};    # System CC
    push @reqs, ( $Config{archname} =~ /arm64/ ? $Config{cc} : 'nasm' );
    push @reqs, 'rustc';
    for my $bin (@reqs) {
        skip_all "Missing $bin" unless bin_path($bin);
    }
    skip_all 'Rust/MinGW target missing' unless check_rust_gnu();
    my $c = Affix::Build->new( name => 'mega_lib', build_dir => $TMP_DIR );
    #
    my $f1 = $TMP_DIR->child('f1.c');
    $f1->spew_utf8(<<~'');
    #ifdef _WIN32
    __declspec(dllexport)
    #endif
    int func_c( ) { return 1; }

    $c->add($f1);
    #
    my $f2 = $TMP_DIR->child('f2.cpp');
    $f2->spew_utf8(<<~'');
    extern "C" {
    #ifdef _WIN32
        __declspec(dllexport)
    #endif
        int func_cpp( ) { return 2; }
    }

    $c->add($f2);
    #
    my $f3 = $TMP_DIR->child('f3.rs');
    $f3->spew_utf8(<<~'');
    #[no_mangle]
    pub extern "C" fn func_rs( )->i32{ 3 }

    $c->add($f3);
    #
    my $f4 = $TMP_DIR->child('f4.zig');
    $f4->spew_utf8(<<~'');
    export fn func_zig() i32 { return 4; }

    $c->add($f4);
    #
    my $f5 = $TMP_DIR->child('f5.d');
    $f5->spew_utf8( ( $^O eq 'MSWin32' ? <<~'' : '' ) . <<~'' );
    import core.sys.windows.dll;
    mixin SimpleDllMain;
    export

    extern(C) int func_d() { return 5; }

    $c->add($f5);
    #
    my $f6 = $TMP_DIR->child('f6.f90');
    $f6->spew_utf8(<<~'');
    function func_f() bind(c, name='func_f')
        use iso_c_binding
        integer(c_int) :: func_f
        func_f=6
    end function

    $c->add($f6);
    #
    my $asm_ext = ( $Config{archname} =~ /arm64/ ) ? 's' : 'asm';
    my $f7      = $TMP_DIR->child("f7.$asm_ext");
    $f7->spew_utf8( ( $^O eq 'MSWin32' || $Config{archname} !~ /arm64/ ) ? <<~'' : <<~'' );
    ; x86/x64
    global func_asm
    section .text
    func_asm:
        mov eax, 7
    ret

    ; ARM64
    .global func_asm
    .text

t/025_affix_wrap.t  view on Meta::CPAN

use Path::Tiny;
use Capture::Tiny qw[capture];

# Determine if Clang is available
my $CLANG_AVAIL = do {
    my ( undef, undef, $exit ) = capture { system 'clang', '--version' };
    $exit == 0;
};

sub spew_files ( $dir, %files ) {
    $dir->child($_)->spew_utf8( $files{$_} ) for keys %files;
    $dir;
}

sub run_tests_for_driver ( $driver_class, $label ) {
    subtest 'Driver: ' . $label => sub {
        subtest 'Preprocessor & Defines' => sub {
            my $dir = Path::Tiny->tempdir;
            spew_files(
                $dir,
                'defs.h' => <<'EOF',

t/025_affix_wrap.t  view on Meta::CPAN

typedef struct { int x; } StaticStruct;
int static_func(int i);
EOF
                'main.c' => '#include "static.h"'
            );
            my $parser  = $driver_class->new( project_files => [ $dir->child('static.h')->stringify ] );
            my $binder  = Affix::Wrap->new( driver => $parser );
            my $pm_file = $dir->child('StaticLib.pm');
            $binder->generate( 'dummy_lib', 'StaticLib', $pm_file->stringify );
            ok -e $pm_file, 'Generated .pm file';
            my $content = $pm_file->slurp_utf8;
            like $content, qr/package\s+StaticLib\s*{/,                                                         'Package decl';
            like $content, qr/use constant STATIC_VAL => 42;/,                                                  'Constant generated';
            like $content, qr/typedef 'StaticStruct' => Struct\[ x => Int \];/,                                 'Struct typedef generated';
            like $content, qr/affix \$lib, ('static_func'|\[_static_func => 'static_func'\]) => \[Int\], Int;/, 'Function affix generated';

            # Syntax check
            my ( undef, undef, $exit ) = capture { system $^X, '-Ilib', '-c', $pm_file->stringify };
            is $exit >> 8, 0, 'Generated code syntax check OK';
        };
    };

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

            = $lang eq 'rust'   ? 'rs' :
            $lang eq 'csharp'   ? 'cs' :
            $lang eq 'fsharp'   ? 'fs' :
            $lang eq 'fortran'  ? 'f90' :
            $lang eq 'pascal'   ? 'pas' :
            $lang eq 'crystal'  ? 'cr' :
            $lang eq 'assembly' ? 'asm' :
            $lang eq 'cobol'    ? 'cbl' :
            $lang;
        my $src = $TMP_DIR->child("test_$lang.$ext");
        $src->spew_utf8($code);
        #
        my $c = Affix::Build->new( build_dir => $TMP_DIR, name => "${lang}_lib" );
        $c->add($src);
        try { $c->compile_and_link() }
        catch ($err) {
            skip_all 'Link failed (toolchain issue?): ' . $err;
            return;
        }
        pass 'Linked successfully';
        #

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

           PROCEDURE DIVISION USING A, B, R.
               ADD A TO B GIVING R.
               GOBACK.
           END PROGRAM add_cob.

subtest 'Polyglot: Number Cruncher (C + Fortran + ASM)' => sub {
    skip_all "Missing compilers" unless bin_path( $Config{cc} ) && bin_path('gfortran');

    # C is our orchestrator
    my $c_src = $TMP_DIR->child('math_core.c');
    $c_src->spew_utf8(<<~'C');
        #include <stdio.h>
        #ifdef _WIN32
        __declspec(dllexport)
        #endif
        int core_version() { return 1; }
        C

    # Fortran does the math
    my $f_src = $TMP_DIR->child('math_algos.f90');
    $f_src->spew_utf8(<<~'F90');
        function fortran_add(a, b) bind(c, name='fortran_add')
            use iso_c_binding
            integer(c_int), value :: a, b
            integer(c_int) :: fortran_add
            fortran_add = a + b
        end function
        F90

    # Assembly for optimization
    my $asm_bin;

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

        $asm_src       = <<~'' }
            global asm_inc
            section .text
            asm_inc:
                mov eax, edi
                inc eax
                ret

    skip_all "Missing Assembler ($asm_bin)" unless bin_path($asm_bin);
    my $asm_file = $TMP_DIR->child($asm_file_name);
    $asm_file->spew_utf8($asm_src);
    #
    my $compiler = Affix::Build->new( name => 'number_cruncher', build_dir => $TMP_DIR );
    $compiler->add($c_src);
    $compiler->add($f_src);
    $compiler->add($asm_file);
    ok( lives { $compiler->link() }, 'Linked Number Cruncher' ) or note $@;
    ok( $compiler->libname->exists,  'Library exists' );
    enjoin( $compiler->libname, 'core_version', 'fortran_add', 'asm_inc' );
};
subtest 'Polyglot: Modern Stack (C++ + Rust + Zig)' => sub {
    skip_all 'Missing compilers'         unless bin_path('g++') && bin_path('rustc') && bin_path('zig');
    skip_all 'Rust/MinGW target missing' unless check_rust_gnu();

    # C++ for ease of ABI
    my $cpp_src = $TMP_DIR->child('interface.cpp');
    $cpp_src->spew_utf8(<<~'');
        extern "C" {
        #ifdef _WIN32
        __declspec(dllexport)
        #endif
            int cpp_interface() { return 2025; }
        }


    # Rust for safety
    my $rs_src = $TMP_DIR->child('safety.rs');
    $rs_src->spew_utf8(<<~'');
        #[no_mangle]
        pub extern "C" fn rust_safe_add(a: i32, b: i32) -> i32 {
            a + b
        }


    # Zig for logic
    my $zig_src = $TMP_DIR->child('logic.zig');
    $zig_src->spew_utf8(<<~'');
        export fn zig_calc() i32 {
            return 42;
        }

    #
    my $compiler = Affix::Build->new( name => 'modern_stack', build_dir => $TMP_DIR );
    $compiler->add($cpp_src);
    $compiler->add($rs_src);
    $compiler->add($zig_src);
    ok( lives { $compiler->link() }, 'Linked Modern Stack' ) or note $@;

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

    push @reqs, $Config{cc};    # System CC
    push @reqs, ( $Config{archname} =~ /arm64/ ? $Config{cc} : 'nasm' );
    push @reqs, 'rustc';
    for my $bin (@reqs) {
        skip_all "Missing $bin" unless bin_path($bin);
    }
    skip_all 'Rust/MinGW target missing' unless check_rust_gnu();
    my $c = Affix::Build->new( name => 'mega_lib', build_dir => $TMP_DIR );
    #
    my $f1 = $TMP_DIR->child('f1.c');
    $f1->spew_utf8(<<~'');
    #ifdef _WIN32
    __declspec(dllexport)
    #endif
    int func_c( ) { return 1; }

    $c->add($f1);
    #
    my $f2 = $TMP_DIR->child('f2.cpp');
    $f2->spew_utf8(<<~'');
    extern "C" {
    #ifdef _WIN32
        __declspec(dllexport)
    #endif
        int func_cpp( ) { return 2; }
    }

    $c->add($f2);
    #
    my $f3 = $TMP_DIR->child('f3.rs');
    $f3->spew_utf8(<<~'');
    #[no_mangle]
    pub extern "C" fn func_rs( )->i32{ 3 }

    $c->add($f3);
    #
    my $f4 = $TMP_DIR->child('f4.zig');
    $f4->spew_utf8(<<~'');
    export fn func_zig() i32 { return 4; }

    $c->add($f4);
    #
    my $f5 = $TMP_DIR->child('f5.d');
    $f5->spew_utf8( ( $^O eq 'MSWin32' ? <<~'' : '' ) . <<~'' );
    import core.sys.windows.dll;
    mixin SimpleDllMain;
    export

    extern(C) int func_d() { return 5; }

    $c->add($f5);
    #
    my $f6 = $TMP_DIR->child('f6.f90');
    $f6->spew_utf8(<<~'');
    function func_f() bind(c, name='func_f')
        use iso_c_binding
        integer(c_int) :: func_f
        func_f=6
    end function

    $c->add($f6);
    #
    my $asm_ext = ( $Config{archname} =~ /arm64/ ) ? 's' : 'asm';
    my $f7      = $TMP_DIR->child("f7.$asm_ext");
    $f7->spew_utf8( ( $^O eq 'MSWin32' || $Config{archname} !~ /arm64/ ) ? <<~'' : <<~'' );
    ; x86/x64
    global func_asm
    section .text
    func_asm:
        mov eax, 7
    ret

    ; ARM64
    .global func_asm
    .text



( run in 1.972 second using v1.01-cache-2.11-cpan-39bf76dae61 )