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 251722Sjkh */ 261722Sjkh/* 271722Sjkh * ======================================================================== 281722Sjkh * crunchgen.c 291722Sjkh * 301722Sjkh * Generates a Makefile and main C file for a crunched executable, 318857Srgrimes * from specs given in a .conf file. 321722Sjkh */ 33237625Sobrien 34237625Sobrien#include <sys/cdefs.h> 35237625Sobrien__FBSDID("$FreeBSD: stable/11/usr.sbin/crunch/crunchgen/crunchgen.c 311185 2017-01-03 22:55:10Z bdrewery $"); 36237625Sobrien 37237625Sobrien#include <sys/param.h> 3870884Sjoe#include <sys/stat.h> 3970884Sjoe 4029453Scharnier#include <ctype.h> 4129453Scharnier#include <err.h> 4270124Sjoe#include <paths.h> 4329453Scharnier#include <stdio.h> 441722Sjkh#include <stdlib.h> 4529453Scharnier#include <string.h> 461722Sjkh#include <unistd.h> 471722Sjkh 481722Sjkh#define CRUNCH_VERSION "0.2" 491722Sjkh 501722Sjkh#define MAXLINELEN 16384 511722Sjkh#define MAXFIELDS 2048 521722Sjkh 531722Sjkh 541722Sjkh/* internal representation of conf file: */ 551722Sjkh 561722Sjkh/* simple lists of strings suffice for most parms */ 571722Sjkh 581722Sjkhtypedef struct strlst { 5970884Sjoe struct strlst *next; 6070884Sjoe char *str; 611722Sjkh} strlst_t; 621722Sjkh 631722Sjkh/* progs have structure, each field can be set with "special" or calculated */ 641722Sjkh 651722Sjkhtypedef struct prog { 6670884Sjoe struct prog *next; /* link field */ 6770884Sjoe char *name; /* program name */ 6870884Sjoe char *ident; /* C identifier for the program name */ 6970884Sjoe char *srcdir; 7070884Sjoe char *realsrcdir; 7170884Sjoe char *objdir; 7270884Sjoe char *objvar; /* Makefile variable to replace OBJS */ 7370884Sjoe strlst_t *objs, *objpaths; 7470884Sjoe strlst_t *buildopts; 7570884Sjoe strlst_t *keeplist; 7670884Sjoe strlst_t *links; 7793435Sluigi strlst_t *libs; 78153687Sceri strlst_t *libs_so; 7970884Sjoe int goterror; 801722Sjkh} prog_t; 811722Sjkh 821722Sjkh 831722Sjkh/* global state */ 841722Sjkh 8568750Sjoestrlst_t *buildopts = NULL; 8670884Sjoestrlst_t *srcdirs = NULL; 8770884Sjoestrlst_t *libs = NULL; 88153687Sceristrlst_t *libs_so = NULL; 8970884Sjoeprog_t *progs = NULL; 901722Sjkh 911722Sjkhchar confname[MAXPATHLEN], infilename[MAXPATHLEN]; 921722Sjkhchar outmkname[MAXPATHLEN], outcfname[MAXPATHLEN], execfname[MAXPATHLEN]; 931722Sjkhchar tempfname[MAXPATHLEN], cachename[MAXPATHLEN], curfilename[MAXPATHLEN]; 9470884Sjoechar outhdrname[MAXPATHLEN] ; /* user-supplied header for *.mk */ 9570884Sjoechar *objprefix; /* where are the objects ? */ 96237574Sobrienchar *path_make; 971722Sjkhint linenum = -1; 981722Sjkhint goterror = 0; 991722Sjkh 10070884Sjoeint verbose, readcache; /* options */ 1011722Sjkhint reading_cache; 10270884Sjoeint makeobj = 0; /* add 'make obj' rules to the makefile */ 1031722Sjkh 1046696Sphkint list_mode; 1056696Sphk 1061722Sjkh/* general library routines */ 1071722Sjkh 108246256Spfgvoid status(const char *str); 1091722Sjkhvoid out_of_memory(void); 1101722Sjkhvoid add_string(strlst_t **listp, char *str); 111246256Spfgint is_dir(const char *pathname); 112246256Spfgint is_nonempty_file(const char *pathname); 113153687Sceriint subtract_strlst(strlst_t **lista, strlst_t **listb); 114153687Sceriint in_list(strlst_t **listp, char *str); 1151722Sjkh 116246261Spfg/* helper routines for main() */ 1171722Sjkh 1188857Srgrimesvoid usage(void); 1191722Sjkhvoid parse_conf_file(void); 1201722Sjkhvoid gen_outputs(void); 1211722Sjkh 122246261Spfgextern char *crunched_skel[]; 1231722Sjkh 124246261Spfg 125237625Sobrienint 126237625Sobrienmain(int argc, char **argv) 1271722Sjkh{ 12870884Sjoe char *p; 12970884Sjoe int optc; 1301722Sjkh 13170884Sjoe verbose = 1; 13270884Sjoe readcache = 1; 13370884Sjoe *outmkname = *outcfname = *execfname = '\0'; 1348857Srgrimes 135237574Sobrien path_make = getenv("MAKE"); 136237574Sobrien if (path_make == NULL || *path_make == '\0') 137237574Sobrien path_make = "make"; 138237574Sobrien 13970884Sjoe p = getenv("MAKEOBJDIRPREFIX"); 14070884Sjoe if (p == NULL || *p == '\0') 14170884Sjoe objprefix = "/usr/obj"; /* default */ 14270884Sjoe else 14370884Sjoe if ((objprefix = strdup(p)) == NULL) 14470884Sjoe out_of_memory(); 14569413Sluigi 14670884Sjoe while((optc = getopt(argc, argv, "lh:m:c:e:p:foq")) != -1) { 14770884Sjoe switch(optc) { 14870884Sjoe case 'f': 14970884Sjoe readcache = 0; 15070884Sjoe break; 15170884Sjoe case 'o': 15270884Sjoe makeobj = 1; 15370884Sjoe break; 15470884Sjoe case 'q': 15570884Sjoe verbose = 0; 15670884Sjoe break; 1571722Sjkh 15870884Sjoe case 'm': 15970884Sjoe strlcpy(outmkname, optarg, sizeof(outmkname)); 16070884Sjoe break; 16170884Sjoe case 'p': 16270884Sjoe if ((objprefix = strdup(optarg)) == NULL) 16370113Sjoe out_of_memory(); 16470113Sjoe break; 1651722Sjkh 16670884Sjoe case 'h': 16770884Sjoe strlcpy(outhdrname, optarg, sizeof(outhdrname)); 16870884Sjoe break; 16970884Sjoe case 'c': 17070884Sjoe strlcpy(outcfname, optarg, sizeof(outcfname)); 17170884Sjoe break; 17270884Sjoe case 'e': 17370884Sjoe strlcpy(execfname, optarg, sizeof(execfname)); 17470884Sjoe break; 17570884Sjoe 17670884Sjoe case 'l': 17770884Sjoe list_mode++; 17870884Sjoe verbose = 0; 17970884Sjoe break; 18070884Sjoe 18170884Sjoe case '?': 18270884Sjoe default: 18370884Sjoe usage(); 18470884Sjoe } 1851722Sjkh } 1861722Sjkh 18770884Sjoe argc -= optind; 18870884Sjoe argv += optind; 1891722Sjkh 19070884Sjoe if (argc != 1) 19170884Sjoe usage(); 1921722Sjkh 19370884Sjoe /* 19470884Sjoe * generate filenames 19570884Sjoe */ 1961722Sjkh 19770884Sjoe strlcpy(infilename, argv[0], sizeof(infilename)); 1981722Sjkh 19970884Sjoe /* confname = `basename infilename .conf` */ 2001722Sjkh 20170884Sjoe if ((p=strrchr(infilename, '/')) != NULL) 20270884Sjoe strlcpy(confname, p + 1, sizeof(confname)); 20370884Sjoe else 20470884Sjoe strlcpy(confname, infilename, sizeof(confname)); 2051722Sjkh 20670884Sjoe if ((p=strrchr(confname, '.')) != NULL && !strcmp(p, ".conf")) 20770884Sjoe *p = '\0'; 2081722Sjkh 20970884Sjoe if (!*outmkname) 21070884Sjoe snprintf(outmkname, sizeof(outmkname), "%s.mk", confname); 21170884Sjoe if (!*outcfname) 21270884Sjoe snprintf(outcfname, sizeof(outcfname), "%s.c", confname); 21370884Sjoe if (!*execfname) 21470884Sjoe snprintf(execfname, sizeof(execfname), "%s", confname); 21570884Sjoe 21670884Sjoe snprintf(cachename, sizeof(cachename), "%s.cache", confname); 21770884Sjoe snprintf(tempfname, sizeof(tempfname), "%s/crunchgen_%sXXXXXX", 21870124Sjoe getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP, confname); 2191722Sjkh 22070884Sjoe parse_conf_file(); 22170884Sjoe if (list_mode) 22270884Sjoe exit(goterror); 2236696Sphk 22470884Sjoe gen_outputs(); 2251722Sjkh 22670884Sjoe exit(goterror); 2271722Sjkh} 2281722Sjkh 2291722Sjkh 230237625Sobrienvoid 231237625Sobrienusage(void) 2321722Sjkh{ 23370884Sjoe fprintf(stderr, "%s%s\n\t%s%s\n", "usage: crunchgen [-foq] ", 23470884Sjoe "[-h <makefile-header-name>] [-m <makefile>]", 23570884Sjoe "[-p <obj-prefix>] [-c <c-file-name>] [-e <exec-file>] ", 23670884Sjoe "<conffile>"); 23770884Sjoe exit(1); 2381722Sjkh} 2391722Sjkh 2401722Sjkh 2411722Sjkh/* 2421722Sjkh * ======================================================================== 2431722Sjkh * parse_conf_file subsystem 2441722Sjkh * 2451722Sjkh */ 2461722Sjkh 2471722Sjkh/* helper routines for parse_conf_file */ 2481722Sjkh 2491722Sjkhvoid parse_one_file(char *filename); 250246256Spfgvoid parse_line(char *pline, int *fc, char **fv, int nf); 2511722Sjkhvoid add_srcdirs(int argc, char **argv); 2521722Sjkhvoid add_progs(int argc, char **argv); 2531722Sjkhvoid add_link(int argc, char **argv); 2541722Sjkhvoid add_libs(int argc, char **argv); 255153687Scerivoid add_libs_so(int argc, char **argv); 25668750Sjoevoid add_buildopts(int argc, char **argv); 2571722Sjkhvoid add_special(int argc, char **argv); 2581722Sjkh 2591722Sjkhprog_t *find_prog(char *str); 2601722Sjkhvoid add_prog(char *progname); 2611722Sjkh 2621722Sjkh 263237625Sobrienvoid 264237625Sobrienparse_conf_file(void) 2651722Sjkh{ 26670884Sjoe if (!is_nonempty_file(infilename)) 26729453Scharnier errx(1, "fatal: input file \"%s\" not found", infilename); 26870884Sjoe 26970884Sjoe parse_one_file(infilename); 27070884Sjoe if (readcache && is_nonempty_file(cachename)) { 27170884Sjoe reading_cache = 1; 27270884Sjoe parse_one_file(cachename); 27370884Sjoe } 2741722Sjkh} 2751722Sjkh 2761722Sjkh 277237625Sobrienvoid 278237625Sobrienparse_one_file(char *filename) 2791722Sjkh{ 28070884Sjoe char *fieldv[MAXFIELDS]; 28170884Sjoe int fieldc; 28270884Sjoe void (*f)(int c, char **v); 28370884Sjoe FILE *cf; 28470884Sjoe char line[MAXLINELEN]; 2851722Sjkh 28670884Sjoe snprintf(line, sizeof(line), "reading %s", filename); 28770884Sjoe status(line); 28870884Sjoe strlcpy(curfilename, filename, sizeof(curfilename)); 2891722Sjkh 29070884Sjoe if ((cf = fopen(curfilename, "r")) == NULL) { 29170884Sjoe warn("%s", curfilename); 29270884Sjoe goterror = 1; 29370884Sjoe return; 29470884Sjoe } 2951722Sjkh 29670884Sjoe linenum = 0; 29770884Sjoe while (fgets(line, MAXLINELEN, cf) != NULL) { 29870884Sjoe linenum++; 29970884Sjoe parse_line(line, &fieldc, fieldv, MAXFIELDS); 30070884Sjoe 30170884Sjoe if (fieldc < 1) 30270884Sjoe continue; 30370884Sjoe 30470884Sjoe if (!strcmp(fieldv[0], "srcdirs")) 30570884Sjoe f = add_srcdirs; 30670884Sjoe else if(!strcmp(fieldv[0], "progs")) 30770884Sjoe f = add_progs; 30870884Sjoe else if(!strcmp(fieldv[0], "ln")) 30970884Sjoe f = add_link; 31070884Sjoe else if(!strcmp(fieldv[0], "libs")) 31170884Sjoe f = add_libs; 312153687Sceri else if(!strcmp(fieldv[0], "libs_so")) 313153687Sceri f = add_libs_so; 31470884Sjoe else if(!strcmp(fieldv[0], "buildopts")) 31570884Sjoe f = add_buildopts; 31670884Sjoe else if(!strcmp(fieldv[0], "special")) 31770884Sjoe f = add_special; 31870884Sjoe else { 31970884Sjoe warnx("%s:%d: skipping unknown command `%s'", 32070884Sjoe curfilename, linenum, fieldv[0]); 32170884Sjoe goterror = 1; 32270884Sjoe continue; 32370884Sjoe } 32470884Sjoe 32570884Sjoe if (fieldc < 2) { 32670884Sjoe warnx("%s:%d: %s %s", 32770884Sjoe curfilename, linenum, fieldv[0], 32870884Sjoe "command needs at least 1 argument, skipping"); 32970884Sjoe goterror = 1; 33070884Sjoe continue; 33170884Sjoe } 33270884Sjoe 33370884Sjoe f(fieldc, fieldv); 3341722Sjkh } 33570884Sjoe 33670884Sjoe if (ferror(cf)) { 33770884Sjoe warn("%s", curfilename); 33870884Sjoe goterror = 1; 3391722Sjkh } 34070884Sjoe fclose(cf); 3411722Sjkh} 3421722Sjkh 3431722Sjkh 344237625Sobrienvoid 345246256Spfgparse_line(char *pline, int *fc, char **fv, int nf) 3461722Sjkh{ 34770884Sjoe char *p; 3481722Sjkh 349246256Spfg p = pline; 35070884Sjoe *fc = 0; 3511722Sjkh 35270884Sjoe while (1) { 353246256Spfg while (isspace((unsigned char)*p)) 35470884Sjoe p++; 35570884Sjoe 35670884Sjoe if (*p == '\0' || *p == '#') 35770884Sjoe break; 35870884Sjoe 35970884Sjoe if (*fc < nf) 36070884Sjoe fv[(*fc)++] = p; 36170884Sjoe 362246256Spfg while (*p && !isspace((unsigned char)*p) && *p != '#') 36370884Sjoe p++; 36470884Sjoe 36570884Sjoe if (*p == '\0' || *p == '#') 36670884Sjoe break; 36770884Sjoe 36870884Sjoe *p++ = '\0'; 36970884Sjoe } 37070884Sjoe 37170884Sjoe if (*p) 37270884Sjoe *p = '\0'; /* needed for '#' case */ 3731722Sjkh} 3741722Sjkh 3751722Sjkh 376237625Sobrienvoid 377237625Sobrienadd_srcdirs(int argc, char **argv) 3781722Sjkh{ 37970884Sjoe int i; 3801722Sjkh 38170884Sjoe for (i = 1; i < argc; i++) { 38270884Sjoe if (is_dir(argv[i])) 38370884Sjoe add_string(&srcdirs, argv[i]); 38470884Sjoe else { 38570884Sjoe warnx("%s:%d: `%s' is not a directory, skipping it", 38670884Sjoe curfilename, linenum, argv[i]); 38770884Sjoe goterror = 1; 38870884Sjoe } 3891722Sjkh } 3901722Sjkh} 3911722Sjkh 3921722Sjkh 393237625Sobrienvoid 394237625Sobrienadd_progs(int argc, char **argv) 3951722Sjkh{ 39670884Sjoe int i; 3971722Sjkh 39870884Sjoe for (i = 1; i < argc; i++) 39970884Sjoe add_prog(argv[i]); 4001722Sjkh} 4011722Sjkh 4021722Sjkh 403237625Sobrienvoid 404237625Sobrienadd_prog(char *progname) 4051722Sjkh{ 40670884Sjoe prog_t *p1, *p2; 4071722Sjkh 40870884Sjoe /* add to end, but be smart about dups */ 4091722Sjkh 41070884Sjoe for (p1 = NULL, p2 = progs; p2 != NULL; p1 = p2, p2 = p2->next) 41170884Sjoe if (!strcmp(p2->name, progname)) 41270884Sjoe return; 4131722Sjkh 41470884Sjoe p2 = malloc(sizeof(prog_t)); 41570884Sjoe if(p2) { 41670884Sjoe memset(p2, 0, sizeof(prog_t)); 41770884Sjoe p2->name = strdup(progname); 41870884Sjoe } 41970884Sjoe if (!p2 || !p2->name) 42070884Sjoe out_of_memory(); 4211722Sjkh 42270884Sjoe p2->next = NULL; 42370884Sjoe if (p1 == NULL) 42470884Sjoe progs = p2; 42570884Sjoe else 42670884Sjoe p1->next = p2; 4271722Sjkh 42870884Sjoe p2->ident = NULL; 42970884Sjoe p2->srcdir = NULL; 43070884Sjoe p2->realsrcdir = NULL; 43170884Sjoe p2->objdir = NULL; 43270884Sjoe p2->links = NULL; 43393435Sluigi p2->libs = NULL; 434153687Sceri p2->libs_so = NULL; 43570884Sjoe p2->objs = NULL; 43670884Sjoe p2->keeplist = NULL; 43770884Sjoe p2->buildopts = NULL; 43870884Sjoe p2->goterror = 0; 43970884Sjoe 44070884Sjoe if (list_mode) 44170884Sjoe printf("%s\n",progname); 4421722Sjkh} 4431722Sjkh 4441722Sjkh 445237625Sobrienvoid 446237625Sobrienadd_link(int argc, char **argv) 4471722Sjkh{ 44870884Sjoe int i; 44970884Sjoe prog_t *p = find_prog(argv[1]); 4501722Sjkh 45170884Sjoe if (p == NULL) { 45270884Sjoe warnx("%s:%d: no prog %s previously declared, skipping link", 45370884Sjoe curfilename, linenum, argv[1]); 45470884Sjoe goterror = 1; 45570884Sjoe return; 45670884Sjoe } 45770884Sjoe 45870884Sjoe for (i = 2; i < argc; i++) { 45970884Sjoe if (list_mode) 46070884Sjoe printf("%s\n",argv[i]); 46170884Sjoe 46270884Sjoe add_string(&p->links, argv[i]); 46370884Sjoe } 4641722Sjkh} 4651722Sjkh 4661722Sjkh 467237625Sobrienvoid 468237625Sobrienadd_libs(int argc, char **argv) 4691722Sjkh{ 47070884Sjoe int i; 4711722Sjkh 472153687Sceri for(i = 1; i < argc; i++) { 47370884Sjoe add_string(&libs, argv[i]); 474153687Sceri if ( in_list(&libs_so, argv[i]) ) 475153687Sceri warnx("%s:%d: " 476153687Sceri "library `%s' specified as dynamic earlier", 477153687Sceri curfilename, linenum, argv[i]); 478153687Sceri } 4791722Sjkh} 4801722Sjkh 4811722Sjkh 482237625Sobrienvoid 483237625Sobrienadd_libs_so(int argc, char **argv) 484153687Sceri{ 485153687Sceri int i; 486153687Sceri 487153687Sceri for(i = 1; i < argc; i++) { 488153687Sceri add_string(&libs_so, argv[i]); 489153687Sceri if ( in_list(&libs, argv[i]) ) 490153687Sceri warnx("%s:%d: " 491153687Sceri "library `%s' specified as static earlier", 492153687Sceri curfilename, linenum, argv[i]); 493153687Sceri } 494153687Sceri} 495153687Sceri 496153687Sceri 497237625Sobrienvoid 498237625Sobrienadd_buildopts(int argc, char **argv) 49968750Sjoe{ 50070884Sjoe int i; 50168750Sjoe 50270884Sjoe for (i = 1; i < argc; i++) 50370884Sjoe add_string(&buildopts, argv[i]); 50468750Sjoe} 50568750Sjoe 50668750Sjoe 507237625Sobrienvoid 508237625Sobrienadd_special(int argc, char **argv) 5091722Sjkh{ 51070884Sjoe int i; 51170884Sjoe prog_t *p = find_prog(argv[1]); 5121722Sjkh 51370884Sjoe if (p == NULL) { 51470884Sjoe if (reading_cache) 51570884Sjoe return; 5161722Sjkh 51770884Sjoe warnx("%s:%d: no prog %s previously declared, skipping special", 51870884Sjoe curfilename, linenum, argv[1]); 51970884Sjoe goterror = 1; 52070884Sjoe return; 52170884Sjoe } 5221722Sjkh 52370884Sjoe if (!strcmp(argv[2], "ident")) { 52470884Sjoe if (argc != 4) 52570884Sjoe goto argcount; 52670884Sjoe if ((p->ident = strdup(argv[3])) == NULL) 52770884Sjoe out_of_memory(); 52870884Sjoe } else if (!strcmp(argv[2], "srcdir")) { 52970884Sjoe if (argc != 4) 53070884Sjoe goto argcount; 53170884Sjoe if ((p->srcdir = strdup(argv[3])) == NULL) 53270884Sjoe out_of_memory(); 53370884Sjoe } else if (!strcmp(argv[2], "objdir")) { 53470884Sjoe if(argc != 4) 53570884Sjoe goto argcount; 53670884Sjoe if((p->objdir = strdup(argv[3])) == NULL) 53770884Sjoe out_of_memory(); 53870884Sjoe } else if (!strcmp(argv[2], "objs")) { 53970884Sjoe p->objs = NULL; 54070884Sjoe for (i = 3; i < argc; i++) 54170884Sjoe add_string(&p->objs, argv[i]); 54270884Sjoe } else if (!strcmp(argv[2], "objpaths")) { 54370884Sjoe p->objpaths = NULL; 54470884Sjoe for (i = 3; i < argc; i++) 54570884Sjoe add_string(&p->objpaths, argv[i]); 54670884Sjoe } else if (!strcmp(argv[2], "keep")) { 54770884Sjoe p->keeplist = NULL; 54870884Sjoe for(i = 3; i < argc; i++) 54970884Sjoe add_string(&p->keeplist, argv[i]); 55070884Sjoe } else if (!strcmp(argv[2], "objvar")) { 55170884Sjoe if(argc != 4) 55270884Sjoe goto argcount; 55370884Sjoe if ((p->objvar = strdup(argv[3])) == NULL) 55470884Sjoe out_of_memory(); 55570884Sjoe } else if (!strcmp(argv[2], "buildopts")) { 55670884Sjoe p->buildopts = NULL; 55770884Sjoe for (i = 3; i < argc; i++) 55870884Sjoe add_string(&p->buildopts, argv[i]); 55993435Sluigi } else if (!strcmp(argv[2], "lib")) { 56093435Sluigi for (i = 3; i < argc; i++) 56193435Sluigi add_string(&p->libs, argv[i]); 56270884Sjoe } else { 56370884Sjoe warnx("%s:%d: bad parameter name `%s', skipping line", 56470884Sjoe curfilename, linenum, argv[2]); 56570884Sjoe goterror = 1; 56670884Sjoe } 56770884Sjoe return; 5681722Sjkh 5691722Sjkh argcount: 57070884Sjoe warnx("%s:%d: too %s arguments, expected \"special %s %s <string>\"", 5711722Sjkh curfilename, linenum, argc < 4? "few" : "many", argv[1], argv[2]); 57270884Sjoe goterror = 1; 5731722Sjkh} 5741722Sjkh 5751722Sjkh 5761722Sjkhprog_t *find_prog(char *str) 5771722Sjkh{ 57870884Sjoe prog_t *p; 5791722Sjkh 58070884Sjoe for (p = progs; p != NULL; p = p->next) 58170884Sjoe if (!strcmp(p->name, str)) 58270884Sjoe return p; 5831722Sjkh 58470884Sjoe return NULL; 5851722Sjkh} 5861722Sjkh 5871722Sjkh 5881722Sjkh/* 5891722Sjkh * ======================================================================== 5901722Sjkh * gen_outputs subsystem 5911722Sjkh * 5921722Sjkh */ 5931722Sjkh 5941722Sjkh/* helper subroutines */ 5951722Sjkh 5961722Sjkhvoid remove_error_progs(void); 5971722Sjkhvoid fillin_program(prog_t *p); 5981722Sjkhvoid gen_specials_cache(void); 5991722Sjkhvoid gen_output_makefile(void); 6001722Sjkhvoid gen_output_cfile(void); 6011722Sjkh 6021722Sjkhvoid fillin_program_objs(prog_t *p, char *path); 6031722Sjkhvoid top_makefile_rules(FILE *outmk); 6041722Sjkhvoid prog_makefile_rules(FILE *outmk, prog_t *p); 6051722Sjkhvoid output_strlst(FILE *outf, strlst_t *lst); 6061722Sjkhchar *genident(char *str); 6071722Sjkhchar *dir_search(char *progname); 6081722Sjkh 6091722Sjkh 610237625Sobrienvoid 611237625Sobriengen_outputs(void) 6121722Sjkh{ 61370884Sjoe prog_t *p; 6141722Sjkh 61570884Sjoe for (p = progs; p != NULL; p = p->next) 61670884Sjoe fillin_program(p); 6171722Sjkh 61870884Sjoe remove_error_progs(); 61970884Sjoe gen_specials_cache(); 62070884Sjoe gen_output_cfile(); 62170884Sjoe gen_output_makefile(); 62270884Sjoe status(""); 62370884Sjoe fprintf(stderr, 624237574Sobrien "Run \"%s -f %s\" to build crunched binary.\n", 625237574Sobrien path_make, outmkname); 6261722Sjkh} 6271722Sjkh 62856995Sluigi/* 62956995Sluigi * run the makefile for the program to find which objects are necessary 63056995Sluigi */ 631237625Sobrienvoid 632237625Sobrienfillin_program(prog_t *p) 6331722Sjkh{ 63470884Sjoe char path[MAXPATHLEN]; 63570884Sjoe char line[MAXLINELEN]; 63670884Sjoe FILE *f; 6371722Sjkh 63870884Sjoe snprintf(line, MAXLINELEN, "filling in parms for %s", p->name); 63970884Sjoe status(line); 6401722Sjkh 64170884Sjoe if (!p->ident) 64270884Sjoe p->ident = genident(p->name); 64370331Sjoe 64470884Sjoe /* look for the source directory if one wasn't specified by a special */ 64570884Sjoe if (!p->srcdir) { 64670884Sjoe p->srcdir = dir_search(p->name); 64770884Sjoe } 64870112Sjoe 64970884Sjoe /* Determine the actual srcdir (maybe symlinked). */ 65070884Sjoe if (p->srcdir) { 65170884Sjoe snprintf(line, MAXLINELEN, "cd %s && echo -n `/bin/pwd`", 65270884Sjoe p->srcdir); 65370884Sjoe f = popen(line,"r"); 65470884Sjoe if (!f) 65570884Sjoe errx(1, "Can't execute: %s\n", line); 65670331Sjoe 65770884Sjoe path[0] = '\0'; 65870884Sjoe fgets(path, sizeof path, f); 65970884Sjoe if (pclose(f)) 66070884Sjoe errx(1, "Can't execute: %s\n", line); 66170331Sjoe 66270884Sjoe if (!*path) 66370884Sjoe errx(1, "Can't perform pwd on: %s\n", p->srcdir); 66470331Sjoe 66570884Sjoe p->realsrcdir = strdup(path); 66670884Sjoe } 66770112Sjoe 66870884Sjoe /* Unless the option to make object files was specified the 66970884Sjoe * the objects will be built in the source directory unless 67070884Sjoe * an object directory already exists. 67170884Sjoe */ 67270884Sjoe if (!makeobj && !p->objdir && p->srcdir) { 673300806Sbdrewery char *auto_obj; 674300806Sbdrewery 675300806Sbdrewery auto_obj = NULL; 67670884Sjoe snprintf(line, sizeof line, "%s/%s", objprefix, p->realsrcdir); 677300806Sbdrewery if (is_dir(line) || 678300806Sbdrewery ((auto_obj = getenv("MK_AUTO_OBJ")) != NULL && 679300806Sbdrewery strcmp(auto_obj, "yes") == 0)) { 68070884Sjoe if ((p->objdir = strdup(line)) == NULL) 68170884Sjoe out_of_memory(); 68270884Sjoe } else 68370884Sjoe p->objdir = p->realsrcdir; 68470884Sjoe } 68570884Sjoe 68670884Sjoe /* 68770884Sjoe * XXX look for a Makefile.{name} in local directory first. 68870884Sjoe * This lets us override the original Makefile. 68970884Sjoe */ 69070884Sjoe snprintf(path, sizeof(path), "Makefile.%s", p->name); 69170884Sjoe if (is_nonempty_file(path)) { 69270884Sjoe snprintf(line, MAXLINELEN, "Using %s for %s", path, p->name); 69370884Sjoe status(line); 69470114Sjoe } else 69570884Sjoe if (p->srcdir) 69670884Sjoe snprintf(path, sizeof(path), "%s/Makefile", p->srcdir); 69770884Sjoe if (!p->objs && p->srcdir && is_nonempty_file(path)) 69870884Sjoe fillin_program_objs(p, path); 6991722Sjkh 70081700Sjoe if (!p->srcdir && !p->objdir && verbose) 70170884Sjoe warnx("%s: %s: %s", 70270884Sjoe "warning: could not find source directory", 70370884Sjoe infilename, p->name); 70470884Sjoe if (!p->objs && verbose) 70570884Sjoe warnx("%s: %s: warning: could not find any .o files", 70670884Sjoe infilename, p->name); 70770880Sjoe 70881823Sjoe if ((!p->srcdir || !p->objdir) && !p->objs) 70970884Sjoe p->goterror = 1; 7101722Sjkh} 7111722Sjkh 712237625Sobrienvoid 713237625Sobrienfillin_program_objs(prog_t *p, char *path) 7141722Sjkh{ 71570884Sjoe char *obj, *cp; 71670884Sjoe int fd, rc; 71770884Sjoe FILE *f; 71870884Sjoe char *objvar="OBJS"; 71970884Sjoe strlst_t *s; 72070884Sjoe char line[MAXLINELEN]; 7211722Sjkh 72270884Sjoe /* discover the objs from the srcdir Makefile */ 7231722Sjkh 72470884Sjoe if ((fd = mkstemp(tempfname)) == -1) { 72570884Sjoe perror(tempfname); 72670884Sjoe exit(1); 72770884Sjoe } 72870884Sjoe if ((f = fdopen(fd, "w")) == NULL) { 72970884Sjoe warn("%s", tempfname); 73070884Sjoe goterror = 1; 73170884Sjoe return; 73270884Sjoe } 73370884Sjoe if (p->objvar) 73470884Sjoe objvar = p->objvar; 7358857Srgrimes 73670884Sjoe /* 73770884Sjoe * XXX include outhdrname (e.g. to contain Make variables) 73870884Sjoe */ 73970884Sjoe if (outhdrname[0] != '\0') 74070884Sjoe fprintf(f, ".include \"%s\"\n", outhdrname); 74170884Sjoe fprintf(f, ".include \"%s\"\n", path); 742187943Sobrien fprintf(f, ".POSIX:\n"); 74370884Sjoe if (buildopts) { 74470884Sjoe fprintf(f, "BUILDOPTS+="); 74570884Sjoe output_strlst(f, buildopts); 74670884Sjoe } 747187131Sobrien fprintf(f, ".if defined(PROG)\n"); 748187131Sobrien fprintf(f, "%s?=${PROG}.o\n", objvar); 74970884Sjoe fprintf(f, ".endif\n"); 75070884Sjoe fprintf(f, "loop:\n\t@echo 'OBJS= '${%s}\n", objvar); 75168569Sjoe 752113886Sru fprintf(f, "crunchgen_objs:\n" 753237574Sobrien "\t@cd %s && %s -f %s $(BUILDOPTS) $(%s_OPTS)", 754237574Sobrien p->srcdir, path_make, tempfname, p->ident); 75570884Sjoe for (s = p->buildopts; s != NULL; s = s->next) 75670884Sjoe fprintf(f, " %s", s->str); 75770884Sjoe fprintf(f, " loop\n"); 75868569Sjoe 75970884Sjoe fclose(f); 7601722Sjkh 761237574Sobrien snprintf(line, MAXLINELEN, "cd %s && %s -f %s -B crunchgen_objs", 762237574Sobrien p->srcdir, path_make, tempfname); 76370884Sjoe if ((f = popen(line, "r")) == NULL) { 76470884Sjoe warn("submake pipe"); 76570884Sjoe goterror = 1; 76670884Sjoe return; 76770884Sjoe } 7681722Sjkh 76970884Sjoe while(fgets(line, MAXLINELEN, f)) { 77070884Sjoe if (strncmp(line, "OBJS= ", 6)) { 77170884Sjoe warnx("make error: %s", line); 77270884Sjoe goterror = 1; 77370884Sjoe continue; 77470884Sjoe } 77570884Sjoe 77670884Sjoe cp = line + 6; 777246256Spfg while (isspace((unsigned char)*cp)) 77870884Sjoe cp++; 77970884Sjoe 78070884Sjoe while(*cp) { 78170884Sjoe obj = cp; 782246256Spfg while (*cp && !isspace((unsigned char)*cp)) 78370884Sjoe cp++; 78470884Sjoe if (*cp) 78570884Sjoe *cp++ = '\0'; 78670884Sjoe add_string(&p->objs, obj); 787246256Spfg while (isspace((unsigned char)*cp)) 78870884Sjoe cp++; 78970884Sjoe } 7901722Sjkh } 79170884Sjoe 79270884Sjoe if ((rc=pclose(f)) != 0) { 79370884Sjoe warnx("make error: make returned %d", rc); 79470884Sjoe goterror = 1; 7951722Sjkh } 79670884Sjoe 79770884Sjoe unlink(tempfname); 7981722Sjkh} 7991722Sjkh 800237625Sobrienvoid 801237625Sobrienremove_error_progs(void) 8021722Sjkh{ 80370884Sjoe prog_t *p1, *p2; 8041722Sjkh 80570884Sjoe p1 = NULL; p2 = progs; 80670884Sjoe while (p2 != NULL) { 80770884Sjoe if (!p2->goterror) 80870884Sjoe p1 = p2, p2 = p2->next; 80970884Sjoe else { 81070884Sjoe /* delete it from linked list */ 81170884Sjoe warnx("%s: %s: ignoring program because of errors", 81270884Sjoe infilename, p2->name); 81370884Sjoe if (p1) 81470884Sjoe p1->next = p2->next; 81570884Sjoe else 81670884Sjoe progs = p2->next; 81770884Sjoe p2 = p2->next; 81870884Sjoe } 8191722Sjkh } 8201722Sjkh} 8211722Sjkh 822237625Sobrienvoid 823237625Sobriengen_specials_cache(void) 8241722Sjkh{ 82570884Sjoe FILE *cachef; 82670884Sjoe prog_t *p; 82770884Sjoe char line[MAXLINELEN]; 8281722Sjkh 82970884Sjoe snprintf(line, MAXLINELEN, "generating %s", cachename); 83070884Sjoe status(line); 8311722Sjkh 83270884Sjoe if ((cachef = fopen(cachename, "w")) == NULL) { 83370884Sjoe warn("%s", cachename); 83470884Sjoe goterror = 1; 83570884Sjoe return; 83670884Sjoe } 8371722Sjkh 83870884Sjoe fprintf(cachef, "# %s - parm cache generated from %s by crunchgen " 83970884Sjoe " %s\n\n", 8401722Sjkh cachename, infilename, CRUNCH_VERSION); 8411722Sjkh 84270884Sjoe for (p = progs; p != NULL; p = p->next) { 84370884Sjoe fprintf(cachef, "\n"); 84470884Sjoe if (p->srcdir) 84570884Sjoe fprintf(cachef, "special %s srcdir %s\n", 84670884Sjoe p->name, p->srcdir); 84770884Sjoe if (p->objdir) 84870884Sjoe fprintf(cachef, "special %s objdir %s\n", 84970884Sjoe p->name, p->objdir); 85070884Sjoe if (p->objs) { 85170884Sjoe fprintf(cachef, "special %s objs", p->name); 85270884Sjoe output_strlst(cachef, p->objs); 85370884Sjoe } 85470884Sjoe if (p->objpaths) { 85570884Sjoe fprintf(cachef, "special %s objpaths", p->name); 85670884Sjoe output_strlst(cachef, p->objpaths); 85770884Sjoe } 8581722Sjkh } 85970884Sjoe fclose(cachef); 8601722Sjkh} 8611722Sjkh 8621722Sjkh 863237625Sobrienvoid 864237625Sobriengen_output_makefile(void) 8651722Sjkh{ 86670884Sjoe prog_t *p; 86770884Sjoe FILE *outmk; 86870884Sjoe char line[MAXLINELEN]; 8691722Sjkh 87070884Sjoe snprintf(line, MAXLINELEN, "generating %s", outmkname); 87170884Sjoe status(line); 8721722Sjkh 87370884Sjoe if ((outmk = fopen(outmkname, "w")) == NULL) { 87470884Sjoe warn("%s", outmkname); 87570884Sjoe goterror = 1; 87670884Sjoe return; 87770884Sjoe } 8781722Sjkh 87970884Sjoe fprintf(outmk, "# %s - generated from %s by crunchgen %s\n\n", 8801722Sjkh outmkname, infilename, CRUNCH_VERSION); 8811722Sjkh 88270884Sjoe if (outhdrname[0] != '\0') 88370884Sjoe fprintf(outmk, ".include \"%s\"\n", outhdrname); 8841722Sjkh 88570884Sjoe top_makefile_rules(outmk); 88670884Sjoe for (p = progs; p != NULL; p = p->next) 88770884Sjoe prog_makefile_rules(outmk, p); 88870884Sjoe 88970884Sjoe fprintf(outmk, "\n# ========\n"); 89070884Sjoe fclose(outmk); 8911722Sjkh} 8921722Sjkh 8931722Sjkh 894237625Sobrienvoid 895237625Sobriengen_output_cfile(void) 8961722Sjkh{ 89770884Sjoe char **cp; 89870884Sjoe FILE *outcf; 89970884Sjoe prog_t *p; 90070884Sjoe strlst_t *s; 90170884Sjoe char line[MAXLINELEN]; 9021722Sjkh 90370884Sjoe snprintf(line, MAXLINELEN, "generating %s", outcfname); 90470884Sjoe status(line); 9051722Sjkh 90670884Sjoe if((outcf = fopen(outcfname, "w")) == NULL) { 90770884Sjoe warn("%s", outcfname); 90870884Sjoe goterror = 1; 90970884Sjoe return; 91070884Sjoe } 9111722Sjkh 91270884Sjoe fprintf(outcf, 91370884Sjoe "/* %s - generated from %s by crunchgen %s */\n", 9141722Sjkh outcfname, infilename, CRUNCH_VERSION); 9151722Sjkh 91670884Sjoe fprintf(outcf, "#define EXECNAME \"%s\"\n", execfname); 91770884Sjoe for (cp = crunched_skel; *cp != NULL; cp++) 91870884Sjoe fprintf(outcf, "%s\n", *cp); 9191722Sjkh 92070884Sjoe for (p = progs; p != NULL; p = p->next) 92170884Sjoe fprintf(outcf, "extern int _crunched_%s_stub();\n", p->ident); 9221722Sjkh 92370884Sjoe fprintf(outcf, "\nstruct stub entry_points[] = {\n"); 92470884Sjoe for (p = progs; p != NULL; p = p->next) { 92570884Sjoe fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n", 92670884Sjoe p->name, p->ident); 92770884Sjoe for (s = p->links; s != NULL; s = s->next) 92870884Sjoe fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n", 92970884Sjoe s->str, p->ident); 93070884Sjoe } 9318857Srgrimes 93270884Sjoe fprintf(outcf, "\t{ EXECNAME, crunched_main },\n"); 93370884Sjoe fprintf(outcf, "\t{ NULL, NULL }\n};\n"); 93470884Sjoe fclose(outcf); 9351722Sjkh} 9361722Sjkh 9371722Sjkh 9381722Sjkhchar *genident(char *str) 9391722Sjkh{ 94070884Sjoe char *n, *s, *d; 9411722Sjkh 94270884Sjoe /* 94370884Sjoe * generates a Makefile/C identifier from a program name, 94470884Sjoe * mapping '-' to '_' and ignoring all other non-identifier 94570884Sjoe * characters. This leads to programs named "foo.bar" and 94670884Sjoe * "foobar" to map to the same identifier. 94770884Sjoe */ 9481722Sjkh 94970884Sjoe if ((n = strdup(str)) == NULL) 95070884Sjoe return NULL; 95170884Sjoe for (d = s = n; *s != '\0'; s++) { 95270884Sjoe if (*s == '-') 95370884Sjoe *d++ = '_'; 954246256Spfg else if (*s == '_' || isalnum((unsigned char)*s)) 95570884Sjoe *d++ = *s; 95670884Sjoe } 95770884Sjoe *d = '\0'; 95870884Sjoe return n; 9591722Sjkh} 9601722Sjkh 9611722Sjkh 9621722Sjkhchar *dir_search(char *progname) 9631722Sjkh{ 96470884Sjoe char path[MAXPATHLEN]; 96570884Sjoe strlst_t *dir; 96670884Sjoe char *srcdir; 9671722Sjkh 96870884Sjoe for (dir = srcdirs; dir != NULL; dir = dir->next) { 96970884Sjoe snprintf(path, MAXPATHLEN, "%s/%s", dir->str, progname); 97070884Sjoe if (!is_dir(path)) 97170884Sjoe continue; 97270884Sjoe 97370884Sjoe if ((srcdir = strdup(path)) == NULL) 97470884Sjoe out_of_memory(); 97570884Sjoe 97670884Sjoe return srcdir; 97770331Sjoe } 97870884Sjoe return NULL; 9791722Sjkh} 9801722Sjkh 9811722Sjkh 982237625Sobrienvoid 983237625Sobrientop_makefile_rules(FILE *outmk) 9841722Sjkh{ 98570884Sjoe prog_t *p; 9861722Sjkh 987246346Spfg fprintf(outmk, "LD?= ld\n"); 988285986Sbdrewery fprintf(outmk, "STRIPBIN?= strip\n"); 989153687Sceri if ( subtract_strlst(&libs, &libs_so) ) 990153687Sceri fprintf(outmk, "# NOTE: Some LIBS declarations below overridden by LIBS_SO\n"); 991153687Sceri 99278520Sjoe fprintf(outmk, "LIBS+="); 99370884Sjoe output_strlst(outmk, libs); 9941722Sjkh 995153687Sceri fprintf(outmk, "LIBS_SO+="); 996153687Sceri output_strlst(outmk, libs_so); 997153687Sceri 99870884Sjoe if (makeobj) { 99970884Sjoe fprintf(outmk, "MAKEOBJDIRPREFIX?=%s\n", objprefix); 1000133399Sharti fprintf(outmk, "MAKEENV=env MAKEOBJDIRPREFIX=$(MAKEOBJDIRPREFIX)\n"); 1001133399Sharti fprintf(outmk, "CRUNCHMAKE=$(MAKEENV) $(MAKE)\n"); 100270884Sjoe } else { 1003133399Sharti fprintf(outmk, "CRUNCHMAKE=$(MAKE)\n"); 100470884Sjoe } 100570112Sjoe 100670884Sjoe if (buildopts) { 100770884Sjoe fprintf(outmk, "BUILDOPTS+="); 100870884Sjoe output_strlst(outmk, buildopts); 100970884Sjoe } 101068750Sjoe 101170884Sjoe fprintf(outmk, "CRUNCHED_OBJS="); 101270884Sjoe for (p = progs; p != NULL; p = p->next) 101370884Sjoe fprintf(outmk, " %s.lo", p->name); 101470884Sjoe fprintf(outmk, "\n"); 10151722Sjkh 101670884Sjoe fprintf(outmk, "SUBMAKE_TARGETS="); 101770884Sjoe for (p = progs; p != NULL; p = p->next) 101870884Sjoe fprintf(outmk, " %s_make", p->ident); 101970884Sjoe fprintf(outmk, "\nSUBCLEAN_TARGETS="); 102070884Sjoe for (p = progs; p != NULL; p = p->next) 102170884Sjoe fprintf(outmk, " %s_clean", p->ident); 102270884Sjoe fprintf(outmk, "\n\n"); 10231722Sjkh 102470884Sjoe fprintf(outmk, "all: objs exe\nobjs: $(SUBMAKE_TARGETS)\n"); 102570884Sjoe fprintf(outmk, "exe: %s\n", execfname); 1026164504Sjb fprintf(outmk, "%s: %s.o $(CRUNCHED_OBJS) $(SUBMAKE_TARGETS)\n", execfname, execfname); 1027153687Sceri fprintf(outmk, ".if defined(LIBS_SO) && !empty(LIBS_SO)\n"); 1028153687Sceri fprintf(outmk, "\t$(CC) -o %s %s.o $(CRUNCHED_OBJS) \\\n", 1029153687Sceri execfname, execfname); 1030153687Sceri fprintf(outmk, "\t\t-Xlinker -Bstatic $(LIBS) \\\n"); 1031153687Sceri fprintf(outmk, "\t\t-Xlinker -Bdynamic $(LIBS_SO)\n"); 1032153687Sceri fprintf(outmk, ".else\n"); 103370884Sjoe fprintf(outmk, "\t$(CC) -static -o %s %s.o $(CRUNCHED_OBJS) $(LIBS)\n", 10341722Sjkh execfname, execfname); 1035153687Sceri fprintf(outmk, ".endif\n"); 1036285986Sbdrewery fprintf(outmk, "\t$(STRIPBIN) %s\n", execfname); 103770884Sjoe fprintf(outmk, "realclean: clean subclean\n"); 103870884Sjoe fprintf(outmk, "clean:\n\trm -f %s *.lo *.o *_stub.c\n", execfname); 103970884Sjoe fprintf(outmk, "subclean: $(SUBCLEAN_TARGETS)\n"); 10401722Sjkh} 10411722Sjkh 10421722Sjkh 1043237625Sobrienvoid 1044237625Sobrienprog_makefile_rules(FILE *outmk, prog_t *p) 10451722Sjkh{ 104670884Sjoe strlst_t *lst; 104730120Sjoerg 104870884Sjoe fprintf(outmk, "\n# -------- %s\n\n", p->name); 10491722Sjkh 105081700Sjoe fprintf(outmk, "%s_OBJDIR=", p->ident); 105181700Sjoe if (p->objdir) 105281700Sjoe fprintf(outmk, "%s", p->objdir); 105381700Sjoe else 105481700Sjoe fprintf(outmk, "$(MAKEOBJDIRPREFIX)/$(%s_REALSRCDIR)\n", 105581700Sjoe p->ident); 105681700Sjoe fprintf(outmk, "\n"); 105781700Sjoe 1058164571Sjb fprintf(outmk, "%s_OBJPATHS=", p->ident); 1059164571Sjb if (p->objpaths) 1060164571Sjb output_strlst(outmk, p->objpaths); 1061164571Sjb else { 1062164571Sjb for (lst = p->objs; lst != NULL; lst = lst->next) { 1063164571Sjb fprintf(outmk, " $(%s_OBJDIR)/%s", p->ident, lst->str); 1064164571Sjb } 1065164571Sjb fprintf(outmk, "\n"); 1066164571Sjb } 1067311185Sbdrewery fprintf(outmk, "$(%s_OBJPATHS): .NOMETA\n", p->ident); 1068164571Sjb 106970884Sjoe if (p->srcdir && p->objs) { 107070884Sjoe fprintf(outmk, "%s_SRCDIR=%s\n", p->ident, p->srcdir); 107170884Sjoe fprintf(outmk, "%s_REALSRCDIR=%s\n", p->ident, p->realsrcdir); 107270112Sjoe 107370884Sjoe fprintf(outmk, "%s_OBJS=", p->ident); 107470884Sjoe output_strlst(outmk, p->objs); 107570884Sjoe if (p->buildopts != NULL) { 107670884Sjoe fprintf(outmk, "%s_OPTS+=", p->ident); 107770884Sjoe output_strlst(outmk, p->buildopts); 107870884Sjoe } 1079164654Sjb#if 0 1080164571Sjb fprintf(outmk, "$(%s_OBJPATHS): %s_make\n\n", p->ident, p->ident); 1081164654Sjb#endif 108270884Sjoe fprintf(outmk, "%s_make:\n", p->ident); 108370884Sjoe fprintf(outmk, "\t(cd $(%s_SRCDIR) && ", p->ident); 108470884Sjoe if (makeobj) 1085133399Sharti fprintf(outmk, "$(CRUNCHMAKE) obj && "); 108670884Sjoe fprintf(outmk, "\\\n"); 1087133399Sharti fprintf(outmk, "\t\t$(CRUNCHMAKE) $(BUILDOPTS) $(%s_OPTS) depend &&", 108870112Sjoe p->ident); 108970884Sjoe fprintf(outmk, "\\\n"); 1090133399Sharti fprintf(outmk, "\t\t$(CRUNCHMAKE) $(BUILDOPTS) $(%s_OPTS) " 109170884Sjoe "$(%s_OBJS))", 109270884Sjoe p->ident, p->ident); 109370884Sjoe fprintf(outmk, "\n"); 109470884Sjoe fprintf(outmk, "%s_clean:\n", p->ident); 1095133399Sharti fprintf(outmk, "\t(cd $(%s_SRCDIR) && $(CRUNCHMAKE) $(BUILDOPTS) clean cleandepend)\n\n", 109670884Sjoe p->ident); 109770884Sjoe } else { 109870884Sjoe fprintf(outmk, "%s_make:\n", p->ident); 109970884Sjoe fprintf(outmk, "\t@echo \"** cannot make objs for %s\"\n\n", 110075152Sru p->name); 110168569Sjoe } 11021722Sjkh 110393435Sluigi if (p->libs) { 110493435Sluigi fprintf(outmk, "%s_LIBS=", p->ident); 110593435Sluigi output_strlst(outmk, p->libs); 110693435Sluigi } 11071722Sjkh 110870884Sjoe fprintf(outmk, "%s_stub.c:\n", p->name); 110970884Sjoe fprintf(outmk, "\techo \"" 111070884Sjoe "int _crunched_%s_stub(int argc, char **argv, char **envp)" 111170884Sjoe "{return main(argc,argv,envp);}\" >%s_stub.c\n", 11121722Sjkh p->ident, p->name); 111393435Sluigi fprintf(outmk, "%s.lo: %s_stub.o $(%s_OBJPATHS)", 11141722Sjkh p->name, p->name, p->ident); 111593435Sluigi if (p->libs) 111693435Sluigi fprintf(outmk, " $(%s_LIBS)", p->ident); 1117153687Sceri 111893435Sluigi fprintf(outmk, "\n"); 1119284422Stijl fprintf(outmk, "\t$(CC) -nostdlib -Wl,-dc -r -o %s.lo %s_stub.o $(%s_OBJPATHS)", 11201722Sjkh p->name, p->name, p->ident); 112193435Sluigi if (p->libs) 112293435Sluigi fprintf(outmk, " $(%s_LIBS)", p->ident); 112393435Sluigi fprintf(outmk, "\n"); 112470884Sjoe fprintf(outmk, "\tcrunchide -k _crunched_%s_stub ", p->ident); 112570884Sjoe for (lst = p->keeplist; lst != NULL; lst = lst->next) 112670884Sjoe fprintf(outmk, "-k _%s ", lst->str); 112770884Sjoe fprintf(outmk, "%s.lo\n", p->name); 11281722Sjkh} 11291722Sjkh 1130237625Sobrienvoid 1131237625Sobrienoutput_strlst(FILE *outf, strlst_t *lst) 11321722Sjkh{ 113370884Sjoe for (; lst != NULL; lst = lst->next) 1134153687Sceri if ( strlen(lst->str) ) 1135153687Sceri fprintf(outf, " %s", lst->str); 113670884Sjoe fprintf(outf, "\n"); 11371722Sjkh} 11381722Sjkh 11391722Sjkh 11401722Sjkh/* 11411722Sjkh * ======================================================================== 11421722Sjkh * general library routines 11431722Sjkh * 11441722Sjkh */ 11451722Sjkh 1146237625Sobrienvoid 1147246256Spfgstatus(const char *str) 11481722Sjkh{ 114970884Sjoe static int lastlen = 0; 115070884Sjoe int len, spaces; 11511722Sjkh 115270884Sjoe if (!verbose) 115370884Sjoe return; 11541722Sjkh 115570884Sjoe len = strlen(str); 115670884Sjoe spaces = lastlen - len; 115770884Sjoe if (spaces < 1) 115870884Sjoe spaces = 1; 11591722Sjkh 116070884Sjoe fprintf(stderr, " [%s]%*.*s\r", str, spaces, spaces, " "); 116170884Sjoe fflush(stderr); 116270884Sjoe lastlen = len; 11631722Sjkh} 11641722Sjkh 11651722Sjkh 1166237625Sobrienvoid 1167237625Sobrienout_of_memory(void) 11681722Sjkh{ 116970884Sjoe err(1, "%s: %d: out of memory, stopping", infilename, linenum); 11701722Sjkh} 11711722Sjkh 11721722Sjkh 1173237625Sobrienvoid 1174237625Sobrienadd_string(strlst_t **listp, char *str) 11751722Sjkh{ 117670884Sjoe strlst_t *p1, *p2; 11771722Sjkh 117870884Sjoe /* add to end, but be smart about dups */ 11791722Sjkh 118070884Sjoe for (p1 = NULL, p2 = *listp; p2 != NULL; p1 = p2, p2 = p2->next) 118170884Sjoe if (!strcmp(p2->str, str)) 118270884Sjoe return; 11831722Sjkh 118470884Sjoe p2 = malloc(sizeof(strlst_t)); 118570884Sjoe if (p2) { 118670884Sjoe p2->next = NULL; 118770884Sjoe p2->str = strdup(str); 118870884Sjoe } 118970884Sjoe if (!p2 || !p2->str) 119070884Sjoe out_of_memory(); 11911722Sjkh 119270884Sjoe if (p1 == NULL) 119370884Sjoe *listp = p2; 119470884Sjoe else 119570884Sjoe p1->next = p2; 11961722Sjkh} 11971722Sjkh 1198237625Sobrienint 1199237625Sobriensubtract_strlst(strlst_t **lista, strlst_t **listb) 1200153687Sceri{ 1201153687Sceri int subtract_count = 0; 1202153687Sceri strlst_t *p1; 1203153687Sceri for (p1 = *listb; p1 != NULL; p1 = p1->next) 1204153687Sceri if ( in_list(lista, p1->str) ) { 1205153687Sceri warnx("Will compile library `%s' dynamically", p1->str); 1206153687Sceri strcat(p1->str, ""); 1207153687Sceri subtract_count++; 1208153687Sceri } 1209153687Sceri return subtract_count; 1210153687Sceri} 12111722Sjkh 1212237625Sobrienint 1213237625Sobrienin_list(strlst_t **listp, char *str) 1214153687Sceri{ 1215153687Sceri strlst_t *p1; 1216153687Sceri for (p1 = *listp; p1 != NULL; p1 = p1->next) 1217153687Sceri if (!strcmp(p1->str, str)) 1218153687Sceri return 1; 1219153687Sceri return 0; 1220153687Sceri} 1221153687Sceri 1222237625Sobrienint 1223246256Spfgis_dir(const char *pathname) 12241722Sjkh{ 122570884Sjoe struct stat buf; 12261722Sjkh 122770884Sjoe if (stat(pathname, &buf) == -1) 122870884Sjoe return 0; 122970884Sjoe 123070884Sjoe return S_ISDIR(buf.st_mode); 12311722Sjkh} 12321722Sjkh 1233237625Sobrienint 1234246256Spfgis_nonempty_file(const char *pathname) 12351722Sjkh{ 123670884Sjoe struct stat buf; 12371722Sjkh 123870884Sjoe if (stat(pathname, &buf) == -1) 123970884Sjoe return 0; 12401722Sjkh 124170884Sjoe return S_ISREG(buf.st_mode) && buf.st_size > 0; 12421722Sjkh} 1243