aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorpmichaud <pmichaud@pobox.com>2012-08-28 00:36:53 -0500
committerpmichaud <pmichaud@pobox.com>2012-08-28 00:36:53 -0500
commitc012d8b882480151d8eb7da92c4cca80d1d9b814 (patch)
tree827354a3d38adfafe328ef55fa454147cc4af868 /tools
parentc3ff6182252a634e2ce8167a8bd367932e858dd5 (diff)
Move skel/ into top-level directory, to try building directly from the repo.
Diffstat (limited to 'tools')
-rw-r--r--tools/build/Makefile.in162
-rw-r--r--tools/build/bin-install.pl28
-rw-r--r--tools/build/module-install.pl112
-rw-r--r--tools/build/star-product.wxs68
-rw-r--r--tools/lib/NQP/Configure.pm365
5 files changed, 735 insertions, 0 deletions
diff --git a/tools/build/Makefile.in b/tools/build/Makefile.in
new file mode 100644
index 0000000..733793b
--- /dev/null
+++ b/tools/build/Makefile.in
@@ -0,0 +1,162 @@
+# Copyright (C) 2006-2012, The Perl Foundation.
+# $Id$
+
+PARROT = parrot-4.6.0
+NQP = nqp-2012.08
+RAKUDO = rakudo-2012.08
+STAR_VERSION = 2012.08
+
+PARROT_ARGS =
+
+# values from parrot_config
+PREFIX_DIR = @prefix@
+PARROT_BIN_DIR = @bindir@
+PARROT_VERSION = @versiondir@
+PARROT_INCLUDE_DIR = @includedir@$(PARROT_VERSION)
+PARROT_LIB_DIR = @libdir@$(PARROT_VERSION)
+PARROT_SRC_DIR = @srcdir@$(PARROT_VERSION)
+HAS_ICU = @has_icu@
+
+CC = @cc@
+CFLAGS = @ccflags@ @cc_shared@ @cc_debug@ @ccwarn@ @cc_hasjit@ @gc_flag@
+EXE = @exe@
+LD = @ld@
+LDFLAGS = @ldflags@ @ld_debug@
+LD_LOAD_FLAGS = @ld_load_flags@
+LIBPARROT = @inst_libparrot_ldflags@
+O = @o@
+LOAD_EXT = @load_ext@
+PERL = @perl@
+CP = @cp@
+MV = @mv@
+RM_F = @rm_f@
+MKPATH = $(PERL) -MExtUtils::Command -e mkpath
+CHMOD = $(PERL) -MExtUtils::Command -e chmod
+POD2MAN = @pod2man@
+
+# locations of parrot resources
+PARROT = $(PARROT_BIN_DIR)/parrot$(EXE)
+NQP_EXE = $(PARROT_BIN_DIR)/nqp$(EXE)
+PBC_TO_EXE = $(PARROT_BIN_DIR)/pbc_to_exe$(EXE)
+PARROT_CONFIG = $(PARROT_BIN_DIR)/parrot_config$(EXE)
+PARROT_TOOLS_DIR = $(PARROT_LIB_DIR)/tools
+PARROT_PERL_LIB = $(PARROT_TOOLS_DIR)/lib
+OPS2C = $(PARROT_BIN_DIR)/ops2c$(EXE)
+PMC2C = $(PERL) $(PARROT_TOOLS_DIR)/build/pmc2c.pl
+PMC2C_INCLUDES = --include src/pmc --include $(PARROT_SRC_DIR) --include $(PARROT_SRC_DIR)/pmc
+CINCLUDES = -I$(PARROT_INCLUDE_DIR) -I$(PARROT_INCLUDE_DIR)/pmc
+LINKARGS = $(LDFLAGS) $(LD_LOAD_FLAGS) $(LIBPARROT) @libs@ @icu_shared@
+
+PERL6_EXE = perl6$(EXE)
+PERL6_LANG_DIR = $(PARROT_LIB_DIR)/languages/perl6
+
+# This list must be kept in order, modules always coming after their
+# dependencies
+MODULES = \
+ modules/zavolaj \
+ modules/xml-writer \
+ modules/svg \
+ modules/svg-plot \
+ modules/Math-RungeKutta \
+ modules/Math-Model \
+ modules/perl6-Term-ANSIColor \
+ modules/test-mock \
+ modules/Grammar-Profiler-Simple \
+ modules/grammar-debugger \
+ modules/Perl6-MIME-Base64 \
+ modules/uri \
+ modules/perl6-lwp-simple \
+ modules/json \
+ modules/perl6-digest-md5 \
+ modules/perl6-File-Tools \
+ modules/panda \
+ modules/perl6-http-status \
+ modules/perl6-http-easy \
+ modules/Template-Mojo \
+ modules/Bailador \
+ modules/DBIish \
+ modules/jsonrpc \
+ modules/Pod-To-HTML \
+ modules/doc \
+
+all: rakudo
+
+rakudo: $(RAKUDO)/$(PERL6_EXE)
+$(RAKUDO)/$(PERL6_EXE):
+ @echo "== Configuring and building Rakudo"
+ cd $(RAKUDO) && $(PERL) Configure.pl --with-nqp=$(NQP_EXE) && $(MAKE)
+rakudo-test: rakudo
+ cd $(RAKUDO) && $(MAKE) test
+rakudo-spectest: rakudo
+ cd $(RAKUDO) && $(MAKE) spectest
+rakudo-install: rakudo
+ cd $(RAKUDO) && $(MAKE) install
+ @win32_libparrot_copy@
+ $(CP) $(DESTDIR)$(PARROT_BIN_DIR)/$(PERL6_EXE) .
+ $(CHMOD) 755 $(PERL6_EXE)
+
+modules-install: rakudo
+ @echo "== Installing 'ufo'"
+ $(PERL) tools/build/module-install.pl $(DESTDIR)$(PARROT_BIN_DIR)/$(PERL6_EXE) $(DESTDIR)$(PERL6_LANG_DIR)/lib $(MODULES)
+ @echo "== Installing binaries"
+ $(PERL) tools/build/bin-install.pl $(DESTDIR)$(PARROT_BIN_DIR)/$(PERL6_EXE) $(DESTDIR)$(PARROT_BIN_DIR) modules/ufo/bin/ufo modules/panda/bin/panda
+
+install: rakudo-install modules-install
+
+test:
+ @echo ""
+ @echo "To run the Rakudo compiler tests, use 'make rakudo-test'"
+ @echo "To run the Perl 6 spectests, use 'make rakudo-spectest'"
+ @echo ""
+ @echo "To run tests for individual modules, try:"
+ @echo " prove -e ./perl6 -r modules/<name>/t"
+ @echo ""
+
+## cleaning
+clean:
+ $(RM_F) $(CLEANUPS)
+
+distclean: realclean
+
+realclean: clean
+ $(RM_F) Makefile
+
+testclean:
+
+
+## miscellaneous targets
+# a listing of all targets meant to be called by users
+help:
+ @echo ""
+ @echo "Following targets are available for the user:"
+ @echo ""
+ @echo "Maintenance:"
+ @echo " perlcritic: Run Perl::Critic on all the Perl 5 code."
+ @echo ""
+ @echo "Cleaning:"
+ @echo " clean: Basic cleaning up."
+ @echo " distclean: Removes also anything built, in theory."
+ @echo " realclean: Removes also files generated by 'Configure.pl'."
+ @echo " testclean: Clean up test results."
+ @echo ""
+ @echo "Misc:"
+ @echo " help: Print this help message."
+ @echo ""
+
+config:
+ $(PERL) Configure.pl
+
+$(PARROT):
+
+CRITIC_FILES=Configure.pl tools/build/
+
+perlcritic:
+ perlcritic -1 --profile tools/util/perlcritic.conf $(CRITIC_FILES)
+
+msi:
+ -$(CP) c:/strawberry/c/bin/libgcc_s_sjlj-1.dll $(PARROT_BIN_DIR)
+ cmd /c heat dir $(PREFIX_DIR) -gg -sfrag -cg RakudoStar -dr INSTALLROOT -srd -out star-files.wxs
+ cmd /c candle star-files.wxs
+ cmd /c candle -dSTARVERSION=$(STAR_VERSION) tools/build/star-product.wxs
+ cmd /c light -b $(PREFIX_DIR) -ext WixUIExtension star-files.wixobj star-product.wixobj -o rakudo-star-$(STAR_VERSION).msi
+
diff --git a/tools/build/bin-install.pl b/tools/build/bin-install.pl
new file mode 100644
index 0000000..1c71cea
--- /dev/null
+++ b/tools/build/bin-install.pl
@@ -0,0 +1,28 @@
+#! perl
+
+use strict;
+use warnings;
+use File::Spec;
+
+my ($p6bin, $dest, @files) = @ARGV;
+die "Usage: $0 <perl6_binary> <destination_path> <source_files>"
+ unless $p6bin && $dest;
+
+for my $filename (@files) {
+ open my $IN, '<', $filename
+ or die "Cannot read file '$filename' for installing it: $!";
+ my $basename = (File::Spec->splitpath($filename))[2];
+ open my $OUT, '>', "$dest/$basename"
+ or die "Cannot write file '$dest/$basename' for installing it: $!";
+ while (<$IN>) {
+ if ($. == 1 && /^#!/) {
+ print { $OUT } "#!$p6bin\n";
+ }
+ else {
+ print { $OUT } $_;
+ }
+ }
+ close $OUT or die "Error while closing file '$dest/$basename': $!";
+ close $IN;
+ chmod 0755, "$dest/$basename";
+}
diff --git a/tools/build/module-install.pl b/tools/build/module-install.pl
new file mode 100644
index 0000000..8d69c78
--- /dev/null
+++ b/tools/build/module-install.pl
@@ -0,0 +1,112 @@
+#! perl
+
+use warnings;
+use strict;
+use File::Find;
+use File::Copy;
+use File::Path;
+use File::Basename;
+
+my $perl6bin = shift @ARGV;
+my $perl6lib = shift @ARGV;
+
+my @pmfiles;
+my @mod_pms;
+while (@ARGV) {
+ my $module = shift @ARGV;
+ print "== Installing module $module\n";
+ our $mlib = "$module/lib";
+
+ @mod_pms = ();
+ find({ no_chdir=>1, wanted => \&libcopy }, $mlib);
+
+ sub libcopy {
+ return unless /\.pm6?|\.pod/;
+ my $source = $File::Find::name;
+ my $target = $source;
+ $target =~ s/\Q$mlib\E/$perl6lib/;
+ print "$source => $target\n";
+ mkpath dirname($target);
+ copy($source, $target) or die "copy failed: $!\n";
+ push @mod_pms, $target if $target =~ /\.pm6?/;
+ }
+
+ my %usages_of;
+ my @modules;
+ my %module_to_path;
+ for my $module_file (@mod_pms) {
+ open(my $fh, '<', $module_file) or die $!;
+ my $module = path_to_module_name($module_file);
+ push @modules, $module;
+ $module_to_path{$module} = $module_file;
+ $usages_of{$module} = [];
+ while (<$fh>) {
+ if (/^\s* (?:use|need) \s+ (\w+ (?: :: \w+)*)/x and my $used = $1) {
+ next if $used eq 'v6';
+ next if $used eq 'MONKEY_TYPING';
+
+ push @{$usages_of{$module}}, $used;
+ }
+ }
+ }
+
+ my @order = topo_sort(\@modules, \%usages_of);
+ my @sources = map { $module_to_path{$_} } @order;
+ push @pmfiles, @sources;
+}
+
+# Internally, we treat the module names as module names, '::' and all.
+# But since they're really files externally, they have to be converted
+# from paths to module names, and back again.
+
+sub path_to_module_name {
+ $_ = shift;
+ s/^.+\blib\///;
+ s/^.+\blib6\///;
+ s/\.pm6?$//;
+ s/\//::/g;
+ $_;
+}
+
+chdir 'rakudo';
+foreach my $pm (@pmfiles) {
+ my $out = $pm;
+ $out =~ s/\.pm6?$/.pir/;
+ my @cmd = ($perl6bin, '--target=pir', "--output=$out", $pm);
+ print join(' ', @cmd), "\n";
+ system(@cmd);
+}
+
+
+# According to "Introduction to Algorithms" by Cormen et al., topological
+# sort is just a depth-first search of a graph where you pay attention to
+# the order in which you get done with a dfs-visit() for each node.
+
+sub topo_sort {
+ my ($modules, $dependencies) = @_;
+ my @modules = @$modules;
+ my @order;
+ my %color_of = map { $_ => 'not yet visited' } @modules;
+
+ for my $module (@modules) {
+ if ($color_of{$module} eq 'not yet visited') {
+ dfs_visit($module, \%color_of, $dependencies, \@order);
+ }
+ }
+ return @order;
+}
+
+sub dfs_visit {
+ my $module = shift;
+ my $color_of = shift;
+ my $dependencies = shift;
+ my $order = shift;
+ $color_of->{$module} = 'visited';
+ for my $used (@{$dependencies->{$module}}) {
+ $color_of->{$used} ||= '';
+ if ($color_of->{$used} eq 'not yet visited') {
+ dfs_visit($used, $color_of, $dependencies, $order);
+ }
+ }
+ push @$order, $module;
+}
diff --git a/tools/build/star-product.wxs b/tools/build/star-product.wxs
new file mode 100644
index 0000000..c950e97
--- /dev/null
+++ b/tools/build/star-product.wxs
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
+ <Product Id="*" Language="1033" Manufacturer="Rakudo Perl 6" Name="Rakudo Star $(var.STARVERSION)" UpgradeCode="{08B7EB05-7EAC-4B60-9F5B-AF6E367FE0FD}" Version="1.0.0">
+ <Package Compressed="yes" InstallerVersion="200" />
+
+ <!-- force installation to C: drive -->
+ <Property Id="ROOTDRIVE"><![CDATA[C:\]]></Property>
+
+ <Directory Id="TARGETDIR" Name="SourceDir">
+ <Directory Id="INSTALLROOT" Name="rakudo" />
+
+ <!-- start menu shortcuts, adapted from http://wix.sourceforge.net/manual-wix3/create_start_menu_shortcut.htm -->
+ <Directory Id="ProgramMenuFolder">
+ <Directory Id="RakudoMenuFolder" Name="Rakudo Perl 6">
+ <Component Id="RakudoStartItems" Guid="B5BD7AEC-C8dC-4F84-AF2E-4A417350D642">
+ <Shortcut Id="RakudoShortcut"
+ Name="Rakudo Perl 6"
+ Target="[INSTALLROOT]bin\perl6.exe"
+ WorkingDirectory="INSTALLROOT" />
+ <RemoveFolder Id="RakudoMenuFolder" On="uninstall" />
+ <RegistryValue Root="HKCU" Key="Software\Microsoft\RakudoPerl6" Name="installed" Type="integer" Value="1" KeyPath="yes" />
+ </Component>
+ </Directory>
+ </Directory>
+ </Directory>
+
+ <Feature Id="ProductFeature" Level="1" Title="Rakudo Star $(var.STARVERSION)">
+ <ComponentGroupRef Id="RakudoStar" />
+ <ComponentRef Id="RakudoStartItems" />
+ </Feature>
+ <Media Id="1" Cabinet="product.cab" EmbedCab="yes" />
+
+ <!-- This is just like WixUI_Minimal but we skip the EULA part -->
+ <UI Id="WixUI_Minimal">
+ <TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="8" />
+ <TextStyle Id="WixUI_Font_Bigger" FaceName="Tahoma" Size="12" />
+ <TextStyle Id="WixUI_Font_Title" FaceName="Tahoma" Size="9" Bold="yes" />
+
+ <Property Id="DefaultUIFont" Value="WixUI_Font_Normal" />
+ <Property Id="WixUI_Mode" Value="Minimal" />
+
+ <DialogRef Id="ErrorDlg" />
+ <DialogRef Id="FatalError" />
+ <DialogRef Id="FilesInUse" />
+ <DialogRef Id="MsiRMFilesInUse" />
+ <DialogRef Id="PrepareDlg" />
+ <DialogRef Id="ProgressDlg" />
+ <DialogRef Id="ResumeDlg" />
+ <DialogRef Id="UserExit" />
+ <DialogRef Id="WelcomeDlg" />
+
+ <Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="PrepareDlg">1</Publish>
+ <Publish Dialog="ExitDialog" Control="Finish" Event="EndDialog" Value="Return" Order="999">1</Publish>
+
+ <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MaintenanceTypeDlg">1</Publish>
+
+ <Publish Dialog="MaintenanceWelcomeDlg" Control="Next" Event="NewDialog" Value="MaintenanceTypeDlg">1</Publish>
+
+ <Publish Dialog="MaintenanceTypeDlg" Control="RepairButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
+ <Publish Dialog="MaintenanceTypeDlg" Control="RemoveButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
+ <Publish Dialog="MaintenanceTypeDlg" Control="Back" Event="NewDialog" Value="MaintenanceWelcomeDlg">1</Publish>
+
+ <Property Id="ARPNOMODIFY" Value="1" />
+ </UI>
+
+ <UIRef Id="WixUI_Common" />
+ </Product>
+</Wix>
diff --git a/tools/lib/NQP/Configure.pm b/tools/lib/NQP/Configure.pm
new file mode 100644
index 0000000..e93c366
--- /dev/null
+++ b/tools/lib/NQP/Configure.pm
@@ -0,0 +1,365 @@
+package NQP::Configure;
+use strict;
+use warnings;
+use Cwd;
+
+use base qw(Exporter);
+our @EXPORT_OK = qw(sorry 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 @required_nqp_files = qw(
+ @bindir@/nqp@exe@
+);
+
+our $nqp_git = 'git://github.com/perl6/nqp.git';
+our $par_git = 'git://github.com/parrot/parrot.git';
+
+sub sorry {
+ my @msg = @_;
+ die join("\n", '', '===SORRY!===', @msg, "\n");
+}
+
+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") {
+ while (<$CONFIG>) {
+ if (/^([\w:]+)=(.*)/) { $config{$1} = $2 }
+ }
+ close($CONFIG);
+ }
+ 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 ($file =~ /.pir$/ && open my $PARROT_CONFIG, '<', $file) {
+ while (<$PARROT_CONFIG>) {
+ if (/P0\["(.*?)"\], "(.*?)"/) { $config{"parrot::$1"} = $2 }
+ }
+ close($PARROT_CONFIG) or die $!;
+ }
+ elsif (open my $PARROT, '-|', "$file parrot-config.pir") {
+ while (<$PARROT>) {
+ if (/^([\w:]+)=(.*)/) { $config{$1} = $2 }
+ }
+ close($PARROT);
+ }
+ 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 ($text =~ /nqp::makefile/) {
+ if ($^O eq 'MSWin32') {
+ $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) # not after line ending in '\'
+ ^ # beginning of line
+ (\t(?>@?[ \t]*)) # capture tab, optional @, and hspace
+ (?!-) # not before - (ignore error) lines
+ (?!cd) # not before cd lines
+ (?!echo) # not before echo lines
+ (?=\S) # must be before non-blank
+ }
+ {$1time\ }mgx;
+ }
+ }
+ $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);
+ system_or_die('git', 'pull')
+ if slurp('.git/HEAD') =~ /^ref:/;
+ }
+
+ 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) {
+ unshift @missing, "I'm missing some needed files:";
+ }
+ @missing;
+}
+
+
+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 $nqpdir = "$startdir/nqp";
+
+ 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 && -d $gen_nqp) {
+ $nqpdir = $gen_nqp;
+ print "Building NQP from source in $nqpdir\n";
+ }
+ elsif ($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) {
+ $PARROT_REVISION = "$nqpdir/tools/build/PARROT_REVISION";
+ 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 "$nqp_exe is NQP $nqp_have.\n";
+ return $nqp_exe;
+ }
+
+ my @cmd = ($^X, 'Configure.pl', "--with-parrot=$with_parrot",
+ "--make-install");
+ print "Building NQP ...\n";
+ chdir($nqpdir);
+ 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 $parrotdir = "$startdir/parrot";
+
+ 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 && -d $gen_parrot) {
+ $parrotdir = $gen_parrot;
+ print "Building Parrot from source in $parrotdir\n";
+ }
+ elsif ($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 "$par_exe is Parrot $par_have.\n";
+ return $par_exe;
+ }
+ chdir($parrotdir) 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');
+ chdir($startdir);
+
+ print "Parrot installed.\n";
+ return fill_template_text('@bindir@/parrot@exe@', %config);
+}
+
+
+1;