From e02d6c257630d6d5b694d7f0f931825f3fd08e03 Mon Sep 17 00:00:00 2001 From: Kiyoshi Aman Date: Thu, 9 May 2019 20:05:54 -0500 Subject: build.pl: basic Perl-based buildsystem --- build.pl | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100755 build.pl (limited to 'build.pl') diff --git a/build.pl b/build.pl new file mode 100755 index 0000000..7662e05 --- /dev/null +++ b/build.pl @@ -0,0 +1,138 @@ +#!/usr/bin/env perl + +use strict; +use warnings; +use autodie; +use feature qw(say); +use constant { + CC => $ENV{CC} // 'gcc', + CFLAGS => $ENV{CFLAGS}, + LDFLAGS => $ENV{LDFLAGS}, + LIBS => $ENV{LIBS}, + DESTDIR => $ENV{DESTDIR}, +}; + +use Cwd; +use Getopt::Long; + +my $DRYRUN = 0; +my $BUILDROOT = getcwd . '/build'; + +sub _scan_src { + my ($path) = @_; + + my %project = (); + + # directory possibly containing projects + opendir(my $d, $path); + for my $ent (readdir $d) { + next if ($ent =~ /^\./); + if (-d "$path/$ent") { + $project{$ent} = {}; + my @outputs = (); + my @files = (); + + # this is a project + opendir(my $dh, "$path/$ent"); + for my $subent (readdir $dh) { + next unless (-e "$path/$ent/$subent"); + if ($subent =~ /\.c$/) { + push @files, $subent; + } elsif ($subent =~ /\.\d$/) { + my @frags = split /\./, $subent, 2; + push @outputs, $frags[0]; + } + } + + $project{$ent}{outputs} = \@outputs; + $project{$ent}{files} = \@files; + } + } + + return \%project; +} + +sub build { + my %bin = %{ _scan_src "bin" }; + my %ubin = %{ _scan_src "usr.bin" }; + + unless (-d $BUILDROOT) { + system('mkdir', '-p', $BUILDROOT) == 0 or die "Couldn't create buildroot: $?\n"; + } + + for my $project (keys %bin) { + build_project('bin', $project, $bin{$project}{outputs}, $bin{$project}{files}); + } + for my $project (keys %ubin) { + build_project('usr.bin', $project, $ubin{$project}{outputs}, $ubin{$project}{files}); + } +} + +sub build_project { + my ($path, $project, $outputs, $files) = @_; + my @outputs = @{ $outputs }; + my @files = @{ $files }; + my (@cflags, @ldflags, @libs); + if (defined(CFLAGS)) { @cflags = split(' ', CFLAGS); } else { @cflags = (); } + if (defined(LDFLAGS)) { @ldflags = split(' ', LDFLAGS); } else { @ldflags = (); } + if (defined(LIBS)) { @libs = split(' ', LIBS); } else { @libs = (); } + + chdir "$path/$project"; + for my $target (@outputs) { + my @args = ('-o', "$BUILDROOT/$target"); + push @args, @cflags, @ldflags, @libs, @files; + if ($DRYRUN) { + say 'Would exec ' . CC . ' ' . join ' ', @args; + } else { + system(CC, @args) == 0 or die "Failed to compile $project/$target: $?\n"; + } + } + chdir "../.."; +} + +sub install { + my %bin = %{ _scan_src "bin" }; + my %ubin = %{ _scan_src "usr.bin" }; + + for my $project (keys %bin) { + install_project('bin', $project, $bin{$project}{outputs}); + } + for my $project (keys %ubin) { + install_project('usr/bin', $project, $ubin{$project}{files}); + } +} + +sub install_project { + my ($path, $project, @outputs) = @_; + + system 'mkdir', '-p', DESTDIR . "/$path" == 0 or die "Failed to create target path: $?\n"; + for my $target (@outputs) { + my @args = ('-Dm755', "$BUILDROOT/$target", DESTDIR . "/$path/$target"); + if ($DRYRUN) { + say 'Would exec install ' . join ' ', @args; + } else { + system('install', @args) == 0 or die "Failed to install $target: $?"; + } + } +} + +my %modes = ( + 'build' => \&build, + 'install' => \&install, +); + +sub main { + GetOptions( + 'buildroot=s' => \$BUILDROOT, + 'dry-run' => \$DRYRUN, + ) or die "Unrecognied commandline options.\n"; + my $mode = 'build'; + + if (@ARGV > 0) { + $mode = $ARGV[0]; + } + say $mode . 'ing...'; + $modes{$mode}->(); +} + +main; -- cgit v1.2.3-60-g2f50