Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
executable file 234 lines (194 sloc) 6.46 KB
#!/usr/bin/env perl6
# This is the template for the entire generated Makefile.
sub makefile_template() {
return q{
.PHONY: all build test install clean distclean purge
PERL6 = $binary
DESTDIR=
PREFIX = $prefix
BLIB = blib
P6LIB = $(PWD)/$(BLIB)/lib,$(PWD)/lib,$(PERL6LIB)
CP = cp -p
MKDIR = mkdir -p
$scripts
$blib_compiled
all build: $(BLIB_COMPILED)
$build_rules
test: build
env PERL6LIB=$(P6LIB) prove -e '$(PERL6)' -r t/
loudtest: build
env PERL6LIB=$(P6LIB) prove -ve '$(PERL6)' -r t/
timetest: build
env PERL6LIB=$(P6LIB) PERL6_TEST_TIMES=1 prove -ve '$(PERL6)' -r t/
install: $(BLIB_COMPILED)
$install_rules
clean:
rm -fr $(BLIB)
distclean purge: clean
rm -r Makefile
}
}
sub MAIN($filename = 'Makefile', Bool :$alpha) {
my $binary = $alpha ?? 'alpha' !! $*EXECUTABLE-NAME;
if $alpha {
note "Using 'alpha' as the Perl 6 binary. Please upgrade your code.";
}
my @modules = get_modules();
my @pods = get_pods();
my $scripts = get_scripts();
my $blib_compiled = join ' ', 'BLIB_COMPILED =', @modules>>.blib-compiled;
my $build_rules = join "\n", @modules>>.buildrule;
my $makefile = $filename eq '-' ?? $*OUT !! open $filename, :w;
my $install_rules = join '', @modules>>.install-rule;
if $scripts {
$install_rules ~= "\t\$(MKDIR) \$(DESTDIR)\$(PREFIX)/bin\n"
~ "\t\$(CP) \$(SCRIPTS) \$(DESTDIR)\$(PREFIX)/bin\n";
}
for @pods {
my $dir = .subst(rx{<-[/]>+$}, '');
$install_rules ~= "\t\$(MKDIR) \$(DESTDIR)\$(PREFIX)/$dir\n";
$install_rules ~= "\t\$(CP) $_ \$(DESTDIR)\$(PREFIX)/$dir\n";
}
$makefile.print(
makefile_template()\
.subst(/^\n/, '')\
.subst('$binary', $binary)\
.subst('$blib_compiled', $blib_compiled)\
.subst('$build_rules', $build_rules)\
.subst('$install_rules', $install_rules)\
.subst('$scripts', $scripts)\
.subst('$prefix', get_prefix())
);
$makefile.close;
}
sub get_scripts() {
if 'bin'.IO ~~ :d {
return 'SCRIPTS= ' ~ qx[echo bin/*].chomp;
}
return '';
}
my %VM_FORMATS =
parrot => { :target<pir>, :extension<.pir> },
jvm => { :target<jar>, :extension<.jar> },
moar => { :target<mbc>, :extension<.moarvm> },
;
my $format = %VM_FORMATS{ $*VM.name } //
die "Unrecognized backend '$*VM<name>'. Please contact your local VM representative.";
class Module {
has $.lib-pm;
has @.dependencies is rw;
has $.target = $format<target>;
has $.extension = $format<extension>;
method name { path-to-module-name($.lib-pm) }
method lib-dir { $.lib-pm.subst(rx{<-[/]>+$}, '') }
method blib-compiled { $.blib-pm ~ $.extension }
method blib-pm { q[$(BLIB)/] ~ $.lib-pm }
method blib-dir { $.blib-pm.subst(rx{<-[/]>+$}, '') }
method buildrule {
my $header = join(' ', $.blib-compiled, ':', $.lib-pm, @.dependencies>>.blib-compiled);
my $mkdir = q[$(MKDIR) ] ~ $.blib-dir;
my $copy = join ' ', '$(CP)', $.lib-pm, $.blib-pm;
my $compile = "PERL6LIB=\$(P6LIB) \$(PERL6) --target=$.target --output=$.blib-compiled $.lib-pm";
return "$header\n\t$mkdir\n\t$copy\n\t$compile\n";
}
method install-compiled { '$(DESTDIR)$(PREFIX)/' ~ $.lib-pm ~ $.extension }
method install-pm { '$(DESTDIR)$(PREFIX)/' ~ $.lib-pm }
method install-rule {
my $rule =join '',
map { "\t$_\n" },
'$(MKDIR) $(DESTDIR)$(PREFIX)/' ~ $.lib-dir,
'$(CP) ' ~ $.blib-pm ~ ' ' ~ $.install-pm,
'$(CP) ' ~ $.blib-compiled ~ ' ' ~ $.install-compiled;
}
}
sub get_pods() {
find-file-by-ext(<lib6 lib>, 'pod');
}
sub get_modules() {
my @module-files = find-file-by-ext(<lib lib6>, <pm pm6>);
my @modules = @module-files.map: { Module.new(lib-pm => $_) };
my %modules-by-name = @modules>>.name Z=> @modules;
for @modules {
# The grep is needed because 'find' prints a final newline, so there'll be an
# empty-string element at the end of the list.
.dependencies.append: %modules-by-name{ flat dependencies(.lib-pm) }.grep: *.defined
}
return @modules;
}
sub get_prefix() {
my @tried;
for <site home> -> $loc {
my $path = %*CUSTOM_LIB{$loc};
push @tried, $path;
mkpath(~$path);
next unless $path.IO.d;
say 'WARNING: You need to re-run ufo whenever you ',
$loc eq 'site' ?? 'update to a new Rakudo version'
!! 'recompile Rakudo';
return $path;
}
die "Could not find a writable installation location (tried @tried.join(' and'))";
}
# blatantly stolen from Shell::Command
sub mkpath($path) {
for [\~] $path.split('/').map({"$_/"}) {
mkdir($_) unless .IO.d
}
}
sub dependencies($filename) {
sub strip_pod(Str $code is copy --> Str) {
my regex ident { \w+ }
my regex delimited-pod-block {
^^
\s*
'=begin'
\s+
<ident>
.*
# XXX match same leading indent?
'=end'
\s+
<ident> # XXX match same ident?
}
while $code ~~ /<delimited-pod-block>/ {
$code = $code.substr(0, $/.from) ~ $code.substr($/.to);
}
$code
}
my @deps;
my $code = slurp($filename);
$code = strip_pod($code);
gather for $code.lines() {
if /^\s* ['use'|'need'] \s+ (\w+ ['::' \w+]*)/ && $0 -> $used {
next if $used eq 'v6';
next if $used eq 'MONKEY_TYPING';
next if $used eq 'fatal';
take ~$used;
}
}
}
# 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($path) {
$path.subst(/^'lib/'/, '').subst(/^'lib6/'/, '').subst(/\.pm6?$/, '').subst('/', '::', :g);
}
sub find-file-by-ext(@dirs, *@ext) {
my $ext-re = @ext.join('|');
my $f = rx/\. <{ $ext-re }> $ /; # RAKUDO: should just be \. @ext $
gather for @dirs {
dirwalk($_, :$f, :fx(&take)) if .IO.d;
}
}
sub dirwalk(Str $dir = '.', Mu :$d = none(<. ..>), Mu :$f = *, :&dx = -> $ {}, :&fx = -> $ {}) {
for dir($dir) -> $p {
when $p.f {
fx($p.Str) if $p.Str ~~ $f;
}
when $p.d {
dirwalk($p.Str, :$d, :$f, :&dx, :&fx)
}
}
dx($dir) if $dir ~~ $d;
}
# vim: ft=perl6