summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKiyoshi Aman <kiyoshi.aman+adelie@gmail.com>2019-05-09 20:05:54 -0500
committerKiyoshi Aman <kiyoshi.aman+adelie@gmail.com>2019-05-09 20:05:54 -0500
commite02d6c257630d6d5b694d7f0f931825f3fd08e03 (patch)
tree4d9634445cc65845d9d76f16cbc6005f88cb92c3
parentec3eeac15118f74309c4657804dd852c87011402 (diff)
downloaduserland-e02d6c257630d6d5b694d7f0f931825f3fd08e03.tar.gz
userland-e02d6c257630d6d5b694d7f0f931825f3fd08e03.tar.bz2
userland-e02d6c257630d6d5b694d7f0f931825f3fd08e03.tar.xz
userland-e02d6c257630d6d5b694d7f0f931825f3fd08e03.zip
build.pl: basic Perl-based buildsystem
-rwxr-xr-xbuild.pl138
1 files changed, 138 insertions, 0 deletions
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;