summaryrefslogblamecommitdiff
path: root/build.pl
blob: 7662e0598042f4248886fed091d1575ff66a5a6b (plain) (tree)









































































































































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