Path: utzoo!attcan!sobmips!uunet!aplcen!samsung!gem.mps.ohio-state.edu!apple!bbn!bbn.com!rsalz From: rsalz@bbn.com (Rich Salz) Newsgroups: comp.os.minix Subject: Re: cppmake - Part 1 of 2 Message-ID: <2153@papaya.bbn.com> Date: 13 Nov 89 18:34:04 GMT References: <1675@bruce.OZ> Organization: BBN Systems and Technologies Corporation Lines: 267 cppmake is pretty neat, but this is small and does something very similar. It was posted to comp.sources.misc about one to two years ago: #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'emake.c' <<'END_OF_FILE' X/* X** EMAKE X** Run /lib/cpp over Dmakefile (if necessary), then call make. X** There is a prolog file, the Dmakefile, and the epilog file; X** see the List variable to set these. X** X** This creates a makefile called MakeAuto, so you don't have to X** spend all that silly time in cpp if the Dmakefile hasn't changed. X*/ X#include X#include X#include X#include X#include X X#ifdef WAIT_UNION X#include X#define WAITVALUE(W) ((W).w_retcode) Xtypedef union wait WAITER; X#else X#define WAITVALUE(W) ((W) >> 8) Xtypedef int WAITER; X#endif /* WAIT_UNION */ X X X/* X** Handy shorthands. X*/ X#define STDOUT 1 X#define STDERR 2 X#define WHITE(c) ((c) == ' ' || (c) == '\t') X#define ENDOF(x) (sizeof x / sizeof x[0]) X X X/* X** Datatype and variable to hold the list of CPP directives that we should X** pass through (make's comment character is '#', which clashes). X*/ Xtypedef struct { X char Value[8]; X int Length; X} ALIST; X XALIST Directives[] = { X { "include", 7 }, X { "define", 6 }, X { "ifndef", 6 }, X { "ifdef", 5 }, X { "undef", 5 }, X { "endif", 5 }, X { "else", 4 }, X { "line", 4 }, X { "if", 2 }, X}; X X/* Other globals. */ Xchar INCLUDE_DIR[] = "-I/usr/cronus/include"; Xchar TempInput[] = "MakeIXXXXXX"; /* CPP input file */ Xchar TempOutput[] = "MakeOXXXXXX"; /* CPP output file */ Xchar DMAKEFILE[] = "Dmakefile"; /* Emake's makefile */ Xchar MAKEFILE[] = "MakeAuto"; /* Generated makefile */ Xchar *List[] = { /* Sources for emake */ X "/usr/cronus/clib/dmakedefs", X DMAKEFILE, X "/usr/cronus/clib/dtargets", X NULL X}; X X/* Linked in later. */ Xextern int errno; Xextern char *mktemp(); Xextern char *malloc(); X X X/* X** Print error message, clean up, and die. X*/ Xstatic void XQuit(s) X char *s; X{ X perror(s); X#ifndef DEBUG X if (unlink(TempInput) < 0 && errno != ENOENT) X perror("Error in unlink#1 in QUIT cleanup"); X if (unlink(TempOutput) < 0 && errno != ENOENT) X perror("Error in unlink#2 in QUIT cleanup"); X#endif /* DEBUG */ X _exit(1); X} X X X/* X** Pre-process the input files, building the make control file. X*/ Xstatic void XPrepare(Cargv) X char **Cargv; X{ X register ALIST *D; X register FILE *F; X register FILE *In; X register char *p; X register int i; X register int j; X WAITER W; X char **Name; X char buff[BUFSIZ]; X X /* Create tempfile for CPP input. */ X if ((F = fopen(TempInput, "w")) == NULL) X Quit(TempInput); X X /* Write each input file to the temporary output. */ X for (Name = List; *Name; Name++) { X if ((In = fopen(*Name, "r")) == NULL) X Quit(*Name); X X /* Read input, eliding #foo lines if foo is not a cpp directive. */ X fputs("# line 0 \"", F); X fputs(*Name, F); X fputs("\"\n", F); X while (fgets(buff, sizeof buff, In)) X if (buff[0] != '#') X fputs(buff, F); X else { X for (p = &buff[1]; *p && WHITE(*p); p++) X p++; X i = strlen(p); X for (D = Directives; D < ENDOF(Directives); D++) X if (i > D->Length X && strncmp(p, D->Value, D->Length) == 0 X && WHITE(p[D->Length])) { X fputs(buff, F); X break; X } X } X X fclose(In); X } X fclose(F); X X /* Create a file to hold the cpp output. */ X i = open(TempOutput, O_WRONLY | O_TRUNC | O_CREAT, 0666); X X /* Call the pre-processor. */ X if ((j = fork()) == 0) { X /* On some systems, dup and dup2 don't do the right thing. */ X if (close(STDOUT) < 0 || dup(i) != STDOUT) X perror("Error in CPP redirection"); X execv(Cargv[0], Cargv); X perror(Cargv[0]); X _exit(1); X } X X /* Wait for it. */ X while (wait(&W) != j) X ; X if (WAITVAL(W)) X Quit("CPP failure"); X X /* Copy cpp output to MAKEFILE, eliding all "#" lines. */ X close(i); X if ((In = fopen(TempOutput, "r")) == NULL) X Quit("Can't open output temporary"); X if ((F = fopen(MAKEFILE, "w")) == NULL) X Quit("Can't open final output file"); X fputs("## HANDS OFF THIS FILE--IT WAS AUTOMATICALLY CREATED!\n", F); X while (fgets(buff, sizeof buff, In)) X if (buff[0] != '#') X for (p = buff; *p && *p != '\n'; p++) X if (!WHITE(*p)) { X fputs(buff, F); X break; X } X fclose(In); X fclose(F); X if (unlink(TempInput) < 0 || unlink(TempOutput) < 0) X perror("Error in cleaning up temp files"); X} X X Xmain(ac, av) X int ac; X register char *av[]; X{ X register char **Margv; X register char **Cargv; X register char *p; X register int Mcount; X register int Ccount; X register int Force; X struct stat Sb1; X struct stat Sb2; X X /* Is it all there? */ X if (stat(DMAKEFILE, &Sb1) < 0) X Quit("Required file Dmakefile is missing"); X X /* Is Dmakefile newer than MakeFile? */ X Force = stat(MAKEFILE, &Sb2) < 0 || Sb1.st_mtime >= Sb2.st_mtime; X X /* Build argument list stubs. */ X Margv = (char **)malloc((unsigned int)(ac + 4) * sizeof (char *)); X Margv[0] = "make"; X Margv[1] = "-f"; X Margv[2] = MAKEFILE; X Cargv = (char **)malloc((unsigned int)(ac + 3) * sizeof (char *)); X Cargv[0] = "/lib/cpp"; X Cargv[1] = INCLUDE_DIR; X X /* Create spool files. */ X mktemp(TempInput); X mktemp(TempOutput); X X /* Scan arg list, moving "-Dxxx" to cpp, all other stuff to make. */ X for (Mcount = 3, Ccount = 2; p = *++av; ) X if (p[0] == '-' && (p[1] == 'D' || p[1] == 'U' || p[1] == 'I')) { X Force++; X Cargv[Ccount++] = p; X } X else X Margv[Mcount++] = p; X Cargv[Ccount++] = TempInput; X Cargv[Ccount] = NULL; X Margv[Mcount] = NULL; X X /* Rebuild MAKEFILE if necessary. */ X if (Force) { X write(STDERR, "Rebuilding...", sizeof "Rebuilding..." - 1); X Prepare(Cargv); X write(STDERR, " done\n", sizeof " done\n" - 1); X } X X /* Now have make do the real work. */ X execvp(Margv[0], Margv); X Quit(Margv[0]); X} END_OF_FILE if test 5787 -ne `wc -c <'emake.c'`; then echo shar: \"'emake.c'\" unpacked with wrong size! fi # end of 'emake.c' fi echo shar: End of shell archive. exit 0 -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.