Affix
view release on metacpan or search on metacpan
t/017_affix_build.t view on Meta::CPAN
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';
#
my $lib = $c->libname;
ok $lib->exists, 'Library created: ' . $lib->basename;
#
my $dll = DynaLoader::dl_load_file( "$lib", 0 );
if ($dll) {
if ( DynaLoader::dl_find_symbol( $dll, $sym ) ) {
pass("Symbol '$sym' found");
}
else {
fail("Symbol '$sym' NOT found in lib");
}
# Attempt unload
DynaLoader::dl_unload_file($dll) if ( $^O eq 'MSWin32' ? $lang ne 'go' : 0 ) && defined &DynaLoader::dl_unload_file;
}
else {
diag( "Load failed: " . DynaLoader::dl_error() );
}
#
ok my $fn = wrap( $lib, $sym, [ Int32, Int32 ], Int32 ), 'wrap';
is $fn->( 3, 7 ), 10, 'call';
};
}
#
run_test( 'c', 'C', <<~'', 'add_c', 'cc' );
#include <stdio.h>
#ifdef _WIN32
__declspec(dllexport)
#endif
int add_c(int a, int b) {
return a + b;
}
run_test( 'cpp', 'C++', <<~'', 'add_cpp', 'c++' );
#ifdef _WIN32
#define EXPORT __declspec(dllexport)
#else
#define EXPORT
#endif
extern "C" {
EXPORT int add_cpp(int a, int b) {
return a + b;
}
}
run_test( 'csharp', 'C#', <<~'', 'add_cs', 'dotnet', \&check_dotnet );
using System.Runtime.InteropServices;
namespace T {
public class C {
[UnmanagedCallersOnly(EntryPoint="add_cs")]
public static int Add(int a, int b) => a + b;
}
}
run_test( 'rust', 'Rust', <<~'', 'add_rs', 'rustc' );
#[no_mangle]
pub extern "C" fn add_rs(a: i32, b: i32) -> i32 {
a + b
}
run_test( 'go', 'Go', <<~'', 'add_go', 'go' );
package main
import "C"
//export add_go
func add_go(a, b C.int) C.int {
return a + b
}
func main() { }
run_test( 'zig', 'Zig', <<~'', 'add_zig', 'zig' );
export fn add_zig(a: i32, b: i32) i32 {
return a + b;
}
# Windows DLLs in D need an entry point mixin
run_test( 'd', 'D', ( $^O eq 'MSWin32' ? <<~'' : '' ) . <<~'', 'add_d', 'dmd' );
import core.sys.windows.dll;
mixin SimpleDllMain;
export
extern(C) int add_d(int a, int b) { return a + b; }
run_test( 'odin', 'Odin', <<~'', 'add_odin', 'odin' );
package main
@(export)
add_odin :: proc "c" (a, b: i32) -> i32 {
return a + b
}
run_test( 'fortran', 'Fortran', <<~'', 'add_f', 'gfortran' );
function add_f(a, b) bind(c, name='add_f')
use iso_c_binding
integer(c_int), value :: a, b
integer(c_int) :: add_f
add_f = a + b
end function
run_test( 'nim', 'Nim', <<~'', 'add_nim', 'nim' );
proc add_nim(a, b: cint): cint {.exportc, dynlib.} =
return a + b
run_test( 'v', 'V', <<~'', 'add_v', 'v' );
[export: 'add_v']
fn add_v(a int, b int) int {
return a + b
}
run_test( 'pascal', 'Pascal', <<~'', 'add_pas', 'fpc' );
library test_pas;
function add_pas(a, b: LongInt): LongInt; cdecl; export;
begin
add_pas := a + b;
end;
exports add_pas;
begin end.
run_test( 'cr', 'Crystal', <<~'', 'add_cr', 'crystal' );
fun add_cr(a : Int32, b : Int32) : Int32
a + b
end
run_test( 'swift', 'Swift', <<~'', 'add_swift', 'swiftc' );
@_cdecl("add_swift")
public func add_swift(a: Int32, b: Int32) -> Int32 {
return a + b
}
run_test( 'assembly', 'Assembly', $Config{archname} =~ /arm64|aarch64/ ? <<~'' : $^O eq 'MSWin32' ? <<~'': <<~'', 'add_asm', 'nasm' );
; ARM64: add w0, w0, w1
.global add_asm
.text
.align 2
add_asm:
add w0, w0, w1
ret
; Win64 x86_64: RCX + RDX -> RAX
global add_asm
section .text
add_asm:
mov eax, ecx
add eax, edx
ret
; SysV x86_64: RDI + RSI -> RAX
global add_asm
section .text
add_asm:
mov eax, edi
add eax, esi
ret
run_test( 'cobol', 'Cobol', <<~'', 'add_cob', 'cobc' );
IDENTIFICATION DIVISION.
PROGRAM-ID. add_cob.
DATA DIVISION.
LINKAGE SECTION.
01 A PIC 9(9) USAGE COMP-5.
01 B PIC 9(9) USAGE COMP-5.
01 R PIC 9(9) USAGE COMP-5.
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
( run in 2.826 seconds using v1.01-cache-2.11-cpan-5c0b1e786e0 )