Affix
view release on metacpan or search on metacpan
builder/Affix/Builder.pm view on Meta::CPAN
# Based on Module::Build::Tiny which is copyright (c) 2011 by Leon Timmermans, David Golden.
# Module::Build::Tiny is free software; you can redistribute it and/or modify it under
# the same terms as the Perl 5 programming language system itself.
use v5.40;
use feature 'class';
no warnings 'experimental::class';
class #
Affix::Builder {
use CPAN::Meta;
use ExtUtils::Install qw[pm_to_blib install];
use ExtUtils::InstallPaths 0.002;
use File::Basename qw[basename dirname];
use File::Path qw[make_path remove_tree];
use File::Spec::Functions qw[catfile catdir rel2abs abs2rel splitdir curdir];
use JSON::PP 2 qw[encode_json decode_json];
use File::Temp qw[tempfile];
# Not in CORE
use Path::Tiny qw[path cwd];
use ExtUtils::Helpers 0.028 qw[make_executable split_like_shell detildefy];
# infix and Affix stuff
use Config qw[%Config];
field $force : param //= 0;
field $debug : param //= 0;
field $libver;
field $cflags;
field $ldflags;
field $cppver = 'c++17'; # https://en.wikipedia.org/wiki/C%2B%2B20#Compiler_support
field $cver = 'c17'; # https://en.wikipedia.org/wiki/C17_(C_standard_revision)
field $make : param //= $Config{make};
#
field $action : param //= 'build';
field $meta : reader = CPAN::Meta->load_file('META.json');
# Params to Build script
field $install_base : param //= '';
field $installdirs : param //= '';
field $uninst : param //= 0; # Make more sense to have a ./Build uninstall command but...
field $install_paths : param //= ExtUtils::InstallPaths->new( dist_name => $meta->name );
field $verbose : param(v) //= 0;
field $dry_run : param //= 0;
field $pureperl : param //= 0;
field $jobs : param //= 1;
field $destdir : param //= '';
field $prefix : param //= '';
#
ADJUST {
-e 'META.json' or die "No META information provided\n";
# Configure Flags
my $is_bsd = $^O =~ /bsd/i;
my $is_win = $^O =~ /MSWin32/i;
$cflags = $is_bsd ? '' : '-fPIC ';
$ldflags = $is_bsd ? '' : ' -flto=auto ';
if ( $debug > 0 ) {
$cflags
.= '-DDEBUG=' .
$debug .
' -g3 -gdwarf-4 ' .
' -Wno-deprecated -pipe ' .
' -Wall -Wextra -Wpedantic -Wvla -Wnull-dereference ' .
' -Wswitch-enum -Wduplicated-cond ' .
' -Wduplicated-branches';
$cflags .= ' -fvar-tracking-assignments' unless $Config{osname} eq 'darwin';
}
elsif ( !$is_win ) {
$cflags
.= ' -DNDEBUG -DBOOST_DISABLE_ASSERTS -O3 -ftree-vectorize -ffast-math -fno-align-functions -fno-align-loops -fno-omit-frame-pointer -flto';
}
# 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]) );
make_executable($_) for values %scripts;
make_path( catdir(qw[blib arch]), { chmod => 0755, verbose => $verbose } );
0;
}
method _clean_objects() {
my $lib_dir = path('lib');
my @objs;
$lib_dir->visit(
sub ( $path, $state ) {
push @objs, $path if $path->is_file && $path =~ /\.(?:o|obj)\z/i;
},
{ recurse => 1 }
);
remove_tree( $_, { verbose => $verbose } ) for @objs;
0;
}
method step_clean() {
remove_tree( $_, { verbose => $verbose } ) for qw[blib temp];
$self->_clean_objects;
0;
}
method step_install() {
$self->step_build() unless -d 'blib';
my %res;
install(
[ from_to => $install_paths->install_map,
verbose => $verbose,
builder/Affix/Builder.pm view on Meta::CPAN
}
# Detects if linking against librt is required (common on Linux/BSD/Solaris for shm_open)
method check_for_lrt() {
return '' if $^O eq 'MSWin32';
warn "Checking if -lrt is required...\n" if $verbose;
my $cc = $Config{cc} || 'cc';
my $test_code = <<'END_C';
#include <sys/mman.h>
#include <fcntl.h>
int main(void) { shm_open("/test", O_RDONLY, 0); return 0; }
END_C
my ( $fh, $src ) = tempfile( SUFFIX => '.c', UNLINK => 1 );
print $fh $test_code;
close $fh;
my ( $ofh, $out ) = tempfile( UNLINK => 1 );
close $ofh;
# Try without -lrt (list-form system to avoid shell injection)
open( my $devnull, '>', '/dev/null' ) if $^O ne 'MSWin32';
my $old_stdout = select $devnull if $devnull;
system( $cc, '-o', $out, $src );
select $old_stdout if $old_stdout;
close $devnull if $devnull;
return '' if $? == 0;
# Try with -lrt
open( $devnull, '>', '/dev/null' ) if $^O ne 'MSWin32';
$old_stdout = select $devnull if $devnull;
system( $cc, '-o', $out, $src, '-lrt' );
select $old_stdout if $old_stdout;
close $devnull if $devnull;
return '-lrt' if $? == 0;
return '';
}
sub command_exists {
my ($cmd) = @_;
if ( $Config{osname} eq 'MSWin32' ) {
return system( 'where', $cmd ) == 0;
}
else {
return system( 'command', '-v', $cmd ) == 0;
}
}
method step_affix {
$self->step_infix;
my $cwd = cwd->absolute;
my @objs;
require ExtUtils::CBuilder;
my %config = %Config;
# ExtUtils::CBuilder only uses $Config{ccflags} and silently drops
# ccflags_uselargefiles, which Configure keeps separate on Solaris/
# illumos (and a few other platforms). Without those defines the system
# headers do not expose off64_t, sigjmp_buf, alloca or fileno, so the
# same source that perl itself builds fails to compile here. Merge them
# in (harmless duplication when ccflags already contains them).
$config{ccflags} = join ' ', grep {length} $config{ccflags}, $config{ccflags_uselargefiles};
if ($debug) {
$config{ldflags} =~ s/-s //g;
$config{ldflags} =~ s/ -s//g;
$config{lddlflags} =~ s/-s //g;
$config{lddlflags} =~ s/ -s//g;
}
my $builder = ExtUtils::CBuilder->new( quiet => !$verbose, config => \%config );
my $pre = $cwd->child(qw[blib arch auto])->absolute;
require DynaLoader;
my $mod2fname = defined &DynaLoader::mod2fname ? \&DynaLoader::mod2fname : sub { return $_[0][-1] };
my @parts = ('Affix');
my $archdir = rel2abs catdir( curdir, qw[. blib arch auto], @parts );
my $err;
make_path( $archdir, { chmod => 0755, error => \$err, verbose => $verbose } );
my $lib_file = catfile( $archdir, $mod2fname->( \@parts ) . '.' . $Config{dlext} );
my @dirs;
push @dirs, '../';
my $has_cxx = !1;
my $recompiled = 0;
my @sources = $cwd->child('lib/Affix.c');
#~ warn "Sources to process: @sources\n";
for my $source (@sources) {
#~ warn "Processing source: $source\n";
my $cxx = $source =~ /cx+$/;
my $file_base = $source->basename(qr[.c$]);
my $tempdir = path('lib');
$tempdir->mkdir( { verbose => $verbose, mode => oct '755' } );
my $version = $meta->version;
my $obj = $builder->object_file($source);
#~ warn "Checking obj: $obj\n";
# Check mtimes of all .c and .h files under lib/ (includes Affix.c, marshal.c, Affix.h)
my $newest_dep = $source->stat->mtime;
my $iter = path('lib')->iterator;
while ( my $entry = $iter->() ) {
next unless $entry->is_file;
next unless $entry =~ /\.[ch]$/;
my $dep_mtime = $entry->stat->mtime;
$newest_dep = $dep_mtime if $dep_mtime > $newest_dep;
}
my $should_compile
= ( $force ||
( !-f $obj ) ||
( $newest_dep >= path($obj)->stat->mtime ) ||
( path(__FILE__)->stat->mtime > path($obj)->stat->mtime ) );
if ($should_compile) {
my $reason
= !-f $obj ? 'object file missing' :
$newest_dep >= path($obj)->stat->mtime ? 'source newer than object' :
path(__FILE__)->stat->mtime > path($obj)->stat->mtime ? 'builder changed' :
'forced';
warn "Compiling $source ($reason)\n";
$recompiled = 1;
}
push @dirs, $source->dirname();
$has_cxx = 1 if $cxx;
push @objs,
$should_compile ?
$builder->compile(
quiet => 0,
'C++' => $cxx,
source => $source->stringify,
defines => { VERSION => qq/"$version"/, XS_VERSION => qq/"$version"/ },
include_dirs => [
cwd->stringify, cwd->child('infix')->realpath->stringify,
cwd->child('infix')->child('include')->realpath->stringify, cwd->child('infix')->child('src')->realpath->stringify,
$source->dirname, $pre->child( $meta->name, 'include' )->stringify
],
extra_compiler_flags =>
( '-fPIC -std=' . ( $cxx ? $cppver : $cver ) . ' ' . $cflags . ( $debug ? ' -ggdb3 -g -Wall -Wextra -pedantic' : '' ) )
) :
$obj;
}
# Point to the Architecture-specific build lib
my $infix_build_lib = cwd->absolute->child('infix')->child( 'build_lib', $Config{archname} )->stringify;
# Check for -lrt requirement
my $lrt_flag = $self->check_for_lrt();
my $data = {
# Removed incorrect -lstdc++ logic. Added -lm for math.
# -pthread is already in $ldflags via ADJUST
extra_linker_flags =>
[ split( ' ', $ldflags ), "-L$infix_build_lib", '-linfix', ( $lrt_flag ? ( split( ' ', $lrt_flag ) ) : () ), '-lm' ],
objects => [@objs],
lib_file => $lib_file,
module_name => join '::',
@parts
};
warn "Linking $lib_file\n" if $recompiled;
return $builder->link(%$data);
}
};
1;
( run in 1.359 second using v1.01-cache-2.11-cpan-f9ab5d97e31 )