#include <sys/wait.h>
#include <unistd.h>
+#ifdef __APPLE__
+#define DYEXT ".dylib"
+#else
+#define DYEXT ".so"
+#endif
+
extern char **environ;
char **cflags, **lflags;
exit(EXIT_FAILURE);
}
-void *alloc(size_t size) {
+void *alloc(size_t s) {
void *r;
- if (!(r = malloc(size))) error("Memory allocation");
+ if (!(r = malloc(s))) error("Memory allocation");
return r;
}
char *extend(char *path, char *ext) {
- char *bp, *ep, *rp, *tp;
- int d, b, e, l;
+ char *bp, *ep, *r, *p;
+ size_t d, b, l, e;
if (!path) return NULL;
d = bp - path;
b = (ep = strrchr(bp, '.')) ? ep - bp : (ep = ext, strlen(bp));
if (*ext == '!') ep = ext + 1;
+ l = strcmp(ep, ".a") == 0 || strcmp(ep, DYEXT) == 0 ? 3 : 0;
e = strlen(ep);
- l = strncmp(ep, ".a", e) == 0 || strncmp(ep, ".dylib", e) == 0 ? 3 : 0;
- tp = rp = alloc(d + l + b + e + 1);
- tp = stpncpy(tp, path, d);
- tp = stpncpy(tp, "lib", l);
- tp = stpncpy(tp, bp, b);
- stpncpy(tp, ep, e + 1);
+ p = r = alloc(d + l + b + e + 1);
+ p = stpncpy(p, path, d);
+ p = stpncpy(p, "lib", l);
+ p = stpncpy(p, bp, b);
+ strcpy(p, ep);
- return rp;
+ return r;
}
int modified(char *target, char *dep) {
struct stat tstat, dstat;
- if (stat(target, &tstat) == -1 && errno != ENOENT)
+ if (stat(target, &tstat) == -1) {
+ if (errno == ENOENT) return !(errno = 0);
error("Unable to stat `%s'", target);
+ }
if (stat(dep, &dstat) == -1) error("Unable to stat `%s'", dep);
- return errno == ENOENT || tstat.st_mtime < dstat.st_mtime;
+ return tstat.st_mtime < dstat.st_mtime;
}
void run(char *path, char **args, char *what, char *who) {
- int i;
+ size_t i;
for (i = 0; args[i]; ++i) printf("%s ", args[i]);
printf("\n");
error("Unable to run %s of `%s'", what, who);
}
-void await(int cpid, char *what, char *who) {
+void await(pid_t cpid, char *what, char *who) {
int status;
if (cpid == -1) error("Unable to delegate the %s of `%s'", what, who);
}
void compile(char *src, ...) {
- int fn, cpid;
+ size_t f;
char **args, **p, *obj, *dep;
va_list deps;
+ pid_t cpid;
- fn = 0;
- if (cflags) while (cflags[fn]) ++fn;
- p = args = alloc((5 + fn + 1) * sizeof*args);
+ if (f = 0, cflags) while (cflags[f]) ++f;
+ p = args = alloc((5 + f + 1) * sizeof*args);
*p++ = "cc";
- if (cflags) for (fn = 0; cflags[fn]; *p++ = cflags[fn++]);
+ if (cflags) for (f = 0; cflags[f]; *p++ = cflags[f++]);
*p++ = "-c";
*p++ = "-o";
*p++ = obj = extend(src, "!.o");
*p++ = src = extend(src, ".c");
*p = NULL;
- dep = strdup(src);
+ dep = src;
va_start(deps, src);
do if (modified(obj, dep)) {
if ((cpid = fork()) == 0) run("/usr/bin/cc", args, "compilation", src);
} while (free(dep), dep = extend(va_arg(deps, char *), ".h"));
va_end(deps);
- free(src);
free(obj);
free(args);
}
void load(char type, char *target, char *obj, ...) {
- int fn, vn, cpid;
va_list count, objs;
- char **args, **p, *path, **o;
+ size_t o, f;
+ char **args, **p, *path, **fp, **a;
+ pid_t cpid;
- fn = 0;
- if (lflags) while (lflags[fn]) ++fn;
va_start(count, obj);
va_copy(objs, count);
- for (vn = 0; va_arg(count, char *); ++vn);
+ for (o = 1; va_arg(count, char *); ++o);
va_end(count);
- p = args = alloc((5 + fn + vn + 1) * sizeof*args);
+ if (f = 0, lflags) while (lflags[f]) ++f;
+ args = alloc((4 + o + f + 1) * sizeof*args);
- path = "/usr/bin/cc";
- *p++ = "cc";
+ p = args + 1;
switch (type) {
case 'd':
- *p++ = "-dynamiclib";
+ *p++ = "-shared";
+ target = extend(target, DYEXT);
case 'x':
- if (lflags) for (fn = 0; lflags[fn]; *p++ = lflags[fn++]);
+ path = "/usr/bin/cc";
+ *args = "cc";
*p++ = "-o";
- *p++ = target = type == 'd' ? extend(target, ".dylib") : strdup(target);
+ fp = p + o + 1;
+ a = args + 3;
break;
case 's':
path = "/usr/bin/ar";
- *(p - 1) = "ar";
+ *args = "ar";
*p++ = "-r";
- *p++ = target = extend(target, ".a");
+ fp = p;
+ a = p += f;
+ target = extend(target, ".a");
break;
default:
error("Unknown linking type `%c'", type);
}
- o = p;
- *o++ = extend(obj, ".o");
- while ((*o++ = extend(va_arg(objs, char *), ".o")));
+ *p++ = target;
+ *p++ = extend(obj, ".o");
+ while ((*p = extend(va_arg(objs, char *), ".o"))) ++p;
va_end(objs);
+ if (lflags) for (f = 0; lflags[f]; *fp++ = lflags[f++]);
+ if (fp > p) *fp = NULL;
+ fp = p;
- o = p;
- while (*o) if (modified(target, *o++)) {
+ p -= o;
+ while (o--) if (modified(target, *p++)) {
if ((cpid = fork()) == 0) run(path, args, "linking", target);
await(cpid, "linking", target);
break;
}
- while (*p) free(*p++);
- free(target);
+ while (a != fp) free(*a++);
free(args);
}
void build(char *path) {
- int cpid;
+ pid_t cpid;
if (path) {
if ((cpid = fork())) {