#!/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;