From c012d8b882480151d8eb7da92c4cca80d1d9b814 Mon Sep 17 00:00:00 2001 From: pmichaud Date: Tue, 28 Aug 2012 00:36:53 -0500 Subject: Move skel/ into top-level directory, to try building directly from the repo. --- tools/build/Makefile.in | 162 +++++++++++++++++++ tools/build/bin-install.pl | 28 ++++ tools/build/module-install.pl | 112 +++++++++++++ tools/build/star-product.wxs | 68 ++++++++ tools/lib/NQP/Configure.pm | 365 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 735 insertions(+) create mode 100644 tools/build/Makefile.in create mode 100644 tools/build/bin-install.pl create mode 100644 tools/build/module-install.pl create mode 100644 tools/build/star-product.wxs create mode 100644 tools/lib/NQP/Configure.pm (limited to 'tools') 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//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 " + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + 1 + + 1 + + 1 + + 1 + 1 + 1 + + + + + + + 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{ (?@?[ \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; -- cgit v1.1