1 1.96 andvar /* $NetBSD: crunchgen.c,v 1.96 2024/02/05 21:46:07 andvar Exp $ */ 2 1.1 cgd /* 3 1.1 cgd * Copyright (c) 1994 University of Maryland 4 1.1 cgd * All Rights Reserved. 5 1.1 cgd * 6 1.1 cgd * Permission to use, copy, modify, distribute, and sell this software and its 7 1.1 cgd * documentation for any purpose is hereby granted without fee, provided that 8 1.1 cgd * the above copyright notice appear in all copies and that both that 9 1.1 cgd * copyright notice and this permission notice appear in supporting 10 1.1 cgd * documentation, and that the name of U.M. not be used in advertising or 11 1.1 cgd * publicity pertaining to distribution of the software without specific, 12 1.1 cgd * written prior permission. U.M. makes no representations about the 13 1.1 cgd * suitability of this software for any purpose. It is provided "as is" 14 1.1 cgd * without express or implied warranty. 15 1.1 cgd * 16 1.1 cgd * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 17 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. 18 1.1 cgd * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 19 1.1 cgd * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 20 1.1 cgd * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 21 1.1 cgd * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22 1.1 cgd * 23 1.1 cgd * Author: James da Silva, Systems Design and Analysis Group 24 1.1 cgd * Computer Science Department 25 1.1 cgd * University of Maryland at College Park 26 1.1 cgd */ 27 1.1 cgd /* 28 1.1 cgd * ======================================================================== 29 1.1 cgd * crunchgen.c 30 1.1 cgd * 31 1.1 cgd * Generates a Makefile and main C file for a crunched executable, 32 1.38 lukem * from specs given in a .conf file. 33 1.1 cgd */ 34 1.51 lukem 35 1.51 lukem #if HAVE_NBTOOL_CONFIG_H 36 1.51 lukem #include "nbtool_config.h" 37 1.31 tv #endif 38 1.31 tv 39 1.51 lukem #include <sys/cdefs.h> 40 1.51 lukem #if !defined(lint) 41 1.96 andvar __RCSID("$NetBSD: crunchgen.c,v 1.96 2024/02/05 21:46:07 andvar Exp $"); 42 1.7 perry #endif 43 1.7 perry 44 1.1 cgd #include <stdlib.h> 45 1.1 cgd #include <unistd.h> 46 1.1 cgd #include <stdio.h> 47 1.1 cgd #include <ctype.h> 48 1.1 cgd #include <string.h> 49 1.71 christos #include <errno.h> 50 1.71 christos #include <err.h> 51 1.72 christos #include <util.h> 52 1.1 cgd 53 1.1 cgd #include <sys/types.h> 54 1.1 cgd #include <sys/stat.h> 55 1.1 cgd #include <sys/param.h> 56 1.12 tsutsui #include <sys/utsname.h> 57 1.1 cgd 58 1.95 rin #define CRUNCH_VERSION "20230623" 59 1.1 cgd 60 1.1 cgd #define MAXLINELEN 16384 61 1.1 cgd #define MAXFIELDS 2048 62 1.1 cgd 63 1.1 cgd /* internal representation of conf file: */ 64 1.1 cgd 65 1.1 cgd /* simple lists of strings suffice for most parms */ 66 1.1 cgd 67 1.1 cgd typedef struct strlst { 68 1.1 cgd struct strlst *next; 69 1.1 cgd char *str; 70 1.1 cgd } strlst_t; 71 1.1 cgd 72 1.1 cgd /* progs have structure, each field can be set with "special" or calculated */ 73 1.1 cgd 74 1.1 cgd typedef struct prog { 75 1.1 cgd struct prog *next; 76 1.1 cgd char *name, *ident; 77 1.1 cgd char *srcdir, *objdir; 78 1.1 cgd strlst_t *objs, *objpaths; 79 1.30 ragge strlst_t *links, *keepsymbols; 80 1.1 cgd int goterror; 81 1.1 cgd } prog_t; 82 1.1 cgd 83 1.94 christos typedef struct var { 84 1.94 christos struct var *next; 85 1.94 christos char *name; 86 1.94 christos const char *value; 87 1.94 christos size_t len; 88 1.94 christos } var_t; 89 1.1 cgd 90 1.1 cgd /* global state */ 91 1.1 cgd 92 1.80 joerg static strlst_t *srcdirs = NULL; 93 1.80 joerg static strlst_t *libs = NULL; 94 1.80 joerg static strlst_t *vars = NULL; 95 1.80 joerg static prog_t *progs = NULL; 96 1.94 christos static var_t *mvars = NULL; 97 1.94 christos static var_t *evars = NULL; 98 1.80 joerg 99 1.80 joerg static char line[MAXLINELEN]; 100 1.80 joerg 101 1.80 joerg static char confname[MAXPATHLEN], infilename[MAXPATHLEN]; 102 1.80 joerg static char outmkname[MAXPATHLEN], outcfname[MAXPATHLEN], execfname[MAXPATHLEN]; 103 1.80 joerg static char cachename[MAXPATHLEN], curfilename[MAXPATHLEN]; 104 1.80 joerg static char curdir[MAXPATHLEN]; 105 1.80 joerg static char topdir[MAXPATHLEN]; 106 1.80 joerg static char libdir[MAXPATHLEN] = "/usr/lib"; 107 1.80 joerg static int linenum = -1; 108 1.80 joerg static int goterror = 0; 109 1.80 joerg 110 1.80 joerg static const char *pname = "crunchgen"; 111 1.80 joerg 112 1.88 kamil /* options */ 113 1.94 christos static int verbose, readcache, useobjs, oneobj; 114 1.88 kamil 115 1.80 joerg static int reading_cache; 116 1.80 joerg static char *machine; 117 1.80 joerg static char *makeobjdirprefix; 118 1.80 joerg static char *makebin; 119 1.80 joerg static char *makeflags; 120 1.1 cgd 121 1.1 cgd /* general library routines */ 122 1.1 cgd 123 1.80 joerg static void status(const char *str); 124 1.80 joerg static void add_string(strlst_t **listp, char *str); 125 1.80 joerg static int is_dir(const char *pathname); 126 1.80 joerg static int is_nonempty_file(const char *pathname); 127 1.94 christos static void addvar(const char *cstr); 128 1.1 cgd 129 1.1 cgd /* helper routines for main() */ 130 1.1 cgd 131 1.80 joerg __dead static void usage(void); 132 1.80 joerg static void parse_conf_file(void); 133 1.80 joerg static void gen_outputs(void); 134 1.1 cgd 135 1.20 christos extern char *crunched_skel[]; 136 1.1 cgd 137 1.60 dsl int 138 1.60 dsl main(int argc, char **argv) 139 1.1 cgd { 140 1.1 cgd char *p; 141 1.1 cgd int optc; 142 1.1 cgd 143 1.18 garbled if ((makebin = getenv("MAKE")) == NULL) 144 1.18 garbled makebin = strdup("make"); 145 1.18 garbled 146 1.26 jmc if ((makeflags = getenv("MAKEFLAGS")) == NULL) 147 1.26 jmc makeflags = strdup(""); 148 1.26 jmc 149 1.12 tsutsui if ((machine = getenv("MACHINE")) == NULL) { 150 1.68 tsutsui static struct utsname utsname; 151 1.12 tsutsui 152 1.12 tsutsui if (uname(&utsname) == -1) { 153 1.12 tsutsui perror("uname"); 154 1.12 tsutsui exit(1); 155 1.12 tsutsui } 156 1.12 tsutsui machine = utsname.machine; 157 1.12 tsutsui } 158 1.17 matt makeobjdirprefix = getenv("MAKEOBJDIRPREFIX"); 159 1.1 cgd verbose = 1; 160 1.1 cgd readcache = 1; 161 1.23 jmc useobjs = 0; 162 1.62 dsl oneobj = 1; 163 1.1 cgd *outmkname = *outcfname = *execfname = '\0'; 164 1.38 lukem 165 1.60 dsl if (argc > 0) 166 1.60 dsl pname = argv[0]; 167 1.1 cgd 168 1.94 christos while ((optc = getopt(argc, argv, "m:c:e:foqsD:L:OV:v:")) != -1) { 169 1.1 cgd switch(optc) { 170 1.1 cgd case 'f': readcache = 0; break; 171 1.1 cgd case 'q': verbose = 0; break; 172 1.62 dsl case 'O': oneobj = 0; break; 173 1.62 dsl case 'o': useobjs = 1, oneobj = 0; break; 174 1.1 cgd 175 1.72 christos case 'm': (void)estrlcpy(outmkname, optarg, sizeof(outmkname)); break; 176 1.72 christos case 'c': (void)estrlcpy(outcfname, optarg, sizeof(outcfname)); break; 177 1.72 christos case 'e': (void)estrlcpy(execfname, optarg, sizeof(execfname)); break; 178 1.1 cgd 179 1.72 christos case 'D': (void)estrlcpy(topdir, optarg, sizeof(topdir)); break; 180 1.72 christos case 'L': (void)estrlcpy(libdir, optarg, sizeof(libdir)); break; 181 1.57 christos case 'v': add_string(&vars, optarg); break; 182 1.94 christos case 'V': addvar(optarg); break; 183 1.3 cgd 184 1.1 cgd case '?': 185 1.1 cgd default: usage(); 186 1.1 cgd } 187 1.1 cgd } 188 1.1 cgd 189 1.1 cgd argc -= optind; 190 1.1 cgd argv += optind; 191 1.1 cgd 192 1.60 dsl if (argc != 1) 193 1.60 dsl usage(); 194 1.1 cgd 195 1.38 lukem /* 196 1.1 cgd * generate filenames 197 1.1 cgd */ 198 1.1 cgd 199 1.72 christos (void)estrlcpy(infilename, argv[0], sizeof(infilename)); 200 1.54 jmc getcwd(curdir, MAXPATHLEN); 201 1.1 cgd 202 1.1 cgd /* confname = `basename infilename .conf` */ 203 1.1 cgd 204 1.60 dsl if ((p = strrchr(infilename, '/')) != NULL) 205 1.72 christos (void)estrlcpy(confname, p + 1, sizeof(confname)); 206 1.60 dsl else 207 1.72 christos (void)estrlcpy(confname, infilename, sizeof(confname)); 208 1.60 dsl if ((p = strrchr(confname, '.')) != NULL && !strcmp(p, ".conf")) 209 1.60 dsl *p = '\0'; 210 1.1 cgd 211 1.8 mycroft if (!*outmkname) 212 1.8 mycroft (void)snprintf(outmkname, sizeof(outmkname), "%s.mk", confname); 213 1.8 mycroft if (!*outcfname) 214 1.8 mycroft (void)snprintf(outcfname, sizeof(outcfname), "%s.c", confname); 215 1.8 mycroft if (!*execfname) 216 1.8 mycroft (void)snprintf(execfname, sizeof(execfname), "%s", confname); 217 1.1 cgd 218 1.8 mycroft (void)snprintf(cachename, sizeof(cachename), "%s.cache", confname); 219 1.1 cgd 220 1.1 cgd parse_conf_file(); 221 1.1 cgd gen_outputs(); 222 1.1 cgd 223 1.1 cgd exit(goterror); 224 1.1 cgd } 225 1.1 cgd 226 1.1 cgd 227 1.60 dsl void 228 1.60 dsl usage(void) 229 1.1 cgd { 230 1.38 lukem fprintf(stderr, 231 1.93 christos "%s [-FfOoPpqSs] [-c c-file-name] [-D src-root] [-d build-options]\n" 232 1.63 wiz "\t [-e exec-file-name] [-L lib-dir] [-m makefile-name]\n" 233 1.63 wiz "\t [-v var-spec] conf-file\n", pname); 234 1.1 cgd exit(1); 235 1.1 cgd } 236 1.1 cgd 237 1.1 cgd 238 1.1 cgd /* 239 1.1 cgd * ======================================================================== 240 1.1 cgd * parse_conf_file subsystem 241 1.1 cgd * 242 1.1 cgd */ 243 1.1 cgd 244 1.1 cgd /* helper routines for parse_conf_file */ 245 1.1 cgd 246 1.80 joerg static void parse_one_file(char *filename); 247 1.80 joerg static void parse_line(char *line, int *fc, char **fv, int nf); 248 1.80 joerg static void add_srcdirs(int argc, char **argv); 249 1.80 joerg static void add_progs(int argc, char **argv); 250 1.80 joerg static void add_link(int argc, char **argv); 251 1.80 joerg static void add_libs(int argc, char **argv); 252 1.80 joerg static void add_special(int argc, char **argv); 253 1.1 cgd 254 1.80 joerg static prog_t *find_prog(char *str); 255 1.80 joerg static void add_prog(char *progname); 256 1.1 cgd 257 1.1 cgd 258 1.80 joerg static void 259 1.60 dsl parse_conf_file(void) 260 1.1 cgd { 261 1.60 dsl if (!is_nonempty_file(infilename)) { 262 1.1 cgd fprintf(stderr, "%s: fatal: input file \"%s\" not found.\n", 263 1.1 cgd pname, infilename); 264 1.1 cgd exit(1); 265 1.1 cgd } 266 1.1 cgd parse_one_file(infilename); 267 1.60 dsl if (readcache && is_nonempty_file(cachename)) { 268 1.1 cgd reading_cache = 1; 269 1.1 cgd parse_one_file(cachename); 270 1.1 cgd } 271 1.1 cgd } 272 1.1 cgd 273 1.1 cgd 274 1.80 joerg static void 275 1.60 dsl parse_one_file(char *filename) 276 1.1 cgd { 277 1.1 cgd char *fieldv[MAXFIELDS]; 278 1.1 cgd int fieldc; 279 1.1 cgd void (*f)(int c, char **v); 280 1.1 cgd FILE *cf; 281 1.1 cgd 282 1.8 mycroft (void)snprintf(line, sizeof(line), "reading %s", filename); 283 1.1 cgd status(line); 284 1.72 christos (void)estrlcpy(curfilename, filename, sizeof(curfilename)); 285 1.1 cgd 286 1.60 dsl if ((cf = fopen(curfilename, "r")) == NULL) { 287 1.1 cgd perror(curfilename); 288 1.1 cgd goterror = 1; 289 1.1 cgd return; 290 1.1 cgd } 291 1.1 cgd 292 1.1 cgd linenum = 0; 293 1.60 dsl while (fgets(line, MAXLINELEN, cf) != NULL) { 294 1.1 cgd linenum++; 295 1.1 cgd parse_line(line, &fieldc, fieldv, MAXFIELDS); 296 1.60 dsl if (fieldc < 1) 297 1.60 dsl continue; 298 1.60 dsl if (!strcmp(fieldv[0], "srcdirs")) f = add_srcdirs; 299 1.60 dsl else if (!strcmp(fieldv[0], "progs")) f = add_progs; 300 1.60 dsl else if (!strcmp(fieldv[0], "ln")) f = add_link; 301 1.60 dsl else if (!strcmp(fieldv[0], "libs")) f = add_libs; 302 1.60 dsl else if (!strcmp(fieldv[0], "special")) f = add_special; 303 1.1 cgd else { 304 1.1 cgd fprintf(stderr, "%s:%d: skipping unknown command `%s'.\n", 305 1.1 cgd curfilename, linenum, fieldv[0]); 306 1.1 cgd goterror = 1; 307 1.1 cgd continue; 308 1.1 cgd } 309 1.60 dsl if (fieldc < 2) { 310 1.38 lukem fprintf(stderr, 311 1.1 cgd "%s:%d: %s command needs at least 1 argument, skipping.\n", 312 1.1 cgd curfilename, linenum, fieldv[0]); 313 1.1 cgd goterror = 1; 314 1.1 cgd continue; 315 1.1 cgd } 316 1.1 cgd f(fieldc, fieldv); 317 1.1 cgd } 318 1.1 cgd 319 1.60 dsl if (ferror(cf)) { 320 1.1 cgd perror(curfilename); 321 1.1 cgd goterror = 1; 322 1.1 cgd } 323 1.1 cgd fclose(cf); 324 1.1 cgd } 325 1.1 cgd 326 1.1 cgd 327 1.80 joerg static void 328 1.75 lukem parse_line(char *pline, int *fc, char **fv, int nf) 329 1.1 cgd { 330 1.1 cgd char *p; 331 1.1 cgd 332 1.75 lukem p = pline; 333 1.1 cgd *fc = 0; 334 1.60 dsl for (;;) { 335 1.64 dsl while (isspace((unsigned char)*p)) 336 1.60 dsl p++; 337 1.60 dsl if (*p == '\0' || *p == '#') 338 1.60 dsl break; 339 1.60 dsl 340 1.60 dsl if (*fc < nf) 341 1.60 dsl fv[(*fc)++] = p; 342 1.64 dsl while (*p && !isspace((unsigned char)*p) && *p != '#') 343 1.60 dsl p++; 344 1.60 dsl if (*p == '\0' || *p == '#') 345 1.60 dsl break; 346 1.1 cgd *p++ = '\0'; 347 1.1 cgd } 348 1.60 dsl if (*p) 349 1.60 dsl *p = '\0'; /* needed for '#' case */ 350 1.1 cgd } 351 1.1 cgd 352 1.1 cgd 353 1.80 joerg static void 354 1.60 dsl add_srcdirs(int argc, char **argv) 355 1.1 cgd { 356 1.1 cgd int i; 357 1.3 cgd char tmppath[MAXPATHLEN]; 358 1.1 cgd 359 1.60 dsl for (i = 1; i < argc; i++) { 360 1.54 jmc if (argv[i][0] == '/') 361 1.72 christos (void)estrlcpy(tmppath, argv[i], sizeof(tmppath)); 362 1.3 cgd else { 363 1.54 jmc if (topdir[0] == '\0') 364 1.72 christos (void)estrlcpy(tmppath, curdir, sizeof(tmppath)); 365 1.54 jmc else 366 1.72 christos (void)estrlcpy(tmppath, topdir, sizeof(tmppath)); 367 1.72 christos (void)estrlcat(tmppath, "/", sizeof(tmppath)); 368 1.72 christos (void)estrlcat(tmppath, argv[i], sizeof(tmppath)); 369 1.3 cgd } 370 1.60 dsl if (is_dir(tmppath)) 371 1.3 cgd add_string(&srcdirs, tmppath); 372 1.1 cgd else { 373 1.38 lukem fprintf(stderr, "%s:%d: `%s' is not a directory, skipping it.\n", 374 1.3 cgd curfilename, linenum, tmppath); 375 1.1 cgd goterror = 1; 376 1.1 cgd } 377 1.1 cgd } 378 1.1 cgd } 379 1.1 cgd 380 1.1 cgd 381 1.80 joerg static void 382 1.60 dsl add_progs(int argc, char **argv) 383 1.1 cgd { 384 1.1 cgd int i; 385 1.1 cgd 386 1.60 dsl for (i = 1; i < argc; i++) 387 1.1 cgd add_prog(argv[i]); 388 1.1 cgd } 389 1.1 cgd 390 1.1 cgd 391 1.80 joerg static void 392 1.60 dsl add_prog(char *progname) 393 1.1 cgd { 394 1.1 cgd prog_t *p1, *p2; 395 1.1 cgd 396 1.1 cgd /* add to end, but be smart about dups */ 397 1.1 cgd 398 1.60 dsl for (p1 = NULL, p2 = progs; p2 != NULL; p1 = p2, p2 = p2->next) 399 1.60 dsl if (!strcmp(p2->name, progname)) 400 1.60 dsl return; 401 1.1 cgd 402 1.94 christos p2 = emalloc(sizeof(*p2)); 403 1.94 christos p2->name = estrdup(progname); 404 1.1 cgd 405 1.1 cgd p2->next = NULL; 406 1.60 dsl if (p1 == NULL) 407 1.60 dsl progs = p2; 408 1.60 dsl else 409 1.60 dsl p1->next = p2; 410 1.1 cgd 411 1.1 cgd p2->ident = p2->srcdir = p2->objdir = NULL; 412 1.30 ragge p2->objs = p2->objpaths = p2->links = p2->keepsymbols = NULL; 413 1.1 cgd p2->goterror = 0; 414 1.1 cgd } 415 1.1 cgd 416 1.1 cgd 417 1.80 joerg static void 418 1.60 dsl add_link(int argc, char **argv) 419 1.1 cgd { 420 1.1 cgd int i; 421 1.1 cgd prog_t *p = find_prog(argv[1]); 422 1.1 cgd 423 1.60 dsl if (p == NULL) { 424 1.38 lukem fprintf(stderr, 425 1.1 cgd "%s:%d: no prog %s previously declared, skipping link.\n", 426 1.1 cgd curfilename, linenum, argv[1]); 427 1.1 cgd goterror = 1; 428 1.1 cgd return; 429 1.1 cgd } 430 1.60 dsl for (i = 2; i < argc; i++) 431 1.1 cgd add_string(&p->links, argv[i]); 432 1.1 cgd } 433 1.1 cgd 434 1.1 cgd 435 1.80 joerg static void 436 1.60 dsl add_libs(int argc, char **argv) 437 1.1 cgd { 438 1.1 cgd int i; 439 1.1 cgd 440 1.60 dsl for (i = 1; i < argc; i++) 441 1.1 cgd add_string(&libs, argv[i]); 442 1.1 cgd } 443 1.1 cgd 444 1.1 cgd 445 1.80 joerg static void 446 1.60 dsl add_special(int argc, char **argv) 447 1.1 cgd { 448 1.1 cgd int i; 449 1.1 cgd prog_t *p = find_prog(argv[1]); 450 1.1 cgd 451 1.60 dsl if (p == NULL) { 452 1.60 dsl if (reading_cache) 453 1.60 dsl return; 454 1.38 lukem fprintf(stderr, 455 1.1 cgd "%s:%d: no prog %s previously declared, skipping special.\n", 456 1.1 cgd curfilename, linenum, argv[1]); 457 1.1 cgd goterror = 1; 458 1.1 cgd return; 459 1.1 cgd } 460 1.1 cgd 461 1.60 dsl if (!strcmp(argv[2], "ident")) { 462 1.60 dsl if (argc != 4) 463 1.60 dsl goto argcount; 464 1.94 christos p->ident = estrdup(argv[3]); 465 1.60 dsl return; 466 1.1 cgd } 467 1.60 dsl 468 1.60 dsl if (!strcmp(argv[2], "srcdir")) { 469 1.60 dsl if (argc != 4) 470 1.60 dsl goto argcount; 471 1.54 jmc if (argv[3][0] == '/') { 472 1.94 christos p->srcdir = estrdup(argv[3]); 473 1.5 pk } else { 474 1.5 pk char tmppath[MAXPATHLEN]; 475 1.54 jmc if (topdir[0] == '\0') 476 1.72 christos (void)estrlcpy(tmppath, curdir, sizeof(tmppath)); 477 1.54 jmc else 478 1.72 christos (void)estrlcpy(tmppath, topdir, sizeof(tmppath)); 479 1.72 christos (void)estrlcat(tmppath, "/", sizeof(tmppath)); 480 1.72 christos (void)estrlcat(tmppath, argv[3], sizeof(tmppath)); 481 1.94 christos p->srcdir = estrdup(tmppath); 482 1.5 pk } 483 1.60 dsl return; 484 1.1 cgd } 485 1.60 dsl 486 1.60 dsl if (!strcmp(argv[2], "objdir")) { 487 1.60 dsl if (argc != 4) 488 1.60 dsl goto argcount; 489 1.94 christos p->objdir = estrdup(argv[3]); 490 1.60 dsl return; 491 1.1 cgd } 492 1.60 dsl 493 1.60 dsl if (!strcmp(argv[2], "objs")) { 494 1.62 dsl oneobj = 0; 495 1.60 dsl for (i = 3; i < argc; i++) 496 1.1 cgd add_string(&p->objs, argv[i]); 497 1.60 dsl return; 498 1.1 cgd } 499 1.60 dsl 500 1.60 dsl if (!strcmp(argv[2], "objpaths")) { 501 1.62 dsl oneobj = 0; 502 1.60 dsl for (i = 3; i < argc; i++) 503 1.1 cgd add_string(&p->objpaths, argv[i]); 504 1.60 dsl return; 505 1.1 cgd } 506 1.60 dsl 507 1.60 dsl if (!strcmp(argv[2], "keepsymbols")) { 508 1.60 dsl for (i = 3; i < argc; i++) 509 1.30 ragge add_string(&p->keepsymbols, argv[i]); 510 1.60 dsl return; 511 1.30 ragge } 512 1.60 dsl 513 1.60 dsl fprintf(stderr, "%s:%d: bad parameter name `%s', skipping line.\n", 514 1.60 dsl curfilename, linenum, argv[2]); 515 1.60 dsl goterror = 1; 516 1.1 cgd return; 517 1.1 cgd 518 1.1 cgd argcount: 519 1.38 lukem fprintf(stderr, 520 1.1 cgd "%s:%d: too %s arguments, expected \"special %s %s <string>\".\n", 521 1.1 cgd curfilename, linenum, argc < 4? "few" : "many", argv[1], argv[2]); 522 1.1 cgd goterror = 1; 523 1.1 cgd } 524 1.1 cgd 525 1.1 cgd 526 1.80 joerg static prog_t * 527 1.60 dsl find_prog(char *str) 528 1.1 cgd { 529 1.1 cgd prog_t *p; 530 1.1 cgd 531 1.60 dsl for (p = progs; p != NULL; p = p->next) 532 1.60 dsl if (!strcmp(p->name, str)) 533 1.60 dsl return p; 534 1.1 cgd 535 1.1 cgd return NULL; 536 1.1 cgd } 537 1.1 cgd 538 1.1 cgd 539 1.1 cgd /* 540 1.1 cgd * ======================================================================== 541 1.1 cgd * gen_outputs subsystem 542 1.1 cgd * 543 1.1 cgd */ 544 1.1 cgd 545 1.1 cgd /* helper subroutines */ 546 1.1 cgd 547 1.80 joerg static void remove_error_progs(void); 548 1.80 joerg static void fillin_program(prog_t *p); 549 1.80 joerg static void gen_specials_cache(void); 550 1.80 joerg static void gen_output_makefile(void); 551 1.80 joerg static void gen_output_cfile(void); 552 1.80 joerg 553 1.80 joerg static void fillin_program_objs(prog_t *p, char *path); 554 1.80 joerg static void top_makefile_rules(FILE *outmk); 555 1.80 joerg static void bottom_makefile_rules(FILE *outmk); 556 1.93 christos static void prog_makefile_rules(FILE *outmk, prog_t *p, const char *); 557 1.80 joerg static void output_strlst(FILE *outf, strlst_t *lst); 558 1.80 joerg static char *genident(char *str); 559 1.80 joerg static char *dir_search(char *progname); 560 1.1 cgd 561 1.1 cgd 562 1.80 joerg static void 563 1.60 dsl gen_outputs(void) 564 1.1 cgd { 565 1.1 cgd prog_t *p; 566 1.1 cgd 567 1.60 dsl for (p = progs; p != NULL; p = p->next) 568 1.1 cgd fillin_program(p); 569 1.1 cgd 570 1.1 cgd remove_error_progs(); 571 1.1 cgd gen_specials_cache(); 572 1.1 cgd gen_output_cfile(); 573 1.1 cgd gen_output_makefile(); 574 1.1 cgd status(""); 575 1.38 lukem fprintf(stderr, 576 1.1 cgd "Run \"make -f %s objs exe\" to build crunched binary.\n", 577 1.1 cgd outmkname); 578 1.1 cgd } 579 1.1 cgd 580 1.1 cgd 581 1.80 joerg static void 582 1.60 dsl fillin_program(prog_t *p) 583 1.1 cgd { 584 1.1 cgd char path[MAXPATHLEN]; 585 1.1 cgd char *srcparent; 586 1.1 cgd strlst_t *s; 587 1.1 cgd 588 1.8 mycroft (void)snprintf(line, sizeof(line), "filling in parms for %s", p->name); 589 1.1 cgd status(line); 590 1.1 cgd 591 1.60 dsl if (!p->ident) 592 1.1 cgd p->ident = genident(p->name); 593 1.60 dsl if (!p->srcdir) { 594 1.1 cgd srcparent = dir_search(p->name); 595 1.60 dsl if (srcparent) { 596 1.8 mycroft (void)snprintf(path, sizeof(path), "%s/%s", srcparent, p->name); 597 1.60 dsl if (is_dir(path)) { 598 1.54 jmc if (path[0] == '/') { 599 1.94 christos p->srcdir = estrdup(path); 600 1.54 jmc } else { 601 1.54 jmc char tmppath[MAXPATHLEN]; 602 1.54 jmc if (topdir[0] == '\0') 603 1.72 christos (void)estrlcpy(tmppath, curdir, sizeof(tmppath)); 604 1.54 jmc else 605 1.72 christos (void)estrlcpy(tmppath, topdir, sizeof(tmppath)); 606 1.72 christos (void)estrlcat(tmppath, "/", sizeof(tmppath)); 607 1.72 christos (void)estrlcat(tmppath, path, sizeof(tmppath)); 608 1.94 christos p->srcdir = estrdup(tmppath); 609 1.54 jmc } 610 1.54 jmc } 611 1.5 pk } 612 1.1 cgd } 613 1.60 dsl 614 1.61 dsl if (!p->srcdir && verbose) 615 1.61 dsl fprintf(stderr, "%s: %s: warning: could not find source directory.\n", 616 1.61 dsl infilename, p->name); 617 1.61 dsl 618 1.60 dsl if (!p->objdir && p->srcdir && useobjs) { 619 1.17 matt if (makeobjdirprefix) { 620 1.17 matt (void)snprintf(path, sizeof(path), "%s/%s", makeobjdirprefix, p->srcdir); 621 1.17 matt if (is_dir(path)) 622 1.17 matt p->objdir = strdup(path); 623 1.17 matt } 624 1.17 matt if (!p->objdir) { 625 1.17 matt (void)snprintf(path, sizeof(path), "%s/obj.%s", p->srcdir, machine); 626 1.17 matt if (is_dir(path)) 627 1.17 matt p->objdir = strdup(path); 628 1.17 matt } 629 1.17 matt if (!p->objdir) { 630 1.13 sommerfe (void)snprintf(path, sizeof(path), "%s/obj", p->srcdir); 631 1.60 dsl if (is_dir(path)) 632 1.2 cgd p->objdir = strdup(path); 633 1.17 matt } 634 1.17 matt if (!p->objdir) { 635 1.17 matt p->objdir = p->srcdir; 636 1.2 cgd } 637 1.1 cgd } 638 1.1 cgd 639 1.62 dsl if (oneobj) 640 1.62 dsl return; 641 1.62 dsl 642 1.60 dsl if (p->srcdir) 643 1.8 mycroft (void)snprintf(path, sizeof(path), "%s/Makefile", p->srcdir); 644 1.60 dsl if (!p->objs && p->srcdir && is_nonempty_file(path)) 645 1.11 cgd fillin_program_objs(p, p->srcdir); 646 1.1 cgd 647 1.60 dsl if (!p->objpaths && p->objs) { 648 1.61 dsl char *objdir; 649 1.61 dsl if (p->objdir && useobjs) 650 1.61 dsl objdir = p->objdir; 651 1.61 dsl else 652 1.61 dsl objdir = p->ident; 653 1.61 dsl for (s = p->objs; s != NULL; s = s->next) { 654 1.61 dsl (void)snprintf(line, sizeof(line), "%s/%s", objdir, s->str); 655 1.61 dsl add_string(&p->objpaths, line); 656 1.1 cgd } 657 1.23 jmc } 658 1.38 lukem 659 1.60 dsl if (!p->objs && verbose) 660 1.38 lukem fprintf(stderr, "%s: %s: warning: could not find any .o files.\n", 661 1.1 cgd infilename, p->name); 662 1.1 cgd 663 1.60 dsl if (!p->objpaths) { 664 1.38 lukem fprintf(stderr, 665 1.1 cgd "%s: %s: error: no objpaths specified or calculated.\n", 666 1.1 cgd infilename, p->name); 667 1.1 cgd p->goterror = goterror = 1; 668 1.1 cgd } 669 1.1 cgd } 670 1.1 cgd 671 1.80 joerg static void 672 1.60 dsl fillin_program_objs(prog_t *p, char *dirpath) 673 1.1 cgd { 674 1.1 cgd char *obj, *cp; 675 1.1 cgd int rc; 676 1.7 perry int fd; 677 1.1 cgd FILE *f; 678 1.35 lukem char tempfname[MAXPATHLEN]; 679 1.1 cgd 680 1.1 cgd /* discover the objs from the srcdir Makefile */ 681 1.1 cgd 682 1.35 lukem (void)snprintf(tempfname, sizeof(tempfname), "/tmp/%sXXXXXX", confname); 683 1.60 dsl if ((fd = mkstemp(tempfname)) < 0) { 684 1.7 perry perror(tempfname); 685 1.7 perry exit(1); 686 1.7 perry } 687 1.7 perry 688 1.60 dsl if ((f = fdopen(fd, "w")) == NULL) { 689 1.1 cgd perror(tempfname); 690 1.1 cgd goterror = 1; 691 1.1 cgd return; 692 1.1 cgd } 693 1.38 lukem 694 1.14 mycroft fprintf(f, ".include \"${.CURDIR}/Makefile\"\n"); 695 1.14 mycroft fprintf(f, ".if defined(PROG)\n"); 696 1.14 mycroft fprintf(f, "OBJS?= ${PROG}.o\n"); 697 1.1 cgd fprintf(f, ".endif\n"); 698 1.1 cgd fprintf(f, "crunchgen_objs:\n\t@echo 'OBJS= '${OBJS}\n"); 699 1.1 cgd fclose(f); 700 1.1 cgd 701 1.11 cgd (void)snprintf(line, sizeof(line), 702 1.52 nathanw "cd %s && %s -B -f %s %s CRUNCHEDPROG=1 crunchgen_objs 2>&1", dirpath, 703 1.33 lukem makebin, tempfname, makeflags); 704 1.60 dsl if ((f = popen(line, "r")) == NULL) { 705 1.1 cgd perror("submake pipe"); 706 1.1 cgd goterror = 1; 707 1.23 jmc unlink(tempfname); 708 1.1 cgd return; 709 1.1 cgd } 710 1.1 cgd 711 1.60 dsl while (fgets(line, MAXLINELEN, f)) { 712 1.60 dsl if (strncmp(line, "OBJS= ", 6)) { 713 1.2 cgd if (strcmp(line, 714 1.2 cgd "sh: warning: running as root with dot in PATH\n") == 0) 715 1.2 cgd continue; 716 1.1 cgd fprintf(stderr, "make error: %s", line); 717 1.38 lukem goterror = 1; 718 1.1 cgd continue; 719 1.1 cgd } 720 1.1 cgd cp = line + 6; 721 1.64 dsl while (isspace((unsigned char)*cp)) 722 1.60 dsl cp++; 723 1.60 dsl while (*cp) { 724 1.1 cgd obj = cp; 725 1.64 dsl while (*cp && !isspace((unsigned char)*cp)) 726 1.60 dsl cp++; 727 1.60 dsl if (*cp) 728 1.60 dsl *cp++ = '\0'; 729 1.1 cgd add_string(&p->objs, obj); 730 1.64 dsl while (isspace((unsigned char)*cp)) 731 1.60 dsl cp++; 732 1.1 cgd } 733 1.1 cgd } 734 1.60 dsl if ((rc=pclose(f)) != 0) { 735 1.1 cgd fprintf(stderr, "make error: make returned %d\n", rc); 736 1.1 cgd goterror = 1; 737 1.1 cgd } 738 1.1 cgd unlink(tempfname); 739 1.1 cgd } 740 1.1 cgd 741 1.80 joerg static void 742 1.60 dsl remove_error_progs(void) 743 1.1 cgd { 744 1.1 cgd prog_t *p1, *p2; 745 1.1 cgd 746 1.38 lukem p1 = NULL; p2 = progs; 747 1.60 dsl while (p2 != NULL) { 748 1.60 dsl if (!p2->goterror) 749 1.1 cgd p1 = p2, p2 = p2->next; 750 1.1 cgd else { 751 1.1 cgd /* delete it from linked list */ 752 1.1 cgd fprintf(stderr, "%s: %s: ignoring program because of errors.\n", 753 1.1 cgd infilename, p2->name); 754 1.60 dsl if (p1) 755 1.60 dsl p1->next = p2->next; 756 1.60 dsl else 757 1.60 dsl progs = p2->next; 758 1.1 cgd p2 = p2->next; 759 1.1 cgd } 760 1.1 cgd } 761 1.1 cgd } 762 1.1 cgd 763 1.80 joerg static void 764 1.60 dsl gen_specials_cache(void) 765 1.1 cgd { 766 1.1 cgd FILE *cachef; 767 1.1 cgd prog_t *p; 768 1.1 cgd 769 1.8 mycroft (void)snprintf(line, sizeof(line), "generating %s", cachename); 770 1.1 cgd status(line); 771 1.1 cgd 772 1.60 dsl if ((cachef = fopen(cachename, "w")) == NULL) { 773 1.1 cgd perror(cachename); 774 1.1 cgd goterror = 1; 775 1.1 cgd return; 776 1.1 cgd } 777 1.1 cgd 778 1.1 cgd fprintf(cachef, "# %s - parm cache generated from %s by crunchgen %s\n\n", 779 1.1 cgd cachename, infilename, CRUNCH_VERSION); 780 1.1 cgd 781 1.60 dsl for (p = progs; p != NULL; p = p->next) { 782 1.1 cgd fprintf(cachef, "\n"); 783 1.60 dsl if (p->srcdir) 784 1.1 cgd fprintf(cachef, "special %s srcdir %s\n", p->name, p->srcdir); 785 1.60 dsl if (p->objdir && useobjs) 786 1.1 cgd fprintf(cachef, "special %s objdir %s\n", p->name, p->objdir); 787 1.60 dsl if (p->objs) { 788 1.1 cgd fprintf(cachef, "special %s objs", p->name); 789 1.1 cgd output_strlst(cachef, p->objs); 790 1.1 cgd } 791 1.62 dsl if (p->objpaths) { 792 1.62 dsl fprintf(cachef, "special %s objpaths", p->name); 793 1.62 dsl output_strlst(cachef, p->objpaths); 794 1.62 dsl } 795 1.1 cgd } 796 1.1 cgd fclose(cachef); 797 1.1 cgd } 798 1.1 cgd 799 1.80 joerg static void 800 1.94 christos addvar(const char *cstr) 801 1.93 christos { 802 1.94 christos char *str = estrdup(cstr), *p; 803 1.94 christos var_t *v = emalloc(sizeof(*v)); 804 1.94 christos 805 1.94 christos if ((p = strchr(str, '=')) == NULL) { 806 1.94 christos v->value = ""; 807 1.94 christos } else { 808 1.94 christos *p++ = '\0'; 809 1.94 christos v->value = p; 810 1.94 christos } 811 1.94 christos v->name = str; 812 1.94 christos // "%s=${%s:Q} " 813 1.94 christos v->len = 2 * strlen(v->name) + 7; 814 1.94 christos v->next = NULL; 815 1.94 christos if (mvars == NULL) { 816 1.94 christos mvars = evars = v; 817 1.94 christos } else { 818 1.94 christos evars->next = v; 819 1.94 christos evars = v; 820 1.94 christos } 821 1.93 christos } 822 1.93 christos 823 1.93 christos 824 1.93 christos static void 825 1.60 dsl gen_output_makefile(void) 826 1.1 cgd { 827 1.1 cgd prog_t *p; 828 1.94 christos var_t *v; 829 1.1 cgd FILE *outmk; 830 1.94 christos size_t len; 831 1.94 christos char *linevars, *ptr; 832 1.1 cgd 833 1.8 mycroft (void)snprintf(line, sizeof(line), "generating %s", outmkname); 834 1.1 cgd status(line); 835 1.1 cgd 836 1.60 dsl if ((outmk = fopen(outmkname, "w")) == NULL) { 837 1.1 cgd perror(outmkname); 838 1.1 cgd goterror = 1; 839 1.1 cgd return; 840 1.1 cgd } 841 1.1 cgd 842 1.1 cgd fprintf(outmk, "# %s - generated from %s by crunchgen %s\n\n", 843 1.1 cgd outmkname, infilename, CRUNCH_VERSION); 844 1.1 cgd 845 1.94 christos top_makefile_rules(outmk); 846 1.94 christos 847 1.94 christos 848 1.94 christos len = 0; 849 1.94 christos for (v = mvars; v != NULL; v = v->next) { 850 1.94 christos len += v->len; 851 1.94 christos } 852 1.94 christos 853 1.94 christos linevars = emalloc(len + 1); 854 1.93 christos 855 1.94 christos ptr = linevars; 856 1.94 christos for (v = mvars; v != NULL; v = v->next) { 857 1.94 christos int rl = snprintf(ptr, v->len + 1, "%s=${%s:Q} ", v->name, v->name); 858 1.94 christos ptr += rl; 859 1.94 christos } 860 1.1 cgd 861 1.60 dsl for (p = progs; p != NULL; p = p->next) 862 1.94 christos prog_makefile_rules(outmk, p, linevars); 863 1.1 cgd 864 1.24 jmc fprintf(outmk, "\n.include <bsd.prog.mk>\n"); 865 1.1 cgd fprintf(outmk, "\n# ========\n"); 866 1.40 lukem 867 1.40 lukem bottom_makefile_rules(outmk); 868 1.40 lukem 869 1.1 cgd fclose(outmk); 870 1.1 cgd } 871 1.1 cgd 872 1.1 cgd 873 1.80 joerg static void 874 1.60 dsl gen_output_cfile(void) 875 1.1 cgd { 876 1.1 cgd char **cp; 877 1.1 cgd FILE *outcf; 878 1.1 cgd prog_t *p; 879 1.1 cgd strlst_t *s; 880 1.1 cgd 881 1.8 mycroft (void)snprintf(line, sizeof(line), "generating %s", outcfname); 882 1.1 cgd status(line); 883 1.1 cgd 884 1.60 dsl if ((outcf = fopen(outcfname, "w")) == NULL) { 885 1.1 cgd perror(outcfname); 886 1.1 cgd goterror = 1; 887 1.1 cgd return; 888 1.1 cgd } 889 1.1 cgd 890 1.38 lukem fprintf(outcf, 891 1.1 cgd "/* %s - generated from %s by crunchgen %s */\n", 892 1.1 cgd outcfname, infilename, CRUNCH_VERSION); 893 1.1 cgd 894 1.1 cgd fprintf(outcf, "#define EXECNAME \"%s\"\n", execfname); 895 1.60 dsl for (cp = crunched_skel; *cp != NULL; cp++) 896 1.1 cgd fprintf(outcf, "%s\n", *cp); 897 1.1 cgd 898 1.60 dsl for (p = progs; p != NULL; p = p->next) 899 1.79 christos fprintf(outcf, "extern int _crunched_%s_stub(int, char **, char **);\n", 900 1.79 christos p->ident); 901 1.1 cgd 902 1.79 christos fprintf(outcf, "\nstatic const struct stub entry_points[] = {\n"); 903 1.60 dsl for (p = progs; p != NULL; p = p->next) { 904 1.1 cgd fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n", 905 1.1 cgd p->name, p->ident); 906 1.60 dsl for (s = p->links; s != NULL; s = s->next) 907 1.1 cgd fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n", 908 1.1 cgd s->str, p->ident); 909 1.1 cgd } 910 1.38 lukem 911 1.1 cgd fprintf(outcf, "\t{ EXECNAME, crunched_main },\n"); 912 1.1 cgd fprintf(outcf, "\t{ NULL, NULL }\n};\n"); 913 1.1 cgd fclose(outcf); 914 1.1 cgd } 915 1.1 cgd 916 1.1 cgd 917 1.80 joerg static char * 918 1.60 dsl genident(char *str) 919 1.1 cgd { 920 1.1 cgd char *n,*s,*d; 921 1.1 cgd 922 1.1 cgd /* 923 1.1 cgd * generates a Makefile/C identifier from a program name, mapping '-' to 924 1.1 cgd * '_' and ignoring all other non-identifier characters. This leads to 925 1.1 cgd * programs named "foo.bar" and "foobar" to map to the same identifier. 926 1.1 cgd */ 927 1.1 cgd 928 1.60 dsl if ((n = strdup(str)) == NULL) 929 1.1 cgd return NULL; 930 1.60 dsl for (d = s = n; *s != '\0'; s++) { 931 1.60 dsl if (*s == '-') 932 1.60 dsl *d++ = '_'; 933 1.60 dsl else 934 1.64 dsl if (*s == '_' || isalnum((unsigned char)*s)) 935 1.60 dsl *d++ = *s; 936 1.1 cgd } 937 1.1 cgd *d = '\0'; 938 1.1 cgd return n; 939 1.1 cgd } 940 1.1 cgd 941 1.1 cgd 942 1.80 joerg static char * 943 1.60 dsl dir_search(char *progname) 944 1.1 cgd { 945 1.1 cgd char path[MAXPATHLEN]; 946 1.1 cgd strlst_t *dir; 947 1.1 cgd 948 1.60 dsl for (dir=srcdirs; dir != NULL; dir=dir->next) { 949 1.86 mrg snprintf(path, sizeof(path), "%s/%s/Makefile", dir->str, progname); 950 1.86 mrg if (is_nonempty_file(path)) 951 1.60 dsl return dir->str; 952 1.1 cgd } 953 1.1 cgd return NULL; 954 1.1 cgd } 955 1.1 cgd 956 1.1 cgd 957 1.80 joerg static void 958 1.60 dsl top_makefile_rules(FILE *outmk) 959 1.1 cgd { 960 1.1 cgd prog_t *p; 961 1.94 christos var_t *v; 962 1.1 cgd 963 1.94 christos for (v = mvars; v != NULL; v = v->next) { 964 1.94 christos fprintf(outmk, "%s=%s\n", v->name, v->value); 965 1.94 christos } 966 1.26 jmc fprintf(outmk, "MAKE?=make\n"); 967 1.25 jmc #ifdef NEW_TOOLCHAIN 968 1.25 jmc fprintf(outmk, "OBJCOPY?=objcopy\n"); 969 1.41 simonb fprintf(outmk, "NM?=nm\n"); 970 1.74 apb fprintf(outmk, "AWK?=awk\n"); 971 1.25 jmc #else 972 1.19 garbled fprintf(outmk, "CRUNCHIDE?=crunchide\n"); 973 1.25 jmc #endif 974 1.1 cgd 975 1.1 cgd fprintf(outmk, "CRUNCHED_OBJS="); 976 1.60 dsl for (p = progs; p != NULL; p = p->next) 977 1.10 wrstuden fprintf(outmk, " %s.cro", p->name); 978 1.1 cgd fprintf(outmk, "\n"); 979 1.24 jmc fprintf(outmk, "DPADD+= ${CRUNCHED_OBJS}\n"); 980 1.24 jmc fprintf(outmk, "LDADD+= ${CRUNCHED_OBJS} "); 981 1.24 jmc output_strlst(outmk, libs); 982 1.42 msaitoh fprintf(outmk, "CRUNCHEDOBJSDIRS="); 983 1.60 dsl for (p = progs; p != NULL; p = p->next) 984 1.42 msaitoh fprintf(outmk, " %s", p->ident); 985 1.42 msaitoh fprintf(outmk, "\n\n"); 986 1.38 lukem 987 1.1 cgd fprintf(outmk, "SUBMAKE_TARGETS="); 988 1.60 dsl for (p = progs; p != NULL; p = p->next) 989 1.1 cgd fprintf(outmk, " %s_make", p->ident); 990 1.1 cgd fprintf(outmk, "\n\n"); 991 1.1 cgd 992 1.40 lukem fprintf(outmk, "PROG=%s\n\n", execfname); 993 1.90 mrg 994 1.95 rin fprintf(outmk, "OBJCOPY_REMOVE_FLAGS=-R .eh_frame_hdr -R .note -R .ident -R .comment -R .copyright\n\n"); 995 1.90 mrg 996 1.90 mrg fprintf(outmk, "OBJCOPY_REMOVE_FLAGS+=-R .eh_frame\n"); 997 1.90 mrg fprintf(outmk, ".if ${MACHINE} != \"sparc64\"\n"); 998 1.90 mrg fprintf(outmk, "OBJCOPY_REMOVE_FLAGS+=-R .note.netbsd.mcmodel\n"); 999 1.90 mrg fprintf(outmk, ".endif\n\n"); 1000 1.38 lukem 1001 1.47 dsl fprintf(outmk, "all: ${PROG}.crunched\n"); 1002 1.47 dsl fprintf(outmk, "${PROG}.crunched: ${SUBMAKE_TARGETS} .WAIT ${PROG}.strip\n"); 1003 1.45 dsl fprintf(outmk, "${PROG}.strip:\n"); 1004 1.45 dsl fprintf(outmk, "\t${MAKE} -f ${PROG}.mk ${PROG}\n"); 1005 1.49 dsl fprintf(outmk, "\t@[ -f ${PROG}.unstripped -a ! ${PROG} -nt ${PROG}.unstripped ] || { \\\n"); 1006 1.95 rin fprintf(outmk, "\t\t${_MKSHMSG:Uecho} \" strip and clear PaX flags \" ${PROG}; \\\n"); 1007 1.49 dsl fprintf(outmk, "\t\tcp ${PROG} ${PROG}.unstripped && \\\n"); 1008 1.90 mrg fprintf(outmk, "\t\t${OBJCOPY} -S ${OBJCOPY_REMOVE_FLAGS} ${PROG} && \\\n"); 1009 1.95 rin fprintf(outmk, "\t\t${PAXCTL} -0 ${PROG} && \\\n"); 1010 1.49 dsl fprintf(outmk, "\t\ttouch ${PROG}.unstripped; \\\n"); 1011 1.45 dsl fprintf(outmk, "\t}\n"); 1012 1.24 jmc fprintf(outmk, "objs: $(SUBMAKE_TARGETS)\n"); 1013 1.1 cgd fprintf(outmk, "exe: %s\n", execfname); 1014 1.50 lukem fprintf(outmk, "clean:\n\trm -rf %s *.cro *.cro.syms *.o *_stub.c ${CRUNCHEDOBJSDIRS} ${PROG}.unstripped\n", 1015 1.1 cgd execfname); 1016 1.40 lukem } 1017 1.40 lukem 1018 1.93 christos 1019 1.80 joerg static void 1020 1.60 dsl bottom_makefile_rules(FILE *outmk) 1021 1.40 lukem { 1022 1.1 cgd } 1023 1.1 cgd 1024 1.1 cgd 1025 1.80 joerg static void 1026 1.94 christos prog_makefile_rules(FILE *outmk, prog_t *p, const char *linevars) 1027 1.1 cgd { 1028 1.30 ragge strlst_t *lst; 1029 1.30 ragge 1030 1.1 cgd fprintf(outmk, "\n# -------- %s\n\n", p->name); 1031 1.1 cgd 1032 1.60 dsl fprintf(outmk, "%s_OBJPATHS=", p->ident); 1033 1.62 dsl #ifndef NEW_TOOLCHAIN 1034 1.62 dsl fprintf(outmk, " %s_stub.o", p->name); 1035 1.62 dsl #endif 1036 1.62 dsl if (p->objs) 1037 1.62 dsl output_strlst(outmk, p->objpaths); 1038 1.62 dsl else 1039 1.62 dsl fprintf(outmk, " %s/%s.ro\n", p->ident, p->name); 1040 1.23 jmc 1041 1.62 dsl if (p->srcdir && !useobjs) { 1042 1.1 cgd fprintf(outmk, "%s_SRCDIR=%s\n", p->ident, p->srcdir); 1043 1.62 dsl if (p->objs) { 1044 1.62 dsl fprintf(outmk, "%s_OBJS=", p->ident); 1045 1.62 dsl output_strlst(outmk, p->objs); 1046 1.62 dsl } 1047 1.67 jmc fprintf(outmk, "%s_make: %s .PHONY\n", p->ident, p->ident); 1048 1.67 jmc fprintf(outmk, "\t( cd %s; printf '.PATH: ${%s_SRCDIR}\\n" 1049 1.61 dsl ".CURDIR:= ${%s_SRCDIR}\\n" 1050 1.61 dsl ".include \"$${.CURDIR}/Makefile\"\\n", 1051 1.38 lukem p->ident, p->ident, p->ident); 1052 1.60 dsl for (lst = vars; lst != NULL; lst = lst->next) 1053 1.57 christos fprintf(outmk, "%s\\n", lst->str); 1054 1.57 christos fprintf(outmk, "'\\\n"); 1055 1.78 christos #define MAKECMD \ 1056 1.94 christos "\t| ${MAKE} -f- CRUNCHEDPROG=1 %s" 1057 1.94 christos fprintf(outmk, MAKECMD "depend", linevars); 1058 1.67 jmc fprintf(outmk, " )\n"); 1059 1.67 jmc fprintf(outmk, "\t( cd %s; printf '.PATH: ${%s_SRCDIR}\\n" 1060 1.67 jmc ".CURDIR:= ${%s_SRCDIR}\\n" 1061 1.67 jmc ".include \"$${.CURDIR}/Makefile\"\\n", 1062 1.67 jmc p->ident, p->ident, p->ident); 1063 1.67 jmc for (lst = vars; lst != NULL; lst = lst->next) 1064 1.67 jmc fprintf(outmk, "%s\\n", lst->str); 1065 1.67 jmc fprintf(outmk, "'\\\n"); 1066 1.94 christos fprintf(outmk, MAKECMD, linevars); 1067 1.62 dsl if (p->objs) 1068 1.67 jmc fprintf(outmk, "${%s_OBJS} ) \n\n", p->ident); 1069 1.62 dsl else 1070 1.67 jmc fprintf(outmk, "%s.ro ) \n\n", p->name); 1071 1.60 dsl } else 1072 1.38 lukem fprintf(outmk, "%s_make:\n\t@echo \"** Using existing objs for %s\"\n\n", 1073 1.1 cgd p->ident, p->name); 1074 1.1 cgd 1075 1.76 kiyohara #ifdef NEW_TOOLCHAIN 1076 1.76 kiyohara fprintf(outmk, "%s:\n\t mkdir %s\n", p->ident, p->ident); 1077 1.76 kiyohara #endif 1078 1.62 dsl fprintf(outmk, "%s.cro: %s .WAIT ${%s_OBJPATHS}\n", 1079 1.62 dsl p->name, p->ident, p->ident); 1080 1.62 dsl 1081 1.25 jmc #ifdef NEW_TOOLCHAIN 1082 1.62 dsl if (p->objs) 1083 1.62 dsl fprintf(outmk, "\t${LD} -r -o %s/%s.ro $(%s_OBJPATHS)\n", 1084 1.62 dsl p->ident, p->name, p->ident); 1085 1.61 dsl /* Use one awk command.... */ 1086 1.74 apb fprintf(outmk, "\t${NM} -ng %s/%s.ro | ${AWK} '/^ *U / { next };", 1087 1.62 dsl p->ident, p->name); 1088 1.61 dsl fprintf(outmk, " /^[0-9a-fA-F]+ C/ { next };"); 1089 1.41 simonb for (lst = p->keepsymbols; lst != NULL; lst = lst->next) 1090 1.61 dsl fprintf(outmk, " / %s$$/ { next };", lst->str); 1091 1.62 dsl fprintf(outmk, " / main$$/ { print \"main _crunched_%s_stub\"; next };", 1092 1.69 simonb p->ident); 1093 1.96 andvar /* gdb thinks these are C++ and ignores everything after the first $$. */ 1094 1.61 dsl fprintf(outmk, " { print $$3 \" \" $$3 \"$$$$from$$$$%s\" }' " 1095 1.61 dsl "> %s.cro.syms\n", p->name, p->name); 1096 1.48 thorpej fprintf(outmk, "\t${OBJCOPY} --redefine-syms %s.cro.syms ", p->name); 1097 1.62 dsl fprintf(outmk, "%s/%s.ro %s.cro\n", p->ident, p->name, p->name); 1098 1.41 simonb #else 1099 1.62 dsl fprintf(outmk, "\t${LD} -dc -r -o %s.cro $(%s_OBJPATHS)\n", 1100 1.62 dsl p->name, p->ident); 1101 1.30 ragge fprintf(outmk, "\t${CRUNCHIDE} -k _crunched_%s_stub ", p->ident); 1102 1.30 ragge for (lst = p->keepsymbols; lst != NULL; lst = lst->next) 1103 1.30 ragge fprintf(outmk, "-k %s ", lst->str); 1104 1.61 dsl fprintf(outmk, "%s.cro\n", p->name); 1105 1.62 dsl fprintf(outmk, "%s_stub.c:\n", p->name); 1106 1.62 dsl fprintf(outmk, "\techo \"" 1107 1.62 dsl "int _crunched_%s_stub(int argc, char **argv, char **envp)" 1108 1.62 dsl "{return main(argc,argv,envp);}\" >%s_stub.c\n", 1109 1.62 dsl p->ident, p->name); 1110 1.25 jmc #endif 1111 1.1 cgd } 1112 1.1 cgd 1113 1.80 joerg static void 1114 1.60 dsl output_strlst(FILE *outf, strlst_t *lst) 1115 1.1 cgd { 1116 1.60 dsl for (; lst != NULL; lst = lst->next) 1117 1.1 cgd fprintf(outf, " %s", lst->str); 1118 1.1 cgd fprintf(outf, "\n"); 1119 1.1 cgd } 1120 1.1 cgd 1121 1.1 cgd 1122 1.1 cgd /* 1123 1.1 cgd * ======================================================================== 1124 1.1 cgd * general library routines 1125 1.1 cgd * 1126 1.1 cgd */ 1127 1.1 cgd 1128 1.80 joerg static void 1129 1.75 lukem status(const char *str) 1130 1.1 cgd { 1131 1.1 cgd static int lastlen = 0; 1132 1.1 cgd int len, spaces; 1133 1.1 cgd 1134 1.60 dsl if (!verbose) 1135 1.60 dsl return; 1136 1.1 cgd 1137 1.1 cgd len = strlen(str); 1138 1.1 cgd spaces = lastlen - len; 1139 1.60 dsl if (spaces < 1) 1140 1.60 dsl spaces = 1; 1141 1.1 cgd 1142 1.1 cgd fprintf(stderr, " [%s]%*.*s\r", str, spaces, spaces, " "); 1143 1.1 cgd fflush(stderr); 1144 1.1 cgd lastlen = len; 1145 1.1 cgd } 1146 1.1 cgd 1147 1.1 cgd 1148 1.80 joerg static void 1149 1.60 dsl add_string(strlst_t **listp, char *str) 1150 1.1 cgd { 1151 1.1 cgd strlst_t *p1, *p2; 1152 1.1 cgd 1153 1.1 cgd /* add to end, but be smart about dups */ 1154 1.1 cgd 1155 1.60 dsl for (p1 = NULL, p2 = *listp; p2 != NULL; p1 = p2, p2 = p2->next) 1156 1.60 dsl if (!strcmp(p2->str, str)) 1157 1.60 dsl return; 1158 1.1 cgd 1159 1.94 christos p2 = emalloc(sizeof(*p2)); 1160 1.94 christos p2->str = estrdup(str); 1161 1.1 cgd 1162 1.1 cgd p2->next = NULL; 1163 1.60 dsl if (p1 == NULL) 1164 1.60 dsl *listp = p2; 1165 1.60 dsl else 1166 1.60 dsl p1->next = p2; 1167 1.1 cgd } 1168 1.1 cgd 1169 1.1 cgd 1170 1.80 joerg static int 1171 1.75 lukem is_dir(const char *pathname) 1172 1.1 cgd { 1173 1.1 cgd struct stat buf; 1174 1.1 cgd 1175 1.60 dsl if (stat(pathname, &buf) == -1) 1176 1.1 cgd return 0; 1177 1.1 cgd return S_ISDIR(buf.st_mode); 1178 1.1 cgd } 1179 1.1 cgd 1180 1.80 joerg static int 1181 1.75 lukem is_nonempty_file(const char *pathname) 1182 1.1 cgd { 1183 1.1 cgd struct stat buf; 1184 1.1 cgd 1185 1.60 dsl if (stat(pathname, &buf) == -1) 1186 1.1 cgd return 0; 1187 1.1 cgd 1188 1.1 cgd return S_ISREG(buf.st_mode) && buf.st_size > 0; 1189 1.1 cgd } 1190