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