Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

New Configure/build system, part 1.

  • Loading branch information...
commit 7ec8cf266d573d1bc6dfb8f9c29e02ac9130c31b 1 parent 151d38f
@pmichaud pmichaud authored
View
2  .gitignore
@@ -2,6 +2,7 @@
src/gen/*
Perl6/*
nqp/
+install/
Makefile
.*.swp
*.patch
@@ -25,7 +26,6 @@ perl6.rc
t/localtest.data
t/spec
parrot
-parrot_install
perl6
perl6.c
perl6.o
View
232 Configure.pl
@@ -6,14 +6,20 @@
use warnings;
use Getopt::Long;
use Cwd;
-use lib "build/lib";
-use Parrot::CompareRevisions qw(compare_revs parse_revision_file read_config version_from_git_describe);
+use lib "tools/lib";
+use NQP::Configure qw(slurp gen_nqp read_config fill_template_file);
+
MAIN: {
+ my %config;
+ $config{'rakudo_config_status'} = join(' ', map { "\"$_\""} @ARGV);
+
my %options;
- GetOptions(\%options, 'help!', 'parrot-config=s', 'makefile-timing!',
- 'gen-parrot!', 'gen-parrot-prefix=s', 'gen-parrot-option=s@',
- 'gen-nqp!');
+ GetOptions(\%options, 'help!', 'prefix=s',
+ 'with-nqp=s', 'gen-nqp:s',
+ 'with-parrot=s', 'gen-parrot:s',
+ 'make-install!', 'makefile-timing!',
+ );
# Print help if it's requested
if ($options{'help'}) {
@@ -21,216 +27,50 @@
exit(0);
}
- # Update/generate parrot build if needed
- if ($options{'gen-parrot'}) {
- my @opts = @{ $options{'gen-parrot-option'} || [] };
- my $prefix = $options{'gen-parrot-prefix'} || cwd()."/parrot_install";
- # parrot's Configure.pl mishandles win32 backslashes in --prefix
- $prefix =~ s{\\}{/}g;
- my @command = ($^X, "build/gen_parrot.pl", "--prefix=$prefix",
- '--gc=gms', ($^O !~ /win32/i ? "--optimize" : ()), @opts);
-
- print "Generating Parrot ...\n";
- print "@command\n\n";
- system(@command) == 0
- or die "Error while executing @command; aborting\n";
- }
-
- # Update/generate NQP build if needed.
- if ($options{'gen-nqp'}) {
- my @command = ($^X, "build/gen_nqp.pl");
- print "Generating NQP ...\n";
- print "@command\n\n";
- system(@command) == 0
- or die "Error while executing @command; aborting\n";
- }
-
- # Get a list of parrot-configs to invoke.
- my @parrot_config_exe = qw(
- parrot_install/bin/parrot_config
- ../../parrot_config
- parrot_config
- );
- if (exists $options{'gen-parrot-prefix'}) {
- @parrot_config_exe =
- $options{'gen-parrot-prefix'} . '/bin/parrot_config';
- }
-
- if ($options{'parrot-config'} && $options{'parrot-config'} ne '1') {
- @parrot_config_exe = ($options{'parrot-config'});
- }
-
- # Get configuration information from parrot_config
- my ($parrot_config, %config) = read_config(@parrot_config_exe);
-
- # Determine the revision of Parrot we require
- my $git_describe = parse_revision_file;
- my $parrot_version = version_from_git_describe($git_describe);
-
- my $parrot_errors = '';
- if (!%config) {
- $parrot_errors .= "Unable to locate parrot_config\n";
- }
- else {
- if ($config{git_describe}) {
- # a parrot built from git
- if (compare_revs($git_describe, $config{'git_describe'}) > 0) {
- $parrot_errors .= "Parrot revision $git_describe required (currently $config{'git_describe'})\n";
- }
- }
- else {
- # not built from a git repo - let's assume it's a release
- if (version_int($parrot_version) > version_int($config{'VERSION'})) {
- $parrot_errors .= "Parrot version $parrot_version required (currently $config{VERSION})\n";
- }
- }
- }
-
- if ($parrot_errors) {
- die <<"END";
-===SORRY!===
-$parrot_errors
-To automatically clone (git) and build a copy of parrot $git_describe,
-try re-running Configure.pl with the '--gen-parrot' option.
-Or, use the '--parrot-config' option to explicitly specify
-the location of parrot_config to be used to build Rakudo Perl.
-
-END
- }
+ my $with_nqp = $options{'with_nqp'};
- my $nqp_exe = $parrot_config;
- # the .* is needed of somebody has the string 'parrot_config' in
- # the build path - we always want to substitute the last occorence
- $nqp_exe =~ s/(.*)parrot_config/$1nqp/s;
- if (system $nqp_exe, '-e', '') {
- die "Cannot execute nqp - maybe try the --gen-nqp option to automatically build one?\n";
+ # Save options in config.status
+ unlink('config.status');
+ if (open(my $CONFIG_STATUS, '>', 'config.status')) {
+ print $CONFIG_STATUS
+ "$^X Configure.pl $config{'rakudo_config_status'} \$*\n";
+ close($CONFIG_STATUS);
}
- # Verify the Parrot installation is sufficient for building Rakudo
- verify_parrot(%config);
-
- # Create the Makefile using the information we just got
- create_makefile($options{'makefile-timing'}, %config);
- my $make = $config{'make'};
-
- {
- no warnings;
- print "Cleaning up ...\n";
- if (open my $CLEAN, '-|', "$make clean") {
- my @slurp = <$CLEAN>;
- close $CLEAN;
- }
- }
-
- print <<"END";
-
-You can now use '$make' to build Rakudo Perl.
-After that, you can use '$make test' to run some local tests,
-or '$make spectest' to check out (via git) a copy of the Perl 6
-official test suite and run its tests.
-
-END
- exit 0;
-
-}
-
-
-sub verify_parrot {
- print "Verifying Parrot installation...\n";
- my %config = @_;
- my $EXE = $config{'exe'};
- my $PARROT_BIN_DIR = $config{'bindir'};
- my $PARROT_VERSION = $config{'versiondir'};
- my $PARROT_LIB_DIR = $config{'libdir'}.$PARROT_VERSION;
- my $PARROT_SRC_DIR = $config{'srcdir'}.$PARROT_VERSION;
- my $PARROT_INCLUDE_DIR = $config{'includedir'}.$PARROT_VERSION;
- my $PARROT_TOOLS_DIR = "$PARROT_LIB_DIR/tools";
- my @required_files = (
- "$PARROT_LIB_DIR/library/PGE/Perl6Grammar.pbc",
- "$PARROT_LIB_DIR/library/PCT/HLLCompiler.pbc",
- "$PARROT_BIN_DIR/ops2c".$EXE,
- "$PARROT_TOOLS_DIR/build/pmc2c.pl",
- "$PARROT_SRC_DIR",
- "$PARROT_SRC_DIR/pmc",
- "$PARROT_INCLUDE_DIR",
- "$PARROT_INCLUDE_DIR/pmc",
- );
- my @missing = map { " $_" } grep { ! -e } @required_files;
- if (@missing) {
- my $missing = join("\n", @missing);
- die <<"END";
-
-===SORRY!===
-I'm missing some needed files from the Parrot installation:
-$missing
-(Perhaps you need to use Parrot's "make install-dev" or
-install the "parrot-devel" package for your system?)
-
-END
+ my ($nqp_want) = split(' ', slurp('tools/build/NQP_REVISION'));
+ if (defined $options{'gen-parrot'}) {
+ $with_nqp = gen_nqp($nqp_want, %options);
}
-}
-
-# Generate a Makefile from a configuration
-sub create_makefile {
- my ($makefile_timing, %config) = @_;
- my $maketext = slurp( 'build/Makefile.in' );
-
- $config{'shell'} = $^O eq 'MSWin32' ? 'cmd' : 'sh';
- $config{'stagestats'} = $makefile_timing ? '--stagestats' : '';
- $config{'win32_libparrot_copy'} = $^O eq 'MSWin32' ? 'copy $(PARROT_BIN_DIR)\libparrot.dll .' : '';
- $maketext =~ s/@(\w+)@/$config{$1}/g;
+ %config = (%config, read_config($with_nqp));
+ $config{'makefile-timing'} = $options{'makefile-timing'};
+ $config{'stagestats'} = '--stagestats' if $options{'makefile-timing'};
+ $config{'shell'} = 'sh';
if ($^O eq 'MSWin32') {
- $maketext =~ s{/}{\\}g;
- $maketext =~ s{\\\*}{\\\\*}g;
- $maketext =~ s{(?:git|http):\S+}{ do {my $t = $&; $t =~ s'\\'/'g; $t} }eg;
- $maketext =~ s/.*curl.*/do {my $t = $&; $t =~ s'%'%%'g; $t}/meg;
- }
-
- if ($makefile_timing) {
- $maketext =~ s{(?<!\\\n)^\t(?!\s*-?cd)(?=[^\n]*\S)}{\ttime }mg;
+ $config{'shell'} = 'cmd';
+ $config{'win32_libparrot_copy'} =
+ 'copy $(PARROT_BIN_DIR)\libparrot.dll .';
}
- my $outfile = 'Makefile';
- print "\nCreating $outfile ...\n";
- open(my $MAKEOUT, '>', $outfile) ||
- die "Unable to write $outfile\n";
- print {$MAKEOUT} $maketext;
- close $MAKEOUT or die $!;
-
- return;
-}
+ fill_template_file('tools/build/Makefile.in', 'Makefile', %config);
-sub slurp {
- my $filename = shift;
-
- open my $fh, '<', $filename or die "Unable to read $filename\n";
- local $/ = undef;
- my $maketext = <$fh>;
- close $fh or die $!;
-
- return $maketext;
-}
-
-sub version_int {
- sprintf('%d%03d%03d', split(/\./, $_[0]))
+ exit 0;
}
# Print some help text.
sub print_help {
print <<'END';
-Configure.pl - Rakudo Configure
+Configure.pl - NQP Configure
General Options:
--help Show this text
+ --prefix=dir Install files in dir
+ --with-parrot=path/to/bin/parrot
+ Parrot executable to use to build NQP
--gen-parrot Download and build a copy of Parrot to use
- --gen-parrot-option='--option=value'
- Set parrot config option when using --gen-parrot
- --parrot-config=/path/to/parrot_config
- Use config information from parrot_config executable
-Experimental developer's options:
- --makefile-timing Insert 'time' command all over in the Makefile
+ --parrot-option='--option=value'
+ Options to pass to parrot configuration for --gen-parrot
END
return;
View
3  build/Makefile.in → tools/build/Makefile.in
@@ -393,3 +393,6 @@ $(DYNOPS): $(OPS_DIR)/$(OPS_SOURCE) src/binder/bind.c src/binder/bind.h src/bind
cd src/binder && $(CC) -c @cc_o_out@container$(O) -I../../$(PMC_DIR) $(CINCLUDES) $(CFLAGS) container.c
cd src/binder && $(CC) -c @cc_o_out@types$(O) -I../../$(PMC_DIR) $(CINCLUDES) $(CFLAGS) types.c
cd $(OPS_DIR) && $(LD) @ld_out@$(OPS)$(LOAD_EXT) $(OPS)$(O) ../binder/bind$(O) ../binder/multidispatch$(O) ../binder/container$(O) ../binder/types$(O) $(LINKARGS)
+
+# nqp::makefile <-- tells NQP::Configure to treat this file as a makefile,
+# performing win32 slash and makefile conversions
View
1  tools/build/NQP_REVISION
@@ -0,0 +1 @@
+2011.05-36-gc9a6dba
View
346 tools/lib/NQP/Configure.pm
@@ -0,0 +1,346 @@
+package NQP::Configure;
+use strict;
+use warnings;
+use Cwd;
+
+use base qw(Exporter);
+our @EXPORT_OK = qw(slurp system_or_die
+ cmp_rev
+ read_parrot_config read_config
+ fill_template_file fill_template_text
+ git_checkout
+ verify_install
+ gen_nqp gen_parrot);
+
+our $exe = $^O eq 'MSWin32' ? '.exe' : '';
+
+our @required_parrot_files = qw(
+ @bindir@/parrot@exe@
+ @bindir@/pbc_to_exe@exe@
+ @bindir@/ops2c@exe@
+ @libdir@@versiondir@/tools/build/pmc2c.pl
+ @srcdir@@versiondir@/pmc
+ @includedir@@versiondir@/pmc
+);
+
+our $nqp_git = 'git://github.com/perl6/nqp.git';
+our $par_git = 'git://github.com/parrot/parrot.git';
+
+
+sub slurp {
+ my $filename = shift;
+ open my $fh, '<', $filename
+ or die "Unable to read $filename\n";
+ local $/ = undef;
+ my $text = <$fh>;
+ close $fh or die $!;
+ return $text;
+}
+
+
+sub system_or_die {
+ my @cmd = @_;
+ system( @cmd ) == 0
+ or die "Command failed (status $?): @cmd\n";
+}
+
+
+sub parse_revision {
+ my $rev = shift;
+ my $sep = qr/[_.]/;
+ $rev =~ /(\d+)$sep(\d+)(?:$sep(\d+))?(?:-(\d+)-g[a-f0-9]*)?$/
+ or die "Unrecognized revision specifier '$rev'\n";
+ return ($1, $2, $3 || 0, $4 || 0);
+}
+
+
+sub cmp_rev {
+ my ($a, $b) = @_;
+ my @a = parse_revision($a);
+ my @b = parse_revision($b);
+ my $cmp = 0;
+ for (0..3) {
+ $cmp = $a[$_] <=> $b[$_];
+ last if $cmp;
+ }
+ $cmp;
+}
+
+
+sub read_config {
+ my @config_src = @_;
+ my %config = ();
+ for my $file (@config_src) {
+ no warnings;
+ if (open my $CONFIG, '-|', "$file --show-config") {
+ print "\nReading configuration from $file ...\n";
+ while (<$CONFIG>) {
+ if (/^([\w:]+)=(.*)/) { $config{$1} = $2 }
+ }
+ close($CONFIG) or die $!;
+ }
+ last if %config;
+ }
+ return %config;
+}
+
+
+sub read_parrot_config {
+ my @parrot_config_src = @_;
+ my %config = ();
+ open my $CONFIG_PIR, '>', 'parrot-config.pir'
+ or die "Unable to write parrot-config.pir\n";
+ print $CONFIG_PIR <<'END';
+ .include 'iglobals.pasm'
+ .sub "main" :main
+ .local pmc interp, config_hash, config_iter
+ interp = getinterp
+ config_hash = interp[.IGLOBALS_CONFIG_HASH]
+ config_iter = iter config_hash
+ config_loop:
+ unless config_iter goto config_done
+ $P0 = shift config_iter
+ print "parrot::"
+ $S0 = $P0.'key'()
+ print $S0
+ print "="
+ $S0 = $P0.'value'()
+ print $S0
+ print "\n"
+ goto config_loop
+ config_done:
+ .return ()
+ .end
+END
+ close($CONFIG_PIR);
+
+ for my $file (@parrot_config_src) {
+ no warnings;
+ if (open my $PARROT, '-|', "$file parrot-config.pir") {
+ print "\nReading configuration information from $file ...\n";
+ while (<$PARROT>) {
+ if (/^([\w:]+)=(.*)/) { $config{$1} = $2 }
+ }
+ close($PARROT) or die $!;
+ }
+ elsif (-r $file && open my $PARROT_CONFIG, '<', $file) {
+ print "\nReading configuration information from $file ...\n";
+ while (<$PARROT_CONFIG>) {
+ if (/P0\["(.*?)"\], "(.*?)"/) { $config{"parrot::$1"} = $2 }
+ }
+ close($PARROT_CONFIG) or die $!;
+ }
+ last if %config;
+ }
+ unlink('parrot-config.pir');
+ return %config;
+}
+
+
+sub fill_template_file {
+ my $infile = shift;
+ my $outfile = shift;
+ my %config = @_;
+ my $text = slurp( $infile );
+ $text = fill_template_text($text, %config);
+ print "\nCreating $outfile ...\n";
+ open(my $OUT, '>', $outfile)
+ or die "Unable to write $outfile\n";
+ print $OUT $text;
+ close($OUT) or die $!;
+}
+
+
+sub fill_template_text {
+ my $text = shift;
+ my %config = @_;
+
+ $text =~ s/@([:\w]+)@/$config{$1} || $config{"parrot::$1"} || ''/ge;
+ if ($^O eq 'MSWin32' && $text =~ /nqp::makefile/) {
+ $text =~ s{/}{\\}g;
+ $text =~ s{\\\*}{\\\\*}g;
+ $text =~ s{(?:git|http):\S+}{ do {my $t = $&; $t =~ s'\\'/'g; $t} }eg;
+ $text =~ s/.*curl.*/do {my $t = $&; $t =~ s'%'%%'g; $t}/meg;
+ if ($config{'makefile-timing'}) {
+ $text =~ s{(?<!\\\n)^\t(?!\s*-?cd)(?=[^\n]*\S)}{\ttime }mg;
+ }
+ }
+ $text;
+}
+
+
+sub git_checkout {
+ my $repo = shift;
+ my $dir = shift;
+ my $checkout = shift;
+ my $pwd = cwd();
+
+ # get an up-to-date repository
+ if (! -d $dir) {
+ system_or_die('git', 'clone', $repo, $dir);
+ chdir($dir);
+ }
+ else {
+ chdir($dir);
+ system_or_die('git', 'fetch');
+ }
+
+ if ($checkout) {
+ system_or_die('git', 'checkout', $checkout);
+ }
+
+ my $git_describe;
+ if (open(my $GIT, '-|', "git describe --tags")) {
+ $git_describe = <$GIT>;
+ close($GIT);
+ chomp $git_describe;
+ }
+ chdir($pwd);
+ $git_describe;
+}
+
+
+sub verify_install {
+ my $files = shift;
+ my %config = @_;
+ print "Verifying installation ...\n";
+ my @missing;
+ for my $reqfile ( @{$files} ) {
+ my $f = fill_template_text($reqfile, %config);
+ push @missing, " $f" unless -e $f;
+ }
+ if (@missing) {
+ my $missing = join("\n", @missing);
+ die <<"END";
+
+===SORRY!===
+I'm missing some needed files in the install directory:
+$missing
+(Perhaps you need to use Parrot's "make install-dev" target or
+install the "parrot-devel" package for your system?)
+
+END
+ }
+ 1;
+}
+
+
+sub gen_nqp {
+ my $nqp_want = shift;
+ my %options = @_;
+
+ my $gen_nqp = $options{'gen-nqp'};
+ my $with_parrot = $options{'with-parrot'};
+ my $gen_parrot = $options{'gen-parrot'};
+ my $prefix = $options{'prefix'} || cwd().'/install';
+ my $startdir = cwd();
+
+ my $PARROT_REVISION = 'nqp/tools/build/PARROT_REVISION';
+
+ my %config;
+ my $nqp_exe;
+ if ($with_parrot) {
+ %config = read_parrot_config($with_parrot)
+ or die "Unable to read parrot configuration from $with_parrot\n";
+ $prefix = $config{'parrot::prefix'};
+ $nqp_exe = fill_template_text('@bindir@/nqp@ext@', %config);
+ %config = read_config($nqp_exe);
+ }
+ elsif ($prefix) {
+ $nqp_exe = "$prefix/bin/nqp$exe";
+ %config = read_config($nqp_exe);
+ }
+
+ my $nqp_have = $config{'nqp::version'} || '';
+ my $nqp_ok = $nqp_have && cmp_rev($nqp_have, $nqp_want) >= 0;
+ if ($gen_nqp) {
+ my $nqp_repo = git_checkout($nqp_git, 'nqp', $gen_nqp);
+ $nqp_ok = $nqp_have eq $nqp_repo;
+ }
+ elsif (!$nqp_ok || defined $gen_parrot && !-f $PARROT_REVISION) {
+ git_checkout($nqp_git, 'nqp', $nqp_want);
+ }
+
+ if (defined $gen_parrot) {
+ my ($par_want) = split(' ', slurp($PARROT_REVISION));
+ $with_parrot = gen_parrot($par_want, %options, prefix => $prefix);
+ %config = read_parrot_config($with_parrot);
+ }
+ elsif (!%config) {
+ %config = read_parrot_config("$prefix/bin/parrot$exe", "parrot$exe");
+ $with_parrot = fill_template_text('@bindir@/parrot@exe@', %config);
+ }
+
+ if ($nqp_ok && -M $nqp_exe < -M $with_parrot) {
+ print "Already have NQP $nqp_have, it's good enough.\n";
+ return $nqp_exe;
+ }
+
+ my @cmd = ($^X, 'Configure.pl', "--with-parrot=$with_parrot",
+ "--make-install");
+ print "Building NQP ...\n";
+ chdir("$startdir/nqp");
+ print "@cmd\n";
+ system_or_die(@cmd);
+ chdir($startdir);
+ return fill_template_text('@bindir@/nqp@exe@', %config);
+}
+
+
+sub gen_parrot {
+ my $par_want = shift;
+ my %options = @_;
+
+ my $prefix = $options{'prefix'} || cwd()."/install";
+ my $gen_parrot = $options{'gen-parrot'};
+ my @opts = @{ $options{'parrot-option'} || [] };
+ push @opts, "--optimize";
+ my $startdir = cwd();
+
+ my $par_exe = "$options{'prefix'}/bin/parrot$exe";
+ my %config = read_parrot_config($par_exe);
+
+ my $par_have = $config{'parrot::git_describe'} || '';
+ my $par_ok = $par_have && cmp_rev($par_have, $par_want) >= 0;
+ if ($gen_parrot) {
+ my $par_repo = git_checkout($par_git, 'parrot', $gen_parrot);
+ $par_ok = $par_have eq $par_repo;
+ }
+ elsif (!$par_ok) {
+ git_checkout($par_git, 'parrot', $par_want);
+ }
+
+ if ($par_ok) {
+ print "Already have Parrot $par_have, that's good enough";
+ print " for $par_want.\n";
+ return $par_exe;
+ }
+ chdir("$startdir/parrot") or die $!;
+ if (-f 'Makefile') {
+ %config = read_parrot_config('config_lib.pir');
+ my $make = $config{'parrot::make'};
+ if ($make) {
+ print "\nPerforming '$make realclean' ...\n";
+ system_or_die($make, 'realclean');
+ }
+ }
+
+ $prefix =~ s{\\}{/}g;
+
+ print "\nConfiguring Parrot ...\n";
+ my @cmd = ($^X, "Configure.pl", @opts, "--prefix=$prefix");
+ print "@cmd\n";
+ system_or_die(@cmd);
+
+ print "\nBuilding Parrot ...\n";
+ %config = read_parrot_config('config_lib.pir');
+ my $make = $config{'parrot::make'} or
+ die "Unable to determine value for 'make' from parrot config\n";
+ system_or_die($make, 'install-dev');
+
+ print "Parrot installed.\n";
+ return fill_template_text('@bindir@/parrot@exe@', %config);
+}
+
+
+1;
Please sign in to comment.
Something went wrong with that request. Please try again.