MarpaX-ESLIF
view release on metacpan or search on metacpan
etc/compile_marpaESLIF.pl view on Meta::CPAN
# directory that is first purged.
#
# Eventual extra includes are generated in inc/include directory.
#
# Object files are in objs directory
#
# Library files are in libs directory
#
my $have_cppguess;
BEGIN {
use File::Spec; # Formally it is not necessary I believe to do it here
# Make sure we have our 'inc' directory prepended the perl search path
my $inc_dir = File::Spec->catdir(File::Spec->curdir, 'inc');
unshift(@INC, $inc_dir);
#
# ExtUtils::CppGuess does not install everywhere.
# This is why we provide it explicitely, we are ok if it fails at run-time
# by enclosing its usage in try/catch
#
$have_cppguess = eval 'use ExtUtils::CppGuess 0.26; 1;';
}
use Archive::Tar;
use Carp qw/croak/;
use Config;
use Config::AutoConf;
use Cwd qw/abs_path/;
use ExtUtils::CBuilder 0.280224; # 0.280224 is to make sure we have the support of $ENV{CXX};
use File::chdir;
use File::Basename;
use File::Copy;
use File::Find;
use File::Path qw/make_path remove_tree/;
use File::Spec;
use File::Which;
use File::Temp;
use IO::Handle;
use Perl::OSType qw/is_os_type/;
use POSIX qw/EXIT_SUCCESS/;
use Try::Tiny;
our $EXTRA_INCLUDE_DIR = File::Spec->catdir('inc', 'include');
our $CONFIG_H = File::Spec->catfile($EXTRA_INCLUDE_DIR, 'marpaESLIFPerl_autoconf.h'); # The file that we generate
our $EXTRACT_DIR = 'extract';
our $TARBALLS_DIR = File::Spec->catdir('etc', 'tarballs');
our $OBJS_DIR = 'objs';
our $IS_WINDOWS = is_os_type('Windows');
$| = 1;
#
# Our distribution have both C and CPP files, and we want to make sure that modifying
# CFLAGS will not affect cpp files. Since we require a version of ExtUtils::CBuilder
# that support the environment variables, explicitely setting the environment variables
# from default ExtUtils::Cbuilder will ensure cc and cpp settings will become independant
# if we are doing to modify any of them.
# We do that for linker settings as well for coherency although we will NEVER touch them.
# OTHERLDFLAGS will be specific to this makefile.
#
# Take care: with ExtUtils::CBuilder, $ENV{CFLAGS} and $ENV{LDFLAGS} are appended to default perl compile flags, not the others
#
#
my %cbuilder_config = ExtUtils::CBuilder->new()->get_config;
$ENV{CC} = $cbuilder_config{cc} // 'cc';
$ENV{CFLAGS} //= '';
$ENV{CFLAGS} .= ' -DNDEBUG -DNTRACE';
$ENV{CXX} = $cbuilder_config{cxx} // $ENV{CC};
$ENV{CXXFLAGS} = $cbuilder_config{cxxflags} // $cbuilder_config{ccflags} // '';
$ENV{LD} = $cbuilder_config{ld} // $ENV{CC};
$ENV{LDFLAGS} //= '';
my @OTHERLDFLAGS = ();
my $optimize = '';
print "==========================================\n";
print "Original compilers and linker settings as per ExtUtils::CBuilder\n";
print "\n";
print "CC (overwrite) $ENV{CC}\n";
print "CFLAGS ( fixed) " . ($cbuilder_config{ccflags} // '') . "\n";
print "CFLAGS ( append) $ENV{CFLAGS}\n";
print "CXX (overwrite) $ENV{CXX}\n";
print "CXXFLAGS (overwrite) $ENV{CXXFLAGS}\n";
print "LD (overwrite) $ENV{LD}\n";
print "LDFLAGS ( fixed) " . ($cbuilder_config{ldflags} // '') . "\n";
print "LDFLAGS ( append) $ENV{LDFLAGS}\n";
print "==========================================\n";
print "\n";
my $ac = Config::AutoConf->new();
# goto jdd;
$ac->check_cc;
#
# Guess CXX configuration
#
# Sun C compiler is a special case, we know that guess_compiler will always get it wrong
#
my $sunc = 0;
my $is_gnu = check_compiler_is_gnu($ac);
my $is_clang = check_compiler_is_clang($ac);
$ac->msg_checking(sprintf "if this is Sun C compiler");
if ($ac->link_if_else("#ifdef __SUNPRO_C\n#else\n#error \"this is not Sun C compiler\"\n#endif\nint main() { return 0; }")) {
$ac->msg_result('yes');
my $cc = which($ENV{CC}) || '';
if (! $cc) {
#
# Should never happen since we checked that the compiler works
#
$ac->msg_notice("Warning! Sun C compiler working but which() on its location returned false !?");
} else {
#
# $cc should be a full path
#
$cc = abs_path($cc);
my $ccdir = dirname($cc) || File::Spec->curdir();
#
# We always give precedence to CC that should be at the same location of the C compiler
#
my $cxx = File::Spec->catfile($ccdir, 'CC');
if (! which($cxx)) {
#
# No CC at the same location?
#
$ac->msg_notice("Warning! Sun C compiler detected but no CC found at the same location - trying with default search path");
$cxx = 'CC';
} else {
#
# Could it be that this CC is also the one that is, eventually, in the path?
#
my $cxxfromPATH = which('CC') || '';
if ($cxxfromPATH) {
$cxxfromPATH = abs_path($cxxfromPATH);
my $cxxfromWhich = abs_path($cxx);
if ($cxxfromWhich eq $cxxfromPATH) {
$ac->msg_notice("Sun C compiler detected and its CC counterpart is already in the search path");
$cxx = 'CC';
}
}
}
if (which($cxx)) {
$ac->msg_notice("Forcing CXX to $cxx");
$ENV{CXX} = $cxx;
#
# We got "CC" executable - no need of eventual -x c++ that perl may have add
#
if ($ENV{CXXFLAGS} =~ s/\-x\s+c\+\+\s*//) {
etc/compile_marpaESLIF.pl view on Meta::CPAN
if (try_compile("#include <stdlib.h>\nint main() {\n exit(0);\n}\n", { extra_compiler_flags => $flag })) {
$ac->msg_result('yes');
$optimize = $flag;
last;
} else {
$ac->msg_result('no');
}
}
} else {
#
# Some versions of gcc may not yell with bad options unless -Werror is set.
# Check that flag and set it temporarly.
#
my $tmpflag = '-Werror';
$ac->msg_checking("if flag $tmpflag works:");
if (try_compile("#include <stdlib.h>\nint main() {\n exit(0);\n}\n", { extra_compiler_flags => $tmpflag })) {
$ac->msg_result('yes');
$has_Werror = 1;
} else {
$ac->msg_result('no');
$tmpflag = '';
}
#
# We test AIX case first because it overlaps with general O3
#
my @flag_candidates = ();
if ($sunc) {
push(@flag_candidates, "-xO3"); # CC
} elsif ($is_gnu || $is_clang) {
push(@flag_candidates, "-O3"); # gcc, clang
} else {
push(@flag_candidates, "-O3 -qstrict"); # xlc maybe ?
push(@flag_candidates, "-O3"); # Others
}
foreach my $flag (@flag_candidates) {
$ac->msg_checking("if flag $flag works:");
if (try_compile("#include <stdlib.h>\nint main() {\n exit(0);\n}\n", { extra_compiler_flags => "$tmpflag $flag" })) {
$ac->msg_result('yes');
$optimize = $flag;
last;
} else {
$ac->msg_result('no');
}
}
}
}
}
my $OTHERLDFLAGS = join(' ', @OTHERLDFLAGS);
print "\n";
print "==========================================\n";
print "Tweaked compilers and linker settings\n";
print "\n";
print "CC (overwrite) $ENV{CC}\n";
print "CFLAGS ( fixed) " . ($cbuilder_config{ccflags} // '') . "\n";
print "CFLAGS ( append) $ENV{CFLAGS}\n";
print "CXX (overwrite) $ENV{CXX}\n";
print "CXXFLAGS (overwrite) $ENV{CXXFLAGS}\n";
print "LD (overwrite) $ENV{LD}\n";
print "LDFLAGS ( fixed) " . ($cbuilder_config{ldflags} // '') . "\n";
print "LDFLAGS ( append) $ENV{LDFLAGS}\n";
print "OTHERLDFLAGS $OTHERLDFLAGS\n";
print "==========================================\n";
print "\n";
my %HAVE_HEADERS = ();
$ac->check_all_headers(
qw{
ctype.h
dlfcn.h
errno.h
fcntl.h
features.h
float.h
inttypes.h
io.h
langinfo.h
limits.h
locale.h
math.h
memory.h
poll.h
process.h
pwd.h
regex.h
signal.h
stdarg.h
stddef.h
stdint.h
stdio.h
stdlib.h
string.h
strings.h
sys/inttypes.h
sys/stat.h
sys/stdint.h
sys/time.h
sys/types.h
time.h
unistd.h
utime.h
wchar.h
wctype.h
windows.h
}, { action_on_header_true => sub { my $header = shift; $HAVE_HEADERS{$header} = 1 } } );
#
# Private extra checks that Config::AutoConf::INI cannot do
#
check_math($ac);
check_ebcdic($ac);
check_inline($ac);
check_forceinline($ac);
check_va_copy($ac);
check_vsnprintf($ac);
check_fileno($ac);
check_localtime_r($ac);
check_write($ac);
check_log2($ac);
check_log2f($ac);
my $char_bit = check_CHAR_BIT($ac);
check_strtold($ac);
etc/compile_marpaESLIF.pl view on Meta::CPAN
#
# Write config file
#
print "Generating $CONFIG_H\n";
$ac->write_config_h($CONFIG_H);
$ac->msg_notice("Append -I$EXTRA_INCLUDE_DIR to compile flags");
$ENV{CFLAGS} .= " -I$EXTRA_INCLUDE_DIR";
$ENV{CXXFLAGS} .= " -I$EXTRA_INCLUDE_DIR";
#
# Generate extra headers eventually
#
if (! $HAVE_HEADERS{"stdint.h"}) {
configure_file($ac, File::Spec->catfile('etc', 'stdint.h.in'), File::Spec->catfile($EXTRA_INCLUDE_DIR, 'stdint.h'));
}
if (! $HAVE_HEADERS{"inttypes.h"}) {
configure_file($ac, File::Spec->catfile('etc', 'inttypes.h.in'), File::Spec->catfile($EXTRA_INCLUDE_DIR, 'inttypes.h'));
}
#
# General flags that we always set
#
foreach my $flag (qw/_REENTRANT _THREAD_SAFE/) {
$ac->msg_notice("Append $flag to compile flags");
$ENV{CFLAGS} .= " -D$flag";
$ENV{CXXFLAGS} .= " -D$flag";
}
#
# Specific flags for cl
#
if ($ENV{CC} =~ /\bcl\b/) {
foreach my $flag (qw/WIN32_LEAN_AND_MEAN CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE/) {
$ac->msg_notice("Append $flag to compile flags");
$ENV{CFLAGS} .= " -D$flag";
$ENV{CXXFLAGS} .= " -D$flag";
}
}
#
# Extract and process tarballs in an order that we know in advance
#
sub get_object_file {
my ($source) = @_;
return File::Spec->catfile($OBJS_DIR, sprintf("%s.o", basename($source)));
}
process_genericLogger($ac);
process_tconv($ac);
process_genericStack($ac);
process_genericHash($ac);
process_genericSparseArray($ac);
process_marpaWrapper($ac);
process_marpaESLIF($ac);
#
# Write LDFLAGS and OTHERLDFLAGS to OTHERLDFLAGS.txt
#
my $otherldflags = 'OTHERLDFLAGS.txt';
open(my $otherldflags_fd, '>', $otherldflags) || die "Cannot open $otherldflags, $!";
foreach (@OTHERLDFLAGS) {
print $otherldflags_fd "$_\n";
}
print $otherldflags_fd "$ENV{LDFLAGS}\n";
close($otherldflags_fd) || warn "Cannot close $otherldflags, $!";
#
# Write CFLAGS to CFLAGS.txt
#
my $cflags = 'CFLAGS.txt';
open(my $cflags_fd, '>', $cflags) || die "Cannot open $cflags, $!";
print $cflags_fd "$ENV{CFLAGS}\n";
close($cflags_fd) || warn "Cannot close $cflags, $!";
exit(EXIT_SUCCESS);
sub guess_compiler {
my ($ac) = @_;
my $guesser = ExtUtils::CppGuess->new(cc => $ENV{CC});
#
# We work quite like Module::Build in the sense that we are appending
# flags.
#
my %module_build_options = $guesser->module_build_options;
my $cxx_guess = $module_build_options{config}->{cc} // '';
my $extra_cxxflags_guess = $module_build_options{extra_compiler_flags} // '';
my $extra_ldflags_guess = $module_build_options{extra_linker_flags} // '';
$ac->msg_notice("ExtUtils::CppGuess says \$cxx_guess=$cxx_guess, \$extra_cxxflags_guess=$extra_cxxflags_guess, \$extra_ldflags_guess=$extra_ldflags_guess");
return ($cxx_guess, $extra_cxxflags_guess, $extra_ldflags_guess);
}
sub try_compile {
no warnings 'once';
my ($csource, $options) = @_;
$options //= {};
my $extra_compiler_flags = $options->{extra_compiler_flags};
my $link = $options->{link} // 0;
my $run = $options->{run} // 0;
my $cbuilder_extra_config = $options->{cbuilder_extra_config};
my $output_ref = $options->{output_ref};
my $silent = $options->{silent} // $ENV{COMPILE_MARPAESLIF_SILENT} // 1;
my $quiet = $options->{quiet} // $ENV{COMPILE_MARPAESLIF_QUIET} // 1;
my $compile_error_is_fatal = $options->{compile_error_is_fatal} // 0;
my $link_error_is_fatal = $options->{link_error_is_fatal} // 0;
my $run_error_is_fatal = $options->{run_error_is_fatal} // 0;
my $cplusplus = $options->{'C++'} // 0;
my $stderr_and_stdout_txt = "stderr_and_stdout.txt";
#
# We do not want to be polluted in any case, redirect stdout and stderr
# to the same output using method as per perlfunc open
#
open(my $oldout, ">&STDOUT") or die "Can't dup STDOUT: $!";
open(OLDERR, ">&", \*STDERR) or die "Can't dup STDERR: $!";
if ($silent) {
open(STDOUT, '>', $stderr_and_stdout_txt) or die "Can't redirect STDOUT: $!";
open(STDERR, ">&STDOUT") or die "Can't dup STDOUT: $!";
select STDERR; $| = 1; # make unbuffered
select STDOUT; $| = 1; # make unbuffered
}
etc/compile_marpaESLIF.pl view on Meta::CPAN
if ($exe_file) {
unlink($exe_file);
}
};
unlink $fh->filename;
open(STDOUT, ">&", $oldout) or die "Can't dup \$oldout: $!";
open(STDERR, ">&OLDERR") or die "Can't dup OLDERR: $!";
unlink $stderr_and_stdout_txt;
if ($have_compile_error && $compile_error_is_fatal) {
die "Compilation error and this is fatal";
}
if ($have_link_error && $link_error_is_fatal) {
die "Link error and this is fatal";
}
if ($have_run_error && $run_error_is_fatal) {
die "Run error and this is fatal";
}
return $rc;
}
sub try_link {
my ($csource, $options) = @_;
$options //= {};
return try_compile($csource, { %$options, link => 1 });
}
sub try_run {
my ($csource, $options) = @_;
$options //= {};
return try_compile($csource, { %$options, link => 1, run => 1 });
}
sub try_output {
my ($csource, $output_ref, $options) = @_;
$options //= {};
return try_compile($csource, { %$options, link => 1, run => 1, output_ref => $output_ref });
}
sub check_math {
my ($ac) = @_;
#
# log/exp and math lib
#
my $lm = $ac->check_lm() // '';
$ac->msg_checking("for math library:");
if($lm) {
$ac->msg_result("$lm");
$ac->search_libs('log', $lm, { action_on_true => $ac->define_var("HAVE_LOG", 1) });
$ac->search_libs('exp', $lm, { action_on_true => $ac->define_var("HAVE_EXP", 1) });
$ac->msg_notice("Append -l$lm to LDFLAGS");
$ENV{LDFLAGS} .= " -l$lm";
} else {
$ac->msg_result("not needed");
$ac->search_libs('log', { action_on_true => $ac->define_var("HAVE_LOG", 1) });
$ac->search_libs('exp', { action_on_true => $ac->define_var("HAVE_EXP", 1) });
}
}
sub check_ebcdic {
my ($ac) = @_;
#
# EBCDIC (We could have used $Config{ebcdic} as well
# --------------------------------------------------
$ac->msg_checking("EBCDIC");
my $prologue = <<PROLOGUE;
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
PROLOGUE
my $body = <<BODY;
if ('M'==0xd4) {
exit(0);
} else {
exit(1);
}
BODY
my $program = $ac->lang_build_program($prologue, $body);
if (try_run($program)) {
$ac->msg_result("yes");
$ac->define_var("EBCDIC", 1)
} else {
$ac->msg_result("no");
}
}
sub check_inline {
my ($ac) = @_;
foreach my $value (qw/inline __inline__ inline__ __inline/) {
$ac->msg_checking($value);
my $prologue = <<PROLOGUE;
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
typedef int foo_t;
static $value foo_t static_foo() {
return 0;
}
foo_t foo() {
return 0;
}
PROLOGUE
my $program = $ac->lang_build_program($prologue);
if (try_run($program)) {
$ac->msg_result("yes");
$ac->define_var("C_INLINE", $value);
if ($value eq 'inline') {
$ac->define_var("C_INLINE_IS_INLINE", 1);
}
last;
( run in 0.714 second using v1.01-cache-2.11-cpan-364913b4093 )