Permalink
Fetching contributors…
Cannot retrieve contributors at this time
executable file 362 lines (317 sloc) 9.28 KB
#!/usr/bin/env perl
use strict;
use File::Temp qw(tempfile tempdir);
use File::Spec::Functions qw(rel2abs);
use File::Basename;
use Getopt::Long;
my @exts = qw(base64 curl gcrypt inflect json markdown mysql socket posix);
my @required_exts = qw();
my @sapis = qw(cli);
our @lib_dirs;
our $path = dirname(rel2abs($0));
our $CFLAGS = "";
our $LDFLAGS = "";
our $prefix = "/usr/local";
sub error {
my $message = shift;
print "\n\e[31m$message\n\e[0m";
die;
};
sub warning {
my $message = shift;
print "\n\e[33m$message\n\e[0m";
};
sub success {
my $message = shift;
print "\n\e[32m$message\n\e[0m";
};
sub help {
print "usage: ./configure <opts>\n";
print " --with-lib-dir=DIR : search DIR for libraries\n";
print " --debug : enable a debug build\n";
print " --profile : enable a profiled build\n";
print " --coverage : enable code coverage\n";
print " --prefix=PREFIX : install into PREFIX\n";
print " --cflags=FLAGS : pass FLAGS to the compiler\n";
print " --ldflags=FLAGS : pass FLAGS to the linker\n";
print " --vanilla : build without any extensions or SAPIs\n";
print " --ext=EXTENSION : enable EXTENSION\n";
print " --no-ext=EXTENSION : disable EXTENSION\n";
print " --sapi=SAPI : enable SAPI\n";
print " --no-sapi=SAPI : disable SAPI\n";
print " --help : print this help\n";
}
exit 1 unless GetOptions "with-lib-dir=s" => sub { push @lib_dirs, $_[1] },
"debug" => \my $debug,
"profile" => \my $profile,
"coverage" => \my $coverage,
"verbose" => \my $verbose,
"prefix=s" => \$prefix,
"cflags=s" => \$CFLAGS,
"ldflags=s" => \$LDFLAGS,
"vanilla" => sub { @exts = (); @sapis = () },
"ext=s" => sub {
my $ext = $_[1];
error "Unknown extension $ext" unless -d "ext/$ext";
push @exts, $ext;
push @required_exts, $ext;
},
"no-ext=s" => sub {
my $ext = $_[1];
@exts = grep { $_ ne $ext } @exts;
},
"sapi=s" => sub {
my $sapi = $_[1];
error "Unknown SAPI $sapi" unless -d "sapi/$sapi";
push @sapis, $sapi;
},
"no-sapi=s" => sub {
my $sapi = $_[1];
@sapis = grep { $_ ne $sapi } @sapis;
},
"help" => sub {
help;
exit 0;
};
for(@lib_dirs) {
$CFLAGS .= " -I$_/include";
$LDFLAGS .= " -L$_/lib";
}
if($profile) {
$CFLAGS .= " -pg";
}
if($coverage) {
$CFLAGS .= " -fprofile-arcs -ftest-coverage"
}
if($debug) {
$CFLAGS .= " -g -DSL_DEBUG";
} else {
$CFLAGS .= " -O3";
}
sub compile {
my ($flags, $src) = @_;
my ($fh, $filename) = tempfile SUFFIX => ".c";
my $binary = $filename;
$binary =~ s/\.c$//;
print $fh $src;
close $fh;
my $command = "$ENV{CC} $CFLAGS $LDFLAGS $flags -o $binary $filename $flags 2>&1";
print "% $command\n" if $verbose;
my $output = `$command`;
print $output if $verbose;
chomp $output;
$? == 0;
};
sub check_lib {
my ($lib, $src, %opts) = @_;
print "Checking for lib$lib... ";
if(compile "-l$lib", $src) {
$LDFLAGS .= " -l$lib" unless $opts{skip_ldflag};
print "ok\n";
} else {
# some libraries (eg. iconv) are rolled into libc on some systems. see if we can compile without the -liconv switch
if(compile "", $src) {
print "ok\n";
} else {
# nope
print "failed\n";
error "Could not find lib$lib (used -l$lib)\nPlease make sure it is available before building Slash";
}
}
};
sub check_header {
my ($header) = @_;
print "Checking for $header...";
my $src = <<C
#include <$header>
int main() {
return 0;
}
C
;
if(compile "", $src) {
print "ok\n";
} else {
print "failed\n";
error "Could not find $header\nPlease make sure it is available before building Slash";
}
}
sub check_prog {
my ($cmd, $expect) = @_;
my ($prog) = split / /, $cmd;
print "Checking for $prog... ";
($_) = `$cmd 2>&1`;
chomp;
if($? == 0 && /$expect/) {
print "$_\n";
} else {
print "failed\n";
error "Could not find $prog (used $cmd)\nPlease make sure it is available before building Slash";
}
}
if(!defined $ENV{CC}) {
warning "CC environment variable not set, falling back to 'cc'...";
$ENV{CC} = "cc";
}
check_prog "$ENV{CC} --version";
check_prog "flex --version", "flex 2";
check_lib "gmp", <<C;
#include <gmp.h>
int main() {
mpz_t mpz;
mpz_init(mpz);
}
C
check_lib "iconv", <<C;
#include <iconv.h>
int main() {
iconv_open("UTF-8", "ISO-8859-1");
}
C
if($^O eq 'msys') {
$CFLAGS .= ' -DPCRE_STATIC';
}
check_lib "pcre", <<C;
#include <pcre.h>
int main() {
pcre_version();
}
C
print "Checking for a thread-safe time.h... ";
if(compile("", "#define __USE_POSIX\n#include <stdlib.h>\n#include <time.h>\n\nint main() { asctime_r(NULL, NULL); gmtime_r(NULL, NULL); localtime_r(NULL, NULL); }")) {
print "ok\n";
$CFLAGS .= " -DSL_HAS_THREADSAFE_TIME";
} else {
printf "failed\n";
warning "Slash is being compiled without support for threadsafe time handling. You should not consider this build production-safe.";
}
unless($debug) {
print "Checking for -march=native... ";
if(compile("-march=native", "int main(){}")) {
print "ok\n";
$CFLAGS .= " -march=native";
} else {
print "failed\n";
}
print "Checking for -flto... ";
if(compile("-flto", "int main(){}")) {
print "ok\n";
$CFLAGS .= " -flto";
$LDFLAGS .= " -flto";
} else {
print "failed\n";
}
}
print "Checking for __builtin_expect... ";
if(compile("", "int main(){ if(__builtin_expect(1, 1)) { } }")) {
print "ok\n";
$CFLAGS .= " -DSL_HAS_BUILTIN_EXPECT";
} else {
print "failed\n";
}
print "Checking for unistd.h... ";
if(compile("", "#include <unistd.h>\nint main(){}")) {
print "ok\n";
$CFLAGS .= " -DSL_HAS_UNISTD";
} else {
print "failed\n";
}
print "Checking for -Wno-gnu... ";
if(compile("-Wno-gnu", "int main() {}")) {
print "ok\n";
$CFLAGS .= " -Wno-gnu";
} else {
print "failed\n";
}
print "Checking for computed goto... ";
if(compile("", "int main() { void* x = &&y; goto *x; y: exit(0); }")) {
print "ok\n";
$CFLAGS .= " -DSL_HAS_COMPUTED_GOTO";
} else {
print "failed\n";
}
open my $mf, ">$path/local.mk";
print $mf "CC=$ENV{CC}\n";
my %platforms = (
darwin => sub {
print $mf "OBJS+= platform/posix.o platform/darwin.o\n";
$CFLAGS .= " -fPIC"
},
linux => sub {
print $mf "OBJS+= platform/posix.o platform/linux.o\n";
$CFLAGS .= " -fPIC";
$LDFLAGS .= " -lpthread -lm"
},
msys => sub {
print $mf "OBJS+= platform/win32.o\n";
},
);
if($platforms{$^O}) {
$platforms{$^O}->();
} else {
error "Unknown system $^O. Please file an issue at https://github.com/slash-lang/slash/issues.";
}
my ($ext_decls, $ext_inits, $ext_static_inits);
my $CURRENT_EXT;
sub needs_static_init {
$ext_decls .= "void sl_static_init_ext_$CURRENT_EXT();";
$ext_static_inits .= "sl_static_init_ext_$CURRENT_EXT();";
};
print "\n";
for my $ext (@exts) {
print "\e[34;1mConfiguring ext/$ext\e[0m\n";
my $conf = "$path/ext/$ext/configure.pl";
$CURRENT_EXT = $ext;
if(-e $conf) {
eval { require $conf; };
if($@) {
print "Skipping installation of ext/$ext\n\n";
die if grep( /^$ext$/, @required_exts );
next;
}
}
$ext_decls .= "void sl_init_ext_$ext(sl_vm_t* vm);";
$ext_inits .= "sl_init_ext_$ext(vm);";
print $mf "include $path/ext/$ext/$ext.mk\n";
}
open my $init_exts, ">$path/src/init_exts.c";
my $require_path = "$prefix/lib/slash/";
$require_path =~ s/\\/\\\\/g;
$require_path =~ s/"/\\"/g;
$require_path =~ s/\n/\\\n/g;
print $init_exts <<"C";
#include <slash.h>
$ext_decls
void
sl_static_init_exts()
{
$ext_static_inits
}
void
sl_init_exts(sl_vm_t* vm)
{
sl_require_path_add(vm, "$require_path");
$ext_inits
}
C
close $init_exts;
print "\n";
for my $sapi (@sapis) {
print "\e[34;1mConfiguring sapi/$sapi\e[0m\n";
my $conf = "$path/sapi/$sapi/configure.pl";
if(-e $conf) {
eval { require $conf; };
if($@) {
print "Skipping installation of sapi/$sapi\n\n";
next;
}
}
print $mf "TARGETS+= sapi[$sapi]\n";
}
print $mf "CFLAGS+= $CFLAGS\n";
print $mf "LDFLAGS+= $LDFLAGS\n";
print $mf "INSTALL_PREFIX=$prefix\n";
print $mf "SAPIS_ENABLED=" . join(" ", @sapis) . "\n";
print $mf "BASE_PATH=$path\n";
close $mf;
success "Ready to build";