From ffb8bd6e317de199d5c2482f68d90d554a00eb3c Mon Sep 17 00:00:00 2001
From: felix
Date: Sat, 20 Oct 2018 13:54:03 +0200
Subject: [PATCH] allow multiple targets in "chicken-do" invocations
To handle selective deletion of files generated by egg-builds, we need
a way to make targets are re-built when one of several generated
files are missing or out of date. This patch generalizes chicken-do(1)
to allow multiple targets. The reordering of the arguments is
inspired by a proposal from Kooda.
Signed-off-by: felix
---
chicken-do.c | 90 +++++++++++++++++++++++++++++++++++---------------
chicken-do.mdoc | 24 ++++++++------
egg-compile.scm | 101 ++++++++++++++++++++++++++++++++++----------------------
3 files changed, 140 insertions(+), 75 deletions(-)
diff --git a/chicken-do.c b/chicken-do.c
index c58acd7e..2923ca8c 100644
--- a/chicken-do.c
+++ b/chicken-do.c
@@ -39,22 +39,33 @@
#include
#include
-static char *target;
+#define MAX_TARGETS 256
+#define MAX_DEPENDS 1024
+
+static char *targets[ MAX_TARGETS ];
+static char *depends[ MAX_DEPENDS ];
+static struct stat tstats[ MAX_TARGETS ];
+static char **cmd;
+static int opts = 1;
+static int quiet = 0;
static void usage(int code)
{
- fputs("usage: chicken-do [-q] [-h] TARGET COMMAND ... : DEPENDENCIES ...\n", stderr);
+ fputs("usage: chicken-do [-q] [-h] [--] TARGET ... : DEPENDENCY ... : COMMAND ...\n", stderr);
exit(code);
}
static void cleanup()
{
+ char **t;
+
+ for(t = targets; *t != NULL; ++t)
#ifdef WIN32
- DeleteFile(target);
+ DeleteFile(*t);
#else
- unlink(target);
+ unlink(*t);
#endif
}
@@ -132,48 +143,75 @@ static int execute(char **argv)
int main(int argc, char *argv[])
{
- int i, count, a = 0;
- char **args = (char **)malloc(sizeof(char *) * argc);
- struct stat st, sd;
- int quiet = 0, opts = 1;
+ int i, a = 0;
+ struct stat *st, sd;
+ char **t = targets;
+ char **d = depends;
if(argc < 3) usage(1);
- target = argv[ 1 ];
+ for(i = 1; i < argc; ++i) {
+ if(!strcmp(argv[ i ], ":")) {
+ *t = NULL;
+ break;
+ }
- for(i = 2; i < argc; ++i) {
if(opts && *argv[ i ] == '-') {
switch(argv[ i ][ 1 ]) {
case 'q': quiet = 1; break;
case 'h': usage(0);
+ case '-': opts = 0; break;
default: usage(1);
}
}
- else if(!strcmp(argv[ i ], ":")) break;
- else {
- args[ a++ ] = argv[ i ];
- opts = 0;
+ else if(t >= targets + MAX_TARGETS) {
+ fprintf(stderr, "too many targets\n");
+ exit(1);
}
+ else *(t++) = argv[ i ];
}
if(i == argc) usage(1);
- args[ a ] = NULL;
+ while(++i < argc) {
+ if(!strcmp(argv[ i ], ":")) {
+ *d = NULL;
+ break;
+ }
- if(stat(target, &st) == -1) {
- if(errno == ENOENT) goto build;
+ if(d >= depends + MAX_DEPENDS) {
+ fprintf(stderr, "too many dependencies\n");
+ exit(1);
+ }
- fprintf(stderr, "%s: %s\n", target, strerror(errno));
- exit(1);
+ *(d++) = argv[ i ];
+ }
+
+ if(i == argc) usage(1);
+
+ cmd = argv + i + 1;
+ st = tstats;
+
+ for(t = targets; *t != NULL; ++t) {
+ if(stat(*t, st++) == -1) {
+ if(errno == ENOENT) goto build;
+
+ fprintf(stderr, "%s: %s\n", *t, strerror(errno));
+ exit(1);
+ }
}
- for(++i; i < argc; ++i) {
- if(stat(argv[ i ], &sd) == -1) {
- fprintf(stderr, "%s: %s\n", argv[ i ], strerror(errno));
+ for(d = depends; *d != NULL; ++d) {
+ if(stat(*d, &sd) == -1) {
+ fprintf(stderr, "%s: %s\n", *d, strerror(errno));
exit(1);
}
- if(sd.st_mtime > st.st_mtime) goto build;
+ st = tstats;
+
+ for(t = targets; *t != NULL; ++t) {
+ if(sd.st_mtime > (st++)->st_mtime) goto build;
+ }
}
return 0;
@@ -182,14 +220,14 @@ build:
if(!quiet) {
fputs(" ", stdout);
- for(i = 0; i < a; ++i)
- printf(" %s", args[ i ]);
+ for(t = cmd; *t != NULL; ++t)
+ printf(" %s", *t);
putchar('\n');
fflush(stdout);
}
- int s = execute(args);
+ int s = execute(cmd);
if(s != 0) cleanup();
diff --git a/chicken-do.mdoc b/chicken-do.mdoc
index 6b6e4d2d..20cf1697 100644
--- a/chicken-do.mdoc
+++ b/chicken-do.mdoc
@@ -35,33 +35,37 @@ not newer than the target
.Nm
.Op Fl q
.Op Fl h
-.Ar TARGET
-.Ar COMMAND ...
+.Op Fl -
+.Ar TARGET ...
.Cm :
.Ar DEPENDENCY ...
+.Cm :
+.Ar COMMAND ...
.Sh DESCRIPTION
-If the file
-.Em TARGET
-does not exist, or if any of the files in
+If the files
+.Em TARGET ...
+do not exist, or if any of the files in
.Em DEPENDENCY ...
-are newer than
-.Em TARGET ,
-then execute the shell commands in
+are newer than one of the target files, then execute the shell commands in
.Em COMMAND ... .
.Pp
-The program accepts following arguments:
+The program accepts the following options:
.Bl -tag -width Ds
.It Fl h
Show usage and exit.
.It Fl q
Quiet operation - do not print shell commands when they are executed.
+.It Fl -
+Treat all following tokens as target filenames, even if they begin with a
+.It -
+character.
.El
.Sh EXIT STATUS
.Ex -std
.Sh EXAMPLES
Build a C program from sources:
.Pp
-.Dl $ chicken-do prg gcc prg.c -o prg \& : prg.c inc.h
+.Dl $ chicken-do prg : prg.c inc.h : gcc prg.c -o prg
.Sh SEE ALSO
.Xr chicken 1 ,
.Xr chicken-status 1 ,
diff --git a/egg-compile.scm b/egg-compile.scm
index 52b4bded..e39ca66a 100644
--- a/egg-compile.scm
+++ b/egg-compile.scm
@@ -471,80 +471,95 @@
default-csc)
platform))
(sname (prefix srcdir name))
+ (tfile (qs* (prefix srcdir (conc types-file ".types"))
+ platform))
+ (ifile (qs* (prefix srcdir (conc inline-file ".inline"))
+ platform))
+ (lfile (qs* (conc sname +link-file-extension+) platform))
(opts (append (if (null? options)
default-static-compilation-options
options)
(if (and types-file
(not predefined-types))
- (list "-emit-types-file"
- (qs* (prefix srcdir (conc types-file ".types"))
- platform))
+ (list "-emit-types-file" tfile)
'())
(if inline-file
- (list "-emit-inline-file"
- (qs* (prefix srcdir (conc inline-file ".inline"))
- platform))
+ (list "-emit-inline-file" ifile)
'())))
(out (qs* (target-file (conc sname
".static"
(object-extension platform))
mode)
platform))
+ (targets (append (list out lfile)
+ (maybe types-file tfile)
+ (maybe inline-file ifile)))
(src (qs* (or source (conc name ".scm")) platform)))
(when custom
(prepare-custom-command cmd platform))
- (print "\n" (qs* default-builder platform #t) " " out " " cmd
+ (print "\n" (qs* default-builder platform #t) " "
+ (joins targets) " : "
+ src " " (qs* eggfile platform) " "
+ (if custom cmd "") " "
+ (filelist srcdir source-dependencies platform)
+ " : " cmd
(if keep-generated-files " -k" "")
" -setup-mode -static -I " srcdir
- " -emit-link-file "
- (qs* (conc sname +link-file-extension+) platform)
+ " -emit-link-file " lfile
(if (eq? mode 'host) " -host" "")
" -D compiling-extension -c -unit " name
" -D compiling-static-extension"
" -C -I" srcdir (arglist opts platform)
- " " src " -o " out " : "
- src " " (qs* eggfile platform) " "
- (if custom cmd "") " "
- (filelist srcdir source-dependencies platform))
+ " " src " -o " out)
(print-end-command platform)))
(define ((compile-dynamic-extension name #!key mode mode
source (options '()) (link-options '())
predefined-types eggfile
- source-dependencies
+ source-dependencies modules
custom types-file inline-file)
srcdir platform)
(let* ((cmd (qs* (or (custom-cmd custom srcdir platform)
default-csc)
platform))
(sname (prefix srcdir name))
+ (tfile (qs* (prefix srcdir (conc types-file ".types"))
+ platform))
+ (ifile (qs* (prefix srcdir (conc inline-file ".inline"))
+ platform))
(opts (append (if (null? options)
default-dynamic-compilation-options
options)
(if (and types-file
(not predefined-types))
- (list "-emit-types-file"
- (qs* (prefix srcdir (conc types-file ".types"))
- platform))
+ (list "-emit-types-file" tfile)
'())
(if inline-file
- (list "-emit-inline-file"
- (qs* (prefix srcdir (conc inline-file ".inline"))
- platform))
+ (list "-emit-inline-file" ifile)
'())))
(out (qs* (target-file (conc sname ".so") mode) platform))
+ (targets (append (list out)
+ (maybe inline-file ifile)
+ (maybe types-file tfile)
+ (map (lambda (m)
+ (qs* (prefix srcdir (conc m ".import.scm"))
+ platform))
+ modules)))
(src (qs* (or source (conc name ".scm")) platform)))
(when custom
(prepare-custom-command cmd platform))
- (print "\n" (qs* default-builder platform #t) " " out " " cmd
+ (print "\n" (qs* default-builder platform #t) " "
+ (joins targets) " : "
+ src " " (qs* eggfile platform) " "
+ (if custom cmd "") " "
+ (filelist srcdir source-dependencies platform)
+ " : " cmd
(if keep-generated-files " -k" "")
(if (eq? mode 'host) " -host" "")
" -D compiling-extension -J -s"
" -setup-mode -I " srcdir " -C -I" srcdir
(arglist opts platform) (arglist link-options platform)
- " " src " -o " out " : " src " " (qs* eggfile platform) " "
- (if custom cmd "") " "
- (filelist srcdir source-dependencies platform))
+ " " src " -o " out)
(print-end-command platform)))
(define ((compile-import-library name #!key mode
@@ -559,13 +574,14 @@
(out (qs* (target-file (conc sname ".import.so") mode)
platform))
(src (qs* (conc name ".import.scm") platform)))
- (print "\n" (qs* default-builder platform #t) " " out " " cmd
+ (print "\n" (qs* default-builder platform #t) " " out " : "
+ src (filelist srcdir source-dependencies platform)
+ " : " cmd
(if keep-generated-files " -k" "")
" -setup-mode -s"
(if (eq? mode 'host) " -host" "")
" -I " srcdir " -C -I" srcdir (arglist opts platform)
- (arglist link-options platform) " " src " -o " out " : "
- src (filelist srcdir source-dependencies platform))
+ (arglist link-options platform) " " src " -o " out)
(print-end-command platform)))
(define ((compile-dynamic-program name #!key source mode
@@ -587,15 +603,16 @@
(src (qs* (or source (conc name ".scm")) platform)))
(when custom
(prepare-custom-command cmd platform))
- (print "\n" (qs* default-builder platform #t) " " out " " cmd
+ (print "\n" (qs* default-builder platform #t) " " out " : "
+ src " " (qs* eggfile platform) " "
+ (if custom cmd "") " "
+ (filelist srcdir source-dependencies platform)
+ " : " cmd
(if keep-generated-files " -k" "")
" -setup-mode"
(if (eq? mode 'host) " -host" "")
" -I " srcdir " -C -I" srcdir (arglist opts platform)
- (arglist link-options platform) " " src " -o " out " : "
- src " " (qs* eggfile platform) " "
- (if custom cmd "") " "
- (filelist srcdir source-dependencies platform))
+ (arglist link-options platform) " " src " -o " out)
(print-end-command platform)))
(define ((compile-static-program name #!key source
@@ -617,15 +634,16 @@
(src (qs* (or source (conc name ".scm")) platform)))
(when custom
(prepare-custom-command cmd platform))
- (print "\n" (qs* default-builder platform #t) " " out " " cmd
+ (print "\n" (qs* default-builder platform #t) " " out " : "
+ src " " (qs* eggfile platform) " "
+ (if custom cmd "") " "
+ (filelist srcdir source-dependencies platform)
+ " : " cmd
(if keep-generated-files " -k" "")
(if (eq? mode 'host) " -host" "")
" -static -setup-mode -I " srcdir " -C -I"
srcdir (arglist opts platform)
- (arglist link-options platform) " " src " -o " out " : "
- src " " (qs* eggfile platform) " "
- (if custom cmd "") " "
- (filelist srcdir source-dependencies platform))
+ (arglist link-options platform) " " src " -o " out)
(print-end-command platform)))
(define ((compile-generated-file name #!key source custom
@@ -635,9 +653,10 @@
(out (qs* (or source name) platform)))
(prepare-custom-command cmd platform)
(print "\n" (qs* default-builder platform #t)
- " " out " " cmd " : " cmd " "
+ " " out " : " cmd " "
(qs* eggfile platform) " "
- (filelist srcdir source-dependencies platform))
+ (filelist srcdir source-dependencies platform)
+ " : " cmd)
(print-end-command platform)))
@@ -977,3 +996,7 @@ EOF
(p1 (substring fname 0 plen)))
(assert (string=? prefix p1) "wrong prefix")
(substring fname (add1 plen))))
+
+(define (joins strs) (string-intersperse strs " "))
+
+(define (maybe f x) (if f (list x) '()))
--
2.16.2