crunchgen.c revision 68750
11722Sjkh/* 21722Sjkh * Copyright (c) 1994 University of Maryland 31722Sjkh * All Rights Reserved. 41722Sjkh * 51722Sjkh * Permission to use, copy, modify, distribute, and sell this software and its 61722Sjkh * documentation for any purpose is hereby granted without fee, provided that 71722Sjkh * the above copyright notice appear in all copies and that both that 81722Sjkh * copyright notice and this permission notice appear in supporting 91722Sjkh * documentation, and that the name of U.M. not be used in advertising or 101722Sjkh * publicity pertaining to distribution of the software without specific, 111722Sjkh * written prior permission. U.M. makes no representations about the 121722Sjkh * suitability of this software for any purpose. It is provided "as is" 131722Sjkh * without express or implied warranty. 141722Sjkh * 151722Sjkh * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 161722Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. 171722Sjkh * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 181722Sjkh * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 191722Sjkh * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 201722Sjkh * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 211722Sjkh * 221722Sjkh * Author: James da Silva, Systems Design and Analysis Group 231722Sjkh * Computer Science Department 241722Sjkh * University of Maryland at College Park 2556995Sluigi * 2656995Sluigi * $FreeBSD: head/usr.sbin/crunch/crunchgen/crunchgen.c 68750 2000-11-15 14:33:29Z joe $ 271722Sjkh */ 281722Sjkh/* 291722Sjkh * ======================================================================== 301722Sjkh * crunchgen.c 311722Sjkh * 321722Sjkh * Generates a Makefile and main C file for a crunched executable, 338857Srgrimes * from specs given in a .conf file. 341722Sjkh */ 3529453Scharnier#include <ctype.h> 3629453Scharnier#include <err.h> 3729453Scharnier#include <stdio.h> 381722Sjkh#include <stdlib.h> 3929453Scharnier#include <string.h> 401722Sjkh#include <unistd.h> 411722Sjkh 421722Sjkh#include <sys/types.h> 431722Sjkh#include <sys/stat.h> 441722Sjkh#include <sys/param.h> 451722Sjkh 461722Sjkh#define CRUNCH_VERSION "0.2" 471722Sjkh 481722Sjkh#define MAXLINELEN 16384 491722Sjkh#define MAXFIELDS 2048 501722Sjkh 511722Sjkh 521722Sjkh/* internal representation of conf file: */ 531722Sjkh 541722Sjkh/* simple lists of strings suffice for most parms */ 551722Sjkh 561722Sjkhtypedef struct strlst { 571722Sjkh struct strlst *next; 581722Sjkh char *str; 591722Sjkh} strlst_t; 601722Sjkh 611722Sjkh/* progs have structure, each field can be set with "special" or calculated */ 621722Sjkh 631722Sjkhtypedef struct prog { 6456995Sluigi struct prog *next; /* link field */ 6556995Sluigi char *name; /* program name */ 6656995Sluigi char *ident; /* C identifier for the program name */ 6756995Sluigi char *srcdir; 6856995Sluigi char *objdir; 6956995Sluigi char *objvar; /* Makefile variable to replace OBJS */ 701722Sjkh strlst_t *objs, *objpaths; 7168569Sjoe strlst_t *buildopts; 7230120Sjoerg strlst_t *keeplist; 731722Sjkh strlst_t *links; 741722Sjkh int goterror; 751722Sjkh} prog_t; 761722Sjkh 771722Sjkh 781722Sjkh/* global state */ 791722Sjkh 8068750Sjoestrlst_t *buildopts = NULL; 811722Sjkhstrlst_t *srcdirs = NULL; 821722Sjkhstrlst_t *libs = NULL; 831722Sjkhprog_t *progs = NULL; 841722Sjkh 851722Sjkhchar line[MAXLINELEN]; 861722Sjkh 871722Sjkhchar confname[MAXPATHLEN], infilename[MAXPATHLEN]; 881722Sjkhchar outmkname[MAXPATHLEN], outcfname[MAXPATHLEN], execfname[MAXPATHLEN]; 891722Sjkhchar tempfname[MAXPATHLEN], cachename[MAXPATHLEN], curfilename[MAXPATHLEN]; 9056995Sluigichar outhdrname[MAXPATHLEN] ; /* user-supplied header for *.mk */ 911722Sjkhint linenum = -1; 921722Sjkhint goterror = 0; 931722Sjkh 941722Sjkhint verbose, readcache; /* options */ 951722Sjkhint reading_cache; 9668286Sjoeint makeobj = 0; /* add 'make obj' rules to the makefile */ 971722Sjkh 986696Sphkint list_mode; 996696Sphk 1001722Sjkh/* general library routines */ 1011722Sjkh 1021722Sjkhvoid status(char *str); 1031722Sjkhvoid out_of_memory(void); 1041722Sjkhvoid add_string(strlst_t **listp, char *str); 1051722Sjkhint is_dir(char *pathname); 1061722Sjkhint is_nonempty_file(char *pathname); 1071722Sjkh 1081722Sjkh/* helper routines for main() */ 1091722Sjkh 1108857Srgrimesvoid usage(void); 1111722Sjkhvoid parse_conf_file(void); 1121722Sjkhvoid gen_outputs(void); 1131722Sjkh 1141722Sjkh 1151722Sjkhint main(int argc, char **argv) 1161722Sjkh{ 1171722Sjkh char *p; 1181722Sjkh int optc; 1191722Sjkh 1201722Sjkh verbose = 1; 1211722Sjkh readcache = 1; 1221722Sjkh *outmkname = *outcfname = *execfname = '\0'; 1238857Srgrimes 12468286Sjoe while((optc = getopt(argc, argv, "lh:m:c:e:foq")) != -1) { 1251722Sjkh switch(optc) { 1261722Sjkh case 'f': readcache = 0; break; 12768286Sjoe case 'o': makeobj = 1; break; 1281722Sjkh case 'q': verbose = 0; break; 1291722Sjkh 1301722Sjkh case 'm': strcpy(outmkname, optarg); break; 13156995Sluigi case 'h': strcpy(outhdrname, optarg); break; 1321722Sjkh case 'c': strcpy(outcfname, optarg); break; 1331722Sjkh case 'e': strcpy(execfname, optarg); break; 1346696Sphk case 'l': list_mode++; verbose = 0; break; 1351722Sjkh 1361722Sjkh case '?': 1371722Sjkh default: usage(); 1381722Sjkh } 1391722Sjkh } 1401722Sjkh 1411722Sjkh argc -= optind; 1421722Sjkh argv += optind; 1431722Sjkh 1441722Sjkh if(argc != 1) usage(); 1451722Sjkh 1468857Srgrimes /* 1471722Sjkh * generate filenames 1481722Sjkh */ 1491722Sjkh 1501722Sjkh strcpy(infilename, argv[0]); 1511722Sjkh 1521722Sjkh /* confname = `basename infilename .conf` */ 1531722Sjkh 1541722Sjkh if((p=strrchr(infilename, '/')) != NULL) strcpy(confname, p+1); 1551722Sjkh else strcpy(confname, infilename); 1561722Sjkh if((p=strrchr(confname, '.')) != NULL && !strcmp(p, ".conf")) *p = '\0'; 1571722Sjkh 1581722Sjkh if(!*outmkname) sprintf(outmkname, "%s.mk", confname); 1591722Sjkh if(!*outcfname) sprintf(outcfname, "%s.c", confname); 1601722Sjkh if(!*execfname) sprintf(execfname, "%s", confname); 1611722Sjkh 1621722Sjkh sprintf(cachename, "%s.cache", confname); 1631722Sjkh sprintf(tempfname, ".tmp_%sXXXXXX", confname); 1641722Sjkh if(mktemp(tempfname) == NULL) { 1651722Sjkh perror(tempfname); 1661722Sjkh exit(1); 1671722Sjkh } 1681722Sjkh 1691722Sjkh parse_conf_file(); 1706696Sphk if (list_mode) 1716696Sphk exit(goterror); 1726696Sphk 1731722Sjkh gen_outputs(); 1741722Sjkh 1751722Sjkh exit(goterror); 1761722Sjkh} 1771722Sjkh 1781722Sjkh 1791722Sjkhvoid usage(void) 1801722Sjkh{ 18129453Scharnier fprintf(stderr, "%s\n%s\n", 18268286Sjoe "usage: crunchgen [-foq] [-m <makefile>] [-c <c file>]", 18329453Scharnier " [-e <exec file>] <conffile>"); 1841722Sjkh exit(1); 1851722Sjkh} 1861722Sjkh 1871722Sjkh 1881722Sjkh/* 1891722Sjkh * ======================================================================== 1901722Sjkh * parse_conf_file subsystem 1911722Sjkh * 1921722Sjkh */ 1931722Sjkh 1941722Sjkh/* helper routines for parse_conf_file */ 1951722Sjkh 1961722Sjkhvoid parse_one_file(char *filename); 1978857Srgrimesvoid parse_line(char *line, int *fc, char **fv, int nf); 1981722Sjkhvoid add_srcdirs(int argc, char **argv); 1991722Sjkhvoid add_progs(int argc, char **argv); 2001722Sjkhvoid add_link(int argc, char **argv); 2011722Sjkhvoid add_libs(int argc, char **argv); 20268750Sjoevoid add_buildopts(int argc, char **argv); 2031722Sjkhvoid add_special(int argc, char **argv); 2041722Sjkh 2051722Sjkhprog_t *find_prog(char *str); 2061722Sjkhvoid add_prog(char *progname); 2071722Sjkh 2081722Sjkh 2091722Sjkhvoid parse_conf_file(void) 2101722Sjkh{ 21129453Scharnier if(!is_nonempty_file(infilename)) 21229453Scharnier errx(1, "fatal: input file \"%s\" not found", infilename); 2131722Sjkh parse_one_file(infilename); 2141722Sjkh if(readcache && is_nonempty_file(cachename)) { 2151722Sjkh reading_cache = 1; 2161722Sjkh parse_one_file(cachename); 2171722Sjkh } 2181722Sjkh} 2191722Sjkh 2201722Sjkh 2211722Sjkhvoid parse_one_file(char *filename) 2221722Sjkh{ 2231722Sjkh char *fieldv[MAXFIELDS]; 2241722Sjkh int fieldc; 2251722Sjkh void (*f)(int c, char **v); 2261722Sjkh FILE *cf; 2271722Sjkh 2281722Sjkh sprintf(line, "reading %s", filename); 2291722Sjkh status(line); 2301722Sjkh strcpy(curfilename, filename); 2311722Sjkh 2321722Sjkh if((cf = fopen(curfilename, "r")) == NULL) { 23329453Scharnier warn("%s", curfilename); 2341722Sjkh goterror = 1; 2351722Sjkh return; 2361722Sjkh } 2371722Sjkh 2381722Sjkh linenum = 0; 2391722Sjkh while(fgets(line, MAXLINELEN, cf) != NULL) { 2401722Sjkh linenum++; 2411722Sjkh parse_line(line, &fieldc, fieldv, MAXFIELDS); 2421722Sjkh if(fieldc < 1) continue; 2431722Sjkh if(!strcmp(fieldv[0], "srcdirs")) f = add_srcdirs; 2441722Sjkh else if(!strcmp(fieldv[0], "progs")) f = add_progs; 2451722Sjkh else if(!strcmp(fieldv[0], "ln")) f = add_link; 2461722Sjkh else if(!strcmp(fieldv[0], "libs")) f = add_libs; 24768750Sjoe else if(!strcmp(fieldv[0], "buildopts")) f = add_buildopts; 2481722Sjkh else if(!strcmp(fieldv[0], "special")) f = add_special; 2491722Sjkh else { 25029453Scharnier warnx("%s:%d: skipping unknown command `%s'", 2511722Sjkh curfilename, linenum, fieldv[0]); 2521722Sjkh goterror = 1; 2531722Sjkh continue; 2541722Sjkh } 2551722Sjkh if(fieldc < 2) { 25629453Scharnier warnx("%s:%d: %s command needs at least 1 argument, skipping", 2571722Sjkh curfilename, linenum, fieldv[0]); 2581722Sjkh goterror = 1; 2591722Sjkh continue; 2601722Sjkh } 2611722Sjkh f(fieldc, fieldv); 2621722Sjkh } 2631722Sjkh 2641722Sjkh if(ferror(cf)) { 26529453Scharnier warn("%s", curfilename); 2661722Sjkh goterror = 1; 2671722Sjkh } 2681722Sjkh fclose(cf); 2691722Sjkh} 2701722Sjkh 2711722Sjkh 2721722Sjkhvoid parse_line(char *line, int *fc, char **fv, int nf) 2731722Sjkh{ 2741722Sjkh char *p; 2751722Sjkh 2761722Sjkh p = line; 2771722Sjkh *fc = 0; 2781722Sjkh while(1) { 2791722Sjkh while(isspace(*p)) p++; 2801722Sjkh if(*p == '\0' || *p == '#') break; 2811722Sjkh 2821722Sjkh if(*fc < nf) fv[(*fc)++] = p; 2831722Sjkh while(*p && !isspace(*p) && *p != '#') p++; 2841722Sjkh if(*p == '\0' || *p == '#') break; 2851722Sjkh *p++ = '\0'; 2861722Sjkh } 2871722Sjkh if(*p) *p = '\0'; /* needed for '#' case */ 2881722Sjkh} 2891722Sjkh 2901722Sjkh 2911722Sjkhvoid add_srcdirs(int argc, char **argv) 2921722Sjkh{ 2931722Sjkh int i; 2941722Sjkh 2951722Sjkh for(i=1;i<argc;i++) { 2961722Sjkh if(is_dir(argv[i])) 2971722Sjkh add_string(&srcdirs, argv[i]); 2981722Sjkh else { 29929453Scharnier warnx("%s:%d: `%s' is not a directory, skipping it", 3001722Sjkh curfilename, linenum, argv[i]); 3011722Sjkh goterror = 1; 3021722Sjkh } 3031722Sjkh } 3041722Sjkh} 3051722Sjkh 3061722Sjkh 3071722Sjkhvoid add_progs(int argc, char **argv) 3081722Sjkh{ 3091722Sjkh int i; 3101722Sjkh 3111722Sjkh for(i=1;i<argc;i++) 3121722Sjkh add_prog(argv[i]); 3131722Sjkh} 3141722Sjkh 3151722Sjkh 3161722Sjkhvoid add_prog(char *progname) 3171722Sjkh{ 3181722Sjkh prog_t *p1, *p2; 3191722Sjkh 3201722Sjkh /* add to end, but be smart about dups */ 3211722Sjkh 3221722Sjkh for(p1 = NULL, p2 = progs; p2 != NULL; p1 = p2, p2 = p2->next) 3231722Sjkh if(!strcmp(p2->name, progname)) return; 3241722Sjkh 3251722Sjkh p2 = malloc(sizeof(prog_t)); 32619822Sjoerg if(p2) { 32719822Sjoerg memset(p2, 0, sizeof(prog_t)); 32819822Sjoerg p2->name = strdup(progname); 32919822Sjoerg } 3308857Srgrimes if(!p2 || !p2->name) 3311722Sjkh out_of_memory(); 3321722Sjkh 3331722Sjkh p2->next = NULL; 3341722Sjkh if(p1 == NULL) progs = p2; 3351722Sjkh else p1->next = p2; 3361722Sjkh 3371722Sjkh p2->ident = p2->srcdir = p2->objdir = NULL; 33830120Sjoerg p2->links = p2->objs = p2->keeplist = NULL; 33968569Sjoe p2->buildopts = NULL; 3401722Sjkh p2->goterror = 0; 3416696Sphk if (list_mode) 3426696Sphk printf("%s\n",progname); 3431722Sjkh} 3441722Sjkh 3451722Sjkh 3461722Sjkhvoid add_link(int argc, char **argv) 3471722Sjkh{ 3481722Sjkh int i; 3491722Sjkh prog_t *p = find_prog(argv[1]); 3501722Sjkh 3511722Sjkh if(p == NULL) { 35229453Scharnier warnx("%s:%d: no prog %s previously declared, skipping link", 3531722Sjkh curfilename, linenum, argv[1]); 3541722Sjkh goterror = 1; 3551722Sjkh return; 3561722Sjkh } 3576696Sphk for(i=2;i<argc;i++) { 3586696Sphk if (list_mode) 3596696Sphk printf("%s\n",argv[i]); 3601722Sjkh add_string(&p->links, argv[i]); 3616696Sphk } 3621722Sjkh} 3631722Sjkh 3641722Sjkh 3651722Sjkhvoid add_libs(int argc, char **argv) 3661722Sjkh{ 3671722Sjkh int i; 3681722Sjkh 3691722Sjkh for(i=1;i<argc;i++) 3701722Sjkh add_string(&libs, argv[i]); 3711722Sjkh} 3721722Sjkh 3731722Sjkh 37468750Sjoevoid add_buildopts(int argc, char **argv) 37568750Sjoe{ 37668750Sjoe int i; 37768750Sjoe 37868750Sjoe for (i = 1; i < argc; i++) 37968750Sjoe add_string(&buildopts, argv[i]); 38068750Sjoe} 38168750Sjoe 38268750Sjoe 3831722Sjkhvoid add_special(int argc, char **argv) 3841722Sjkh{ 3851722Sjkh int i; 3861722Sjkh prog_t *p = find_prog(argv[1]); 3871722Sjkh 3881722Sjkh if(p == NULL) { 3891722Sjkh if(reading_cache) return; 39029453Scharnier warnx("%s:%d: no prog %s previously declared, skipping special", 3911722Sjkh curfilename, linenum, argv[1]); 3921722Sjkh goterror = 1; 3931722Sjkh return; 3941722Sjkh } 3951722Sjkh 3961722Sjkh if(!strcmp(argv[2], "ident")) { 3971722Sjkh if(argc != 4) goto argcount; 3981722Sjkh if((p->ident = strdup(argv[3])) == NULL) 3991722Sjkh out_of_memory(); 4001722Sjkh } 4011722Sjkh else if(!strcmp(argv[2], "srcdir")) { 4021722Sjkh if(argc != 4) goto argcount; 4031722Sjkh if((p->srcdir = strdup(argv[3])) == NULL) 4041722Sjkh out_of_memory(); 4051722Sjkh } 4061722Sjkh else if(!strcmp(argv[2], "objdir")) { 4071722Sjkh if(argc != 4) goto argcount; 4081722Sjkh if((p->objdir = strdup(argv[3])) == NULL) 4091722Sjkh out_of_memory(); 4101722Sjkh } 4111722Sjkh else if(!strcmp(argv[2], "objs")) { 4121722Sjkh p->objs = NULL; 4131722Sjkh for(i=3;i<argc;i++) 4141722Sjkh add_string(&p->objs, argv[i]); 4151722Sjkh } 4161722Sjkh else if(!strcmp(argv[2], "objpaths")) { 4171722Sjkh p->objpaths = NULL; 4181722Sjkh for(i=3;i<argc;i++) 4191722Sjkh add_string(&p->objpaths, argv[i]); 4201722Sjkh } 42130120Sjoerg else if(!strcmp(argv[2], "keep")) { 42230120Sjoerg p->keeplist = NULL; 42330120Sjoerg for(i=3;i<argc;i++) 42430120Sjoerg add_string(&p->keeplist, argv[i]); 42530120Sjoerg } 42656995Sluigi else if(!strcmp(argv[2], "objvar")) { 42756995Sluigi if(argc != 4) 42856995Sluigi goto argcount; 42956995Sluigi if((p->objvar = strdup(argv[3])) == NULL) 43056995Sluigi out_of_memory(); 43156995Sluigi } 43268569Sjoe else if (!strcmp(argv[2], "buildopts")) { 43368569Sjoe p->buildopts = NULL; 43468569Sjoe for (i = 3; i < argc; i++) 43568569Sjoe add_string(&p->buildopts, argv[i]); 43668569Sjoe } 4371722Sjkh else { 43829453Scharnier warnx("%s:%d: bad parameter name `%s', skipping line", 4391722Sjkh curfilename, linenum, argv[2]); 4401722Sjkh goterror = 1; 4411722Sjkh } 4421722Sjkh return; 4431722Sjkh 4441722Sjkh 4451722Sjkh argcount: 44629453Scharnier warnx("%s:%d: too %s arguments, expected \"special %s %s <string>\"", 4471722Sjkh curfilename, linenum, argc < 4? "few" : "many", argv[1], argv[2]); 4481722Sjkh goterror = 1; 4491722Sjkh} 4501722Sjkh 4511722Sjkh 4521722Sjkhprog_t *find_prog(char *str) 4531722Sjkh{ 4541722Sjkh prog_t *p; 4551722Sjkh 4561722Sjkh for(p = progs; p != NULL; p = p->next) 4571722Sjkh if(!strcmp(p->name, str)) return p; 4581722Sjkh 4591722Sjkh return NULL; 4601722Sjkh} 4611722Sjkh 4621722Sjkh 4631722Sjkh/* 4641722Sjkh * ======================================================================== 4651722Sjkh * gen_outputs subsystem 4661722Sjkh * 4671722Sjkh */ 4681722Sjkh 4691722Sjkh/* helper subroutines */ 4701722Sjkh 4711722Sjkhvoid remove_error_progs(void); 4721722Sjkhvoid fillin_program(prog_t *p); 4731722Sjkhvoid gen_specials_cache(void); 4741722Sjkhvoid gen_output_makefile(void); 4751722Sjkhvoid gen_output_cfile(void); 4761722Sjkh 4771722Sjkhvoid fillin_program_objs(prog_t *p, char *path); 4781722Sjkhvoid top_makefile_rules(FILE *outmk); 4791722Sjkhvoid prog_makefile_rules(FILE *outmk, prog_t *p); 4801722Sjkhvoid output_strlst(FILE *outf, strlst_t *lst); 4811722Sjkhchar *genident(char *str); 4821722Sjkhchar *dir_search(char *progname); 4831722Sjkh 4841722Sjkh 4851722Sjkhvoid gen_outputs(void) 4861722Sjkh{ 4871722Sjkh prog_t *p; 4881722Sjkh 4891722Sjkh for(p = progs; p != NULL; p = p->next) 4901722Sjkh fillin_program(p); 4911722Sjkh 4921722Sjkh remove_error_progs(); 4931722Sjkh gen_specials_cache(); 4941722Sjkh gen_output_cfile(); 4951722Sjkh gen_output_makefile(); 4961722Sjkh status(""); 4978857Srgrimes fprintf(stderr, 4981722Sjkh "Run \"make -f %s objs exe\" to build crunched binary.\n", 4991722Sjkh outmkname); 5001722Sjkh} 5011722Sjkh 50256995Sluigi/* 50356995Sluigi * run the makefile for the program to find which objects are necessary 50456995Sluigi */ 5051722Sjkhvoid fillin_program(prog_t *p) 5061722Sjkh{ 5071722Sjkh char path[MAXPATHLEN]; 5081722Sjkh char *srcparent; 5091722Sjkh strlst_t *s; 5101722Sjkh 5111722Sjkh sprintf(line, "filling in parms for %s", p->name); 5121722Sjkh status(line); 5131722Sjkh 5148857Srgrimes if(!p->ident) 5151722Sjkh p->ident = genident(p->name); 5161722Sjkh if(!p->srcdir) { 5171722Sjkh srcparent = dir_search(p->name); 5181722Sjkh if(srcparent) 5191722Sjkh sprintf(path, "%s/%s", srcparent, p->name); 5201722Sjkh if(is_dir(path)) 5211722Sjkh p->srcdir = strdup(path); 5221722Sjkh } 5231722Sjkh if(!p->objdir && p->srcdir) { 52417430Sphk FILE *f; 52517430Sphk 52632704Ssos sprintf(path, "cd %s && echo -n /usr/obj`/bin/pwd`", p->srcdir); 52717430Sphk p->objdir = p->srcdir; 52817430Sphk f = popen(path,"r"); 52917430Sphk if (f) { 53017430Sphk fgets(path,sizeof path, f); 53117430Sphk if (!pclose(f)) { 53217430Sphk if(is_dir(path)) 53317430Sphk p->objdir = strdup(path); 53417430Sphk } 53517430Sphk } 5361722Sjkh } 53756995Sluigi/* 53856995Sluigi * XXX look for a Makefile.{name} in local directory first. 53956995Sluigi * This lets us override the original Makefile. 54056995Sluigi */ 54156995Sluigi sprintf(path, "Makefile.%s", p->name); 54256995Sluigi if (is_nonempty_file(path)) { 54356995Sluigi sprintf(line, "Using %s for %s", path, p->name); 54456995Sluigi status(line); 54556995Sluigi } else 5461722Sjkh if(p->srcdir) sprintf(path, "%s/Makefile", p->srcdir); 5471722Sjkh if(!p->objs && p->srcdir && is_nonempty_file(path)) 5481722Sjkh fillin_program_objs(p, path); 5491722Sjkh 5501722Sjkh if(!p->objpaths && p->objdir && p->objs) 5511722Sjkh for(s = p->objs; s != NULL; s = s->next) { 5521722Sjkh sprintf(line, "%s/%s", p->objdir, s->str); 5531722Sjkh add_string(&p->objpaths, line); 5541722Sjkh } 5551722Sjkh 5561722Sjkh if(!p->srcdir && verbose) 55729453Scharnier warnx("%s: %s: warning: could not find source directory", 5581722Sjkh infilename, p->name); 5591722Sjkh if(!p->objs && verbose) 56029453Scharnier warnx("%s: %s: warning: could not find any .o files", 5611722Sjkh infilename, p->name); 5621722Sjkh 5631722Sjkh if(!p->objpaths) { 56429453Scharnier warnx("%s: %s: error: no objpaths specified or calculated", 5651722Sjkh infilename, p->name); 5661722Sjkh p->goterror = goterror = 1; 5671722Sjkh } 5681722Sjkh} 5691722Sjkh 5701722Sjkhvoid fillin_program_objs(prog_t *p, char *path) 5711722Sjkh{ 5721722Sjkh char *obj, *cp; 5731722Sjkh int rc; 5741722Sjkh FILE *f; 57556995Sluigi char *objvar="OBJS"; 57668569Sjoe strlst_t *s; 5771722Sjkh 5781722Sjkh /* discover the objs from the srcdir Makefile */ 5791722Sjkh 5801722Sjkh if((f = fopen(tempfname, "w")) == NULL) { 58129453Scharnier warn("%s", tempfname); 5821722Sjkh goterror = 1; 5831722Sjkh return; 5841722Sjkh } 58556995Sluigi if (p->objvar) 58656995Sluigi objvar = p->objvar ; 5878857Srgrimes 58856995Sluigi /* 58956995Sluigi * XXX include outhdrname (e.g. to contain Make variables) 59056995Sluigi */ 59156995Sluigi if (outhdrname[0] != '\0') 59256995Sluigi fprintf(f, ".include \"%s\"\n", outhdrname); 5931722Sjkh fprintf(f, ".include \"%s\"\n", path); 59468750Sjoe if (buildopts) { 59568750Sjoe fprintf(f, "BUILDOPTS+="); 59668750Sjoe output_strlst(f, buildopts); 59768750Sjoe } 59856995Sluigi fprintf(f, ".if defined(PROG) && !defined(%s)\n", objvar); 59956995Sluigi fprintf(f, "%s=${PROG}.o\n", objvar); 6001722Sjkh fprintf(f, ".endif\n"); 60168285Sjoe fprintf(f, "loop:\n\t@echo 'OBJS= '${%s}\n", objvar); 60268569Sjoe 60368750Sjoe fprintf(f, "crunchgen_objs:\n\t@make -f %s $(BUILDOPTS) $(%s_OPTS)", 60468569Sjoe tempfname, p->ident); 60568569Sjoe for (s = p->buildopts; s != NULL; s = s->next) 60668569Sjoe fprintf(f, " %s", s->str); 60768569Sjoe fprintf(f, " loop\n"); 60868569Sjoe 6091722Sjkh fclose(f); 6101722Sjkh 6111722Sjkh sprintf(line, "make -f %s crunchgen_objs 2>&1", tempfname); 6121722Sjkh if((f = popen(line, "r")) == NULL) { 61329453Scharnier warn("submake pipe"); 6141722Sjkh goterror = 1; 6151722Sjkh return; 6161722Sjkh } 6171722Sjkh 6181722Sjkh while(fgets(line, MAXLINELEN, f)) { 6191722Sjkh if(strncmp(line, "OBJS= ", 6)) { 62029453Scharnier warnx("make error: %s", line); 6218857Srgrimes goterror = 1; 6221722Sjkh continue; 6231722Sjkh } 6241722Sjkh cp = line + 6; 6251722Sjkh while(isspace(*cp)) cp++; 6261722Sjkh while(*cp) { 6271722Sjkh obj = cp; 6281722Sjkh while(*cp && !isspace(*cp)) cp++; 6291722Sjkh if(*cp) *cp++ = '\0'; 6301722Sjkh add_string(&p->objs, obj); 6311722Sjkh while(isspace(*cp)) cp++; 6321722Sjkh } 6331722Sjkh } 6341722Sjkh if((rc=pclose(f)) != 0) { 63529453Scharnier warnx("make error: make returned %d", rc); 6361722Sjkh goterror = 1; 6371722Sjkh } 6381722Sjkh unlink(tempfname); 6391722Sjkh} 6401722Sjkh 6411722Sjkhvoid remove_error_progs(void) 6421722Sjkh{ 6431722Sjkh prog_t *p1, *p2; 6441722Sjkh 6458857Srgrimes p1 = NULL; p2 = progs; 6468857Srgrimes while(p2 != NULL) { 6471722Sjkh if(!p2->goterror) 6481722Sjkh p1 = p2, p2 = p2->next; 6491722Sjkh else { 6501722Sjkh /* delete it from linked list */ 65129453Scharnier warnx("%s: %s: ignoring program because of errors", 6521722Sjkh infilename, p2->name); 6531722Sjkh if(p1) p1->next = p2->next; 6541722Sjkh else progs = p2->next; 6551722Sjkh p2 = p2->next; 6561722Sjkh } 6571722Sjkh } 6581722Sjkh} 6591722Sjkh 6601722Sjkhvoid gen_specials_cache(void) 6611722Sjkh{ 6621722Sjkh FILE *cachef; 6631722Sjkh prog_t *p; 6641722Sjkh 6651722Sjkh sprintf(line, "generating %s", cachename); 6661722Sjkh status(line); 6671722Sjkh 6681722Sjkh if((cachef = fopen(cachename, "w")) == NULL) { 66929453Scharnier warn("%s", cachename); 6701722Sjkh goterror = 1; 6711722Sjkh return; 6721722Sjkh } 6731722Sjkh 6741722Sjkh fprintf(cachef, "# %s - parm cache generated from %s by crunchgen %s\n\n", 6751722Sjkh cachename, infilename, CRUNCH_VERSION); 6761722Sjkh 6771722Sjkh for(p = progs; p != NULL; p = p->next) { 6781722Sjkh fprintf(cachef, "\n"); 6791722Sjkh if(p->srcdir) 6801722Sjkh fprintf(cachef, "special %s srcdir %s\n", p->name, p->srcdir); 6811722Sjkh if(p->objdir) 6821722Sjkh fprintf(cachef, "special %s objdir %s\n", p->name, p->objdir); 6831722Sjkh if(p->objs) { 6841722Sjkh fprintf(cachef, "special %s objs", p->name); 6851722Sjkh output_strlst(cachef, p->objs); 6861722Sjkh } 6871722Sjkh fprintf(cachef, "special %s objpaths", p->name); 6881722Sjkh output_strlst(cachef, p->objpaths); 6891722Sjkh } 6901722Sjkh fclose(cachef); 6911722Sjkh} 6921722Sjkh 6931722Sjkh 6941722Sjkhvoid gen_output_makefile(void) 6951722Sjkh{ 6961722Sjkh prog_t *p; 6971722Sjkh FILE *outmk; 6981722Sjkh 6991722Sjkh sprintf(line, "generating %s", outmkname); 7001722Sjkh status(line); 7011722Sjkh 7021722Sjkh if((outmk = fopen(outmkname, "w")) == NULL) { 70329453Scharnier warn("%s", outmkname); 7041722Sjkh goterror = 1; 7051722Sjkh return; 7061722Sjkh } 7071722Sjkh 7081722Sjkh fprintf(outmk, "# %s - generated from %s by crunchgen %s\n\n", 7091722Sjkh outmkname, infilename, CRUNCH_VERSION); 71056995Sluigi if (outhdrname[0] != '\0') 71156995Sluigi fprintf(outmk, ".include \"%s\"\n", outhdrname); 7121722Sjkh 7131722Sjkh top_makefile_rules(outmk); 7141722Sjkh 7151722Sjkh for(p = progs; p != NULL; p = p->next) 7168857Srgrimes prog_makefile_rules(outmk, p); 7171722Sjkh 7181722Sjkh fprintf(outmk, "\n# ========\n"); 7191722Sjkh fclose(outmk); 7201722Sjkh} 7211722Sjkh 7221722Sjkh 7231722Sjkhvoid gen_output_cfile(void) 7241722Sjkh{ 7251722Sjkh extern char *crunched_skel[]; 7261722Sjkh char **cp; 7271722Sjkh FILE *outcf; 7281722Sjkh prog_t *p; 7291722Sjkh strlst_t *s; 7301722Sjkh 7311722Sjkh sprintf(line, "generating %s", outcfname); 7321722Sjkh status(line); 7331722Sjkh 7341722Sjkh if((outcf = fopen(outcfname, "w")) == NULL) { 73529453Scharnier warn("%s", outcfname); 7361722Sjkh goterror = 1; 7371722Sjkh return; 7381722Sjkh } 7391722Sjkh 7408857Srgrimes fprintf(outcf, 7411722Sjkh "/* %s - generated from %s by crunchgen %s */\n", 7421722Sjkh outcfname, infilename, CRUNCH_VERSION); 7431722Sjkh 7441722Sjkh fprintf(outcf, "#define EXECNAME \"%s\"\n", execfname); 7451722Sjkh for(cp = crunched_skel; *cp != NULL; cp++) 7461722Sjkh fprintf(outcf, "%s\n", *cp); 7471722Sjkh 7481722Sjkh for(p = progs; p != NULL; p = p->next) 7491722Sjkh fprintf(outcf, "extern int _crunched_%s_stub();\n", p->ident); 7501722Sjkh 7511722Sjkh fprintf(outcf, "\nstruct stub entry_points[] = {\n"); 7521722Sjkh for(p = progs; p != NULL; p = p->next) { 7531722Sjkh fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n", 7541722Sjkh p->name, p->ident); 7551722Sjkh for(s = p->links; s != NULL; s = s->next) 7561722Sjkh fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n", 7571722Sjkh s->str, p->ident); 7581722Sjkh } 7598857Srgrimes 7601722Sjkh fprintf(outcf, "\t{ EXECNAME, crunched_main },\n"); 7611722Sjkh fprintf(outcf, "\t{ NULL, NULL }\n};\n"); 7621722Sjkh fclose(outcf); 7631722Sjkh} 7641722Sjkh 7651722Sjkh 7661722Sjkhchar *genident(char *str) 7671722Sjkh{ 7681722Sjkh char *n,*s,*d; 7691722Sjkh 7701722Sjkh /* 7711722Sjkh * generates a Makefile/C identifier from a program name, mapping '-' to 7721722Sjkh * '_' and ignoring all other non-identifier characters. This leads to 7731722Sjkh * programs named "foo.bar" and "foobar" to map to the same identifier. 7741722Sjkh */ 7751722Sjkh 7761722Sjkh if((n = strdup(str)) == NULL) 7771722Sjkh return NULL; 7781722Sjkh for(d = s = n; *s != '\0'; s++) { 7791722Sjkh if(*s == '-') *d++ = '_'; 7801722Sjkh else if(*s == '_' || isalnum(*s)) *d++ = *s; 7811722Sjkh } 7821722Sjkh *d = '\0'; 7831722Sjkh return n; 7841722Sjkh} 7851722Sjkh 7861722Sjkh 7871722Sjkhchar *dir_search(char *progname) 7881722Sjkh{ 7891722Sjkh char path[MAXPATHLEN]; 7901722Sjkh strlst_t *dir; 7911722Sjkh 7921722Sjkh for(dir=srcdirs; dir != NULL; dir=dir->next) { 7931722Sjkh sprintf(path, "%s/%s", dir->str, progname); 7941722Sjkh if(is_dir(path)) return dir->str; 7951722Sjkh } 7961722Sjkh return NULL; 7971722Sjkh} 7981722Sjkh 7991722Sjkh 8001722Sjkhvoid top_makefile_rules(FILE *outmk) 8011722Sjkh{ 8021722Sjkh prog_t *p; 8031722Sjkh 8041722Sjkh fprintf(outmk, "LIBS="); 8051722Sjkh output_strlst(outmk, libs); 8061722Sjkh 80768750Sjoe if (buildopts) { 80868750Sjoe fprintf(outmk, "BUILDOPTS+="); 80968750Sjoe output_strlst(outmk, buildopts); 81068750Sjoe } 81168750Sjoe 8121722Sjkh fprintf(outmk, "CRUNCHED_OBJS="); 8131722Sjkh for(p = progs; p != NULL; p = p->next) 8141722Sjkh fprintf(outmk, " %s.lo", p->name); 8151722Sjkh fprintf(outmk, "\n"); 8161722Sjkh 8171722Sjkh fprintf(outmk, "SUBMAKE_TARGETS="); 8181722Sjkh for(p = progs; p != NULL; p = p->next) 8191722Sjkh fprintf(outmk, " %s_make", p->ident); 82032589Sbrian fprintf(outmk, "\nSUBCLEAN_TARGETS="); 82132589Sbrian for(p = progs; p != NULL; p = p->next) 82232589Sbrian fprintf(outmk, " %s_clean", p->ident); 8231722Sjkh fprintf(outmk, "\n\n"); 8241722Sjkh 8258857Srgrimes fprintf(outmk, "%s: %s.o $(CRUNCHED_OBJS)\n", 8261722Sjkh execfname, execfname); 8271722Sjkh fprintf(outmk, "\t$(CC) -static -o %s %s.o $(CRUNCHED_OBJS) $(LIBS)\n", 8281722Sjkh execfname, execfname); 8291722Sjkh fprintf(outmk, "\tstrip %s\n", execfname); 8301722Sjkh fprintf(outmk, "all: objs exe\nobjs: $(SUBMAKE_TARGETS)\n"); 8311722Sjkh fprintf(outmk, "exe: %s\n", execfname); 83232589Sbrian fprintf(outmk, "realclean: clean subclean\n"); 8331722Sjkh fprintf(outmk, "clean:\n\trm -f %s *.lo *.o *_stub.c\n", 8341722Sjkh execfname); 83532589Sbrian fprintf(outmk, "subclean: $(SUBCLEAN_TARGETS)\n"); 8361722Sjkh} 8371722Sjkh 8381722Sjkh 8391722Sjkhvoid prog_makefile_rules(FILE *outmk, prog_t *p) 8401722Sjkh{ 84130120Sjoerg strlst_t *lst; 84230120Sjoerg 8431722Sjkh fprintf(outmk, "\n# -------- %s\n\n", p->name); 8441722Sjkh 8451722Sjkh if(p->srcdir && p->objs) { 8461722Sjkh fprintf(outmk, "%s_SRCDIR=%s\n", p->ident, p->srcdir); 8471722Sjkh fprintf(outmk, "%s_OBJS=", p->ident); 8481722Sjkh output_strlst(outmk, p->objs); 84968569Sjoe if (p->buildopts != NULL) { 85068569Sjoe fprintf(outmk, "%s_OPTS+=", p->ident); 85168569Sjoe output_strlst(outmk, p->buildopts); 85268569Sjoe } 8531722Sjkh fprintf(outmk, "%s_make:\n", p->ident); 85468286Sjoe fprintf(outmk, "\t(cd $(%s_SRCDIR) && ", p->ident); 85568286Sjoe if (makeobj) 85668286Sjoe fprintf(outmk, "make obj && "); 85768286Sjoe fprintf(outmk, "\\\n"); 85868750Sjoe fprintf(outmk, "\t\tmake $(BUILDOPTS) $(%s_OPTS) depend && \\\n" 85968750Sjoe "\t\tmake $(BUILDOPTS) $(%s_OPTS) $(%s_OBJS))\n", 86068286Sjoe p->ident, p->ident, p->ident); 86132589Sbrian fprintf(outmk, "%s_clean:\n", p->ident); 86232589Sbrian fprintf(outmk, "\t(cd $(%s_SRCDIR) && make clean)\n\n", p->ident); 8631722Sjkh } 8641722Sjkh else 8658857Srgrimes fprintf(outmk, "%s_make:\n\t@echo \"** cannot make objs for %s\"\n\n", 8661722Sjkh p->ident, p->name); 8671722Sjkh 8681722Sjkh fprintf(outmk, "%s_OBJPATHS=", p->ident); 8691722Sjkh output_strlst(outmk, p->objpaths); 8701722Sjkh 8711722Sjkh fprintf(outmk, "%s_stub.c:\n", p->name); 8721722Sjkh fprintf(outmk, "\techo \"" 8731722Sjkh "int _crunched_%s_stub(int argc, char **argv, char **envp)" 8741722Sjkh "{return main(argc,argv,envp);}\" >%s_stub.c\n", 8751722Sjkh p->ident, p->name); 8761722Sjkh fprintf(outmk, "%s.lo: %s_stub.o $(%s_OBJPATHS)\n", 8771722Sjkh p->name, p->name, p->ident); 8788857Srgrimes fprintf(outmk, "\tld -dc -r -o %s.lo %s_stub.o $(%s_OBJPATHS)\n", 8791722Sjkh p->name, p->name, p->ident); 88039171Sjkh fprintf(outmk, "\tcrunchide -k _crunched_%s_stub ", p->ident); 88130120Sjoerg for(lst = p->keeplist; lst != NULL; lst = lst->next) 88230120Sjoerg fprintf(outmk, "-k _%s ", lst->str); 88330120Sjoerg fprintf(outmk, "%s.lo\n", p->name); 8841722Sjkh} 8851722Sjkh 8861722Sjkhvoid output_strlst(FILE *outf, strlst_t *lst) 8871722Sjkh{ 8881722Sjkh for(; lst != NULL; lst = lst->next) 8891722Sjkh fprintf(outf, " %s", lst->str); 8901722Sjkh fprintf(outf, "\n"); 8911722Sjkh} 8921722Sjkh 8931722Sjkh 8941722Sjkh/* 8951722Sjkh * ======================================================================== 8961722Sjkh * general library routines 8971722Sjkh * 8981722Sjkh */ 8991722Sjkh 9001722Sjkhvoid status(char *str) 9011722Sjkh{ 9021722Sjkh static int lastlen = 0; 9031722Sjkh int len, spaces; 9041722Sjkh 9051722Sjkh if(!verbose) return; 9061722Sjkh 9071722Sjkh len = strlen(str); 9081722Sjkh spaces = lastlen - len; 9091722Sjkh if(spaces < 1) spaces = 1; 9101722Sjkh 9111722Sjkh fprintf(stderr, " [%s]%*.*s\r", str, spaces, spaces, " "); 9121722Sjkh fflush(stderr); 9131722Sjkh lastlen = len; 9141722Sjkh} 9151722Sjkh 9161722Sjkh 9171722Sjkhvoid out_of_memory(void) 9181722Sjkh{ 91929453Scharnier errx(1, "%s: %d: out of memory, stopping", infilename, linenum); 9201722Sjkh} 9211722Sjkh 9221722Sjkh 9231722Sjkhvoid add_string(strlst_t **listp, char *str) 9241722Sjkh{ 9251722Sjkh strlst_t *p1, *p2; 9261722Sjkh 9271722Sjkh /* add to end, but be smart about dups */ 9281722Sjkh 9291722Sjkh for(p1 = NULL, p2 = *listp; p2 != NULL; p1 = p2, p2 = p2->next) 9301722Sjkh if(!strcmp(p2->str, str)) return; 9311722Sjkh 9321722Sjkh p2 = malloc(sizeof(strlst_t)); 93319822Sjoerg if(p2) { 93419822Sjoerg memset(p2, 0, sizeof(strlst_t)); 93519822Sjoerg p2->str = strdup(str); 93619822Sjoerg } 9371722Sjkh if(!p2 || !p2->str) 9381722Sjkh out_of_memory(); 9391722Sjkh 9401722Sjkh p2->next = NULL; 9411722Sjkh if(p1 == NULL) *listp = p2; 9421722Sjkh else p1->next = p2; 9431722Sjkh} 9441722Sjkh 9451722Sjkh 9461722Sjkhint is_dir(char *pathname) 9471722Sjkh{ 9481722Sjkh struct stat buf; 9491722Sjkh 9501722Sjkh if(stat(pathname, &buf) == -1) 9511722Sjkh return 0; 9521722Sjkh return S_ISDIR(buf.st_mode); 9531722Sjkh} 9541722Sjkh 9551722Sjkhint is_nonempty_file(char *pathname) 9561722Sjkh{ 9571722Sjkh struct stat buf; 9581722Sjkh 9591722Sjkh if(stat(pathname, &buf) == -1) 9601722Sjkh return 0; 9611722Sjkh 9621722Sjkh return S_ISREG(buf.st_mode) && buf.st_size > 0; 9631722Sjkh} 964