aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Ankarstrom <john@ankarstrom.se>2021-07-06 16:45:30 +0200
committerJohn Ankarstrom <john@ankarstrom.se>2021-07-06 16:46:24 +0200
commitf6e8218a332933d1a6c34421c8a1638cd726c7b4 (patch)
tree0d00a36e07a4eddb5299d801de5106a567d0aace
downloadbuild-f6e8218a332933d1a6c34421c8a1638cd726c7b4.tar.gz
Add 'build' script
-rwxr-xr-xbuild103
1 files changed, 103 insertions, 0 deletions
diff --git a/build b/build
new file mode 100755
index 0000000..b6d3653
--- /dev/null
+++ b/build
@@ -0,0 +1,103 @@
+#!/usr/bin/perl
+
+# build -- process and act on embedded build instructions
+
+use strict;
+use warnings;
+
+# parse arguments
+
+my ($debug, $fork) = (0, 0);
+my $usage = "usage: $0 [-dddf] file [...]\n";
+
+while (@ARGV and ($_ = $ARGV[0]) =~ /^-/) {
+ shift @ARGV;
+ last if $_ eq '--';
+ $debug++ for /(d)/g;
+ $fork++ if /f/;
+ die $usage if /[^-df]/;
+}
+
+die $usage if not @ARGV;
+
+# find build line(s) in each file
+
+my $i;
+for my $file (@ARGV) {
+ my ($cmd, $target, @deps);
+ open my $f, '<', $file or die "could not open $file: $!\n";
+ $i = 1;
+ while (<$f>) {
+ if (not $cmd and m{
+ ^ .*
+ (?: (?:build|generate) \s+ (?:it \s+)? with
+ | (?:built|generated) \s+ with
+ | the \s+ command
+ | run(?:ning)?
+ | issu(?:e|ing)
+ ) \s+
+ (.+?) \s* (?: > \s* (.+?))? \.? \s*
+ (?:\*/)? \s* $
+ }x) {
+ warn "$file build line: $_" if $debug > 2;
+ $cmd = $1;
+ $target = $2;
+ }
+ elsif (not @deps and m{
+ ^ .*
+ (?: depends \s+ on
+ | dependent \s+ on
+ ) \s+
+ (?: the \s+ files? \s+ )?
+ (.+?) \.? \s*
+ (?:\*/)? \s* $
+ }x) {
+ warn "$file dependency line: $_" if $debug > 2;
+ push @deps, $_ for split /,?\s+/, $1;
+ if ($deps[-2] eq 'and') {
+ $deps[-2] = $deps[-1];
+ pop @deps;
+ }
+ }
+ last if ++$i > 20;
+ }
+ warn "$file dependencies: @deps\n" if $debug > 1;
+ build($file, $cmd, $target, @deps) if $cmd;
+ warn "$file: no build line found\n" if not $cmd;
+}
+
+# build target according to build line
+
+sub build {
+ my ($source, $cmd, $target, @deps) = @_;
+ my $m = (stat$target)[9];
+
+ if (! -e $target) {
+ warn "$source: building because $target does not exist\n"
+ if $debug;
+ goto update;
+ }
+
+ for ($source, @deps) {
+ if (! -e $_) {
+ warn "$source: non-existent dependency '$_'\n";
+ next;
+ }
+ if ($m < (stat$_)[9]) {
+ warn "$source: building because $_ is modified\n"
+ if $debug;
+ goto update;
+ }
+ }
+ warn "$source: $target already up-to-date\n";
+ return;
+
+update:
+ warn "$source: $cmd > $target\n";
+ if ($fork) {
+ exec('/bin/sh', '-c', "$cmd > $target") if fork() == 0;
+ } else {
+ system("$cmd > $target");
+ }
+ return;
+}