Affix
view release on metacpan or search on metacpan
lib/Affix/Build.pm view on Meta::CPAN
package Affix::Build v1.0.9 {
use v5.40;
use experimental qw[class try];
use Config;
use Path::Tiny;
use File::Spec;
use Carp qw[croak];
use Capture::Tiny qw[capture];
use ExtUtils::MakeMaker;
use Text::ParseWords;
class Affix::Build {
# Public Parameters
field $os : param : reader //= $^O;
field $clean : param : reader //= 0;
field $build_dir : param : reader //= Path::Tiny->tempdir( CLEANUP => $clean );
field $name : param : reader //= 'affix_lib';
field $debug : param : reader //= 0;
field $version : param : reader //= ();
# Global flags applied to all compilations of that type
# cflags, cxxflags, ldflags, rustflags, etc.
field $flags : param : reader //= {};
# Internal State
field @sources;
field $libname : reader;
field $linker : reader;
# Cached Flag Arrays
field @cflags;
field @cxxflags;
field @ldflags;
field $_lib;
#
ADJUST {
my $so_ext = $Config{so} // 'so';
$build_dir = Path::Tiny->new($build_dir) unless builtin::blessed $build_dir;
# Standard convention: Windows DLLs don't need 'lib' prefix, Unix SOs do.
my $prefix = ( $os eq 'MSWin32' || $name =~ /^lib/ ) ? '' : 'lib';
my $suffix = defined $version ? ".$version" : '';
$libname = $build_dir->child("$prefix$name.$so_ext$suffix")->absolute;
# We prefer C++ drivers (g++, clang++) to handle standard libraries for mixed code (C+Rust, C+C++)
$linker = $self->_can_run(qw[g++ clang++ c++ icpx]) || $self->_can_run(qw[cc gcc clang icx cl]) || 'c++';
# Parse global flags...
@cflags = map { chomp; $_ } grep { defined && length } Text::ParseWords::parse_line( q/ /, 1, $flags->{cflags} // '' );
@cxxflags = map { chomp; $_ } grep { defined && length } Text::ParseWords::parse_line( q/ /, 1, $flags->{cxxflags} // '' );
@ldflags = map { chomp; $_ } grep { defined && length } Text::ParseWords::parse_line( q/ /, 1, $flags->{ldflags} // '' );
}
method add ( $input, %args ) {
$_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} // [];
$local_flags = [ split ' ', $local_flags ] unless builtin::reftype $local_flags eq 'ARRAY';
push @sources, { path => $path, lang => $lang, flags => $local_flags };
}
method compile_and_link () {
croak "No sources added" unless @sources;
# Check if we are mixing languages
my %langs = map { $_->{lang} => 1 } @sources;
if ( ( scalar keys %langs ) > 1 ) {
return $self->_strategy_polyglot();
}
return $_lib = $self->_strategy_native();
}
method link { $_lib //= $self->compile_and_link(); $_lib }
# Used when only one language is present. We delegate the entire build process
# to that language's compiler to produce the final shared library.
method _strategy_native () {
my $src = $sources[0];
my $l = $src->{lang};
my $handler = $self->_resolve_handler($l);
return $self->$handler( $src, $libname, 'dynamic' );
( run in 1.400 second using v1.01-cache-2.11-cpan-39bf76dae61 )