/* Copyright (c) 1993 UNIX System Laboratories, Inc. */ /* All Rights Reserved */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */ /* UNIX System Laboratories, Inc. */ /* The copyright notice above does not evidence any */ /* actual or intended publication of such source code. */ /* Copyright (c) 1990, 1991, 1992, 1993 UNIX System Laboratories, Inc. */ /* Copyright (c) 1988, 1990 AT&T */ /* All Rights Reserved */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */ /* UNIX System Laboratories, Inc. */ /* The copyright notice above does not evidence any */ /* actual or intended publication of such source code. */ #ident "@(#)make:main.c 1.24.1.2" #include "defs" #include #include #include #include #include #include /* NAME ** make - maintain, update and regenerate groups of programs. ** ** OPTIONS for make ** '-f' The description file is the next argument; ** (makefile is the default) ** '-p' Print out a complete set of macro definitions and target ** descriptions ** '-i' Ignore error codes returned by invoked commands ** '-S' stop after any command fails (normally do parallel work) ** '-s' Silent mode. Do not print command lines before invoking ** '-n' No execute mode. Print commands, but do not execute them. ** '-t' Touch the target files but don't issue command ** '-g' Turn on auto $(GET) ** '-q' Question. Check if object is up-to-date; ** returns exit code 0 if up-to-date, -1 if not ** '-u' unconditional flag. Ignore timestamps. ** '-e' environment variable override locals ** '-r' ignore built in rules ** '-d' Debug. No-op unless compiled with -DMKDEBUG ** prints nice debug tracking messages ** '-D' Debug alot. ** '-w' Set off warning msgs. ** '-P' Set on parallel. ** '-B' Block the target's output. ** Additional SGI options: ** '-N' turn on NULL suffix allowing dependencies option ** '-M' turn off NULL suffix ... option ** '-O' turn off -b' ** '-b' turn on MH DEFAULT handling (default) */ #ifndef MAKE_SHELL #define MAKE_SHELL _PATH_BSHELL #endif static char makefile[] = "makefile", Makefile[] = "Makefile", Makeflags[] = "MAKEFLAGS", RELEASE[] = "RELEASE"; char Nullstr[] = "", funny[CHAR_LIST]; extern CHARSTAR builtin[]; CHARSTAR *linesptr = builtin; int parallel = PARALLEL ; /* The max. no. of parallel proc. that make will fork */ char tmp_block[30]; char * cur_makefile; char * cur_wd; /* Current working directory */ int nproc = 0 ; /* No. of process currently running */ int desc_start = NO; FILE *fin; struct nameblock pspace; NAMEBLOCK curpname = &pspace, mainname, firstname; LINEBLOCK sufflist; VARBLOCK firstvar; PATTERN firstpat ; OPENDIR firstod; void (*intstat) (), (*quitstat) (), (*hupstat) (), (*termstat) (); /* ** Declare local functions and make LINT happy. */ static int rddescf(); static int rdd1(); static void printdesc(); static void prname(); static void getmflgs(); static void setflags(); static int optswitch(); static void usage(); static void setmflgs(); static int chkmflgs(); static void setmmacs(); static int chkmmacs(); static void readenv(); static int eqsign(); static void callyacc(); void posix_env(); void convtmflgs(); static char temp_path[MAXPATHLEN]; /* max temp pathname */ int Mflags = MH_DEP; int okdel = YES; int k_error = 0; /* For -k option errors */ int mf_dashed = 0; /* If MAKEFLAGS is dashed format or not */ /* * Save command line args for a possible alternate make - * the arg parsing stuff trashes argv before we can determine * that we need to switch makes */ CHARSTAR *sargv; int sargc; static CHARSTAR Cmd; /* * OUTMAX really needs to scale with ARG_MAX - we use outmax instead. * Since quite a few routines (subst()) have no length checking * we give ourselves some extra - its still easy to coredump make by * having too long a command line, but at least we'll never core dump when * we could have executed the command successfully. */ long outmax; extern char yyfilename[]; extern int prereq(); main(argc, argv) int argc; CHARSTAR argv[]; { void intrupt(); register NAMEBLOCK p; register CHARSTAR s; register VARBLOCK v; register int i; time_t tjunk; char *getenv(), *sname(), *m_getcwd(), *vptr; void setvar(), enbint(), pwait(); int nfargs, chdir(), doname(), isdir(), descset = 0; char *args; (void)setlocale(LC_ALL, ""); (void)setcat("uxepu"); (void)setlabel("UX:make"); for (s = "#|=^();&<>*?[]:$`'\"\\\n" ; *s ; ++s) funny[(unsigned char)*s] |= META; /* make '$' a terminal so yylex can interpret */ for (s = "\n\t :=;{}&>|$" ; *s ; ++s) funny[(unsigned char)*s] |= TERMINAL; funny[(unsigned char)'\0'] |= TERMINAL; TURNON(INTRULE); /* Default internal rules, turned on */ init_lex(); builtin[1] = "MAKE=make"; /* * WARNING - this is only useful for error messages, etc - we * permit make to continue (and set this to ".") if the getcwd * fails. */ cur_wd = m_getcwd(); outmax = sysconf(_SC_ARG_MAX) + 8000; /* remember args since setflags trashes */ Cmd = argv[0]; sargv = malloc((argc+1-1) * sizeof(CHARSTAR)); for(i=1; ivarval.charstar = MAKE_SHELL; v->envflg = YES; v->noreset = NO; TURNON(EXPORT); /* Export $(MAKEFLAGS) macros */ getmflgs(); /* Init $(MAKEFLAGS) variable */ TURNOFF(EXPORT); setflags(argc, argv); /* Set command line flags */ setvar("$", "$"); /* Read command line "=" type args and make them readonly. */ TURNON(INARGS | EXPORT); #ifdef MKDEBUG if (IS_ON(DBUG)) printf("Reading \"=\" args on command line.\n"); #endif args = ck_malloc(outmax); strcpy(args,"MAKEARGS="); /* set to all command line macros */ /* set a yyfilename - eqsign calls yacc that may output an error */ strcpy(yyfilename, "Command line argruments"); for (i = 1; i < argc; ++i) if ( argv[i] && argv[i][0] != MINUS && eqsign(argv[i]) ) { strcat(args, " '"); strcat(args, argv[i]); strcat(args, "'"); setmmacs(argv[i]); /* POSIX Add to MAKEFLAGS */ argv[i] = 0; } callyacc(args); TURNOFF(INARGS | EXPORT); if (IS_ON(INTRULE)) { /* Read internal definitions and rules. */ #ifdef MKDEBUG if (IS_ON(DBUG)) printf("Reading internal rules.\n"); #endif strcpy(yyfilename, "Internal Rules"); (void)rdd1((FILE *) NULL); } TURNOFF(INTRULE); /* Done with internal rules, now. */ /* Read environment args. * Let file args which follow override, unless 'e' * in MAKEFLAGS variable is set. */ if (chkmflgs('e')) /* New POSIX format but backward compat */ TURNON(ENVOVER); #ifdef MKDEBUG if (IS_ON(DBUG)) printf("Reading environment.\n"); #endif TURNON(EXPORT); strcpy(yyfilename, "Environment variables"); readenv(); TURNOFF(EXPORT | ENVOVER); /* Get description file in the following order: ** - command line '-f' parameters ** - default names (makefile, Makefile, s.makefile, s.Makefile) */ desc_start = YES; for (i = 1; i < argc; i++) if ( argv[i] && (argv[i][0] == MINUS) && (argv[i][1] == 'f') && (argv[i][2] == CNULL)) { argv[i] = 0; if (i >= argc - 1 || argv[i+1] == 0) fatal(":117:no description file after -f flag (bu1)"); if ( rddescf(argv[++i], YES) ) fatal1(":118:cannot open %s", argv[i]); argv[i] = 0; ++descset; } if ( !descset ) { if ( rddescf(makefile, NO)) if ( rddescf(Makefile, NO) ) if ( rddescf(makefile, YES)) (void)rddescf(Makefile, YES); } /* Set the POSIX default for ARFLAGS */ if(IS_ON(POSIX) && !getenv("ARFLAGS") ) { setvar("ARFLAGS","-rv"); } if (IS_ON(PRTR)) printdesc(NO); if ( p = SRCHNAME(".IGNORE") ) { /* POSIX: Turn on globally only if no prerequisites */ if(IS_ON(POSIX)) { if(!prereq(p,(CHARSTAR) 0)) TURNON(IGNERR); } else TURNON(IGNERR); } if ( p = SRCHNAME(".SILENT") ) { /* POSIX: Turn on globally only if no prerequisites */ if(IS_ON(POSIX)) { if(!prereq(p,(CHARSTAR) 0)) TURNON(SIL); } else TURNON(SIL); } /* * Permit flags to be turned on from within a Makefile * We don't use .MAKEFLAGS since smake already uses that */ if (p = SRCHNAME(".MAKEOPTS")) { DEPBLOCK d; LINEBLOCK lp; for (lp = p->linep; lp; lp = lp->nextline) { for (d = lp->depp; d; d = d->nextdep) if (d->depname->namep[0] == '-') optswitch(d->depname->namep[1]); } } /* perform sanity checking for parallel (after MAKEOPTS) */ if(IS_ON(PAR) && IS_ON(NOEX)) TURNOFF(PAR); if (IS_ON(PAR)) { if(IS_ON(BLOCK)) sprintf(tmp_block,"/var/tmp/make%d", getpid()); if ((vptr = getenv("PARALLEL")) && !(STREQ(vptr, ""))) if((parallel = atoi(vptr)) <= 0 ) parallel = 1; } else TURNOFF(BLOCK); if (p = SRCHNAME(".SUFFIXES")) sufflist = p->linep; intstat = (void(*)()) signal(SIGINT, SIG_IGN); quitstat = (void(*)()) signal(SIGQUIT, SIG_IGN); hupstat = (void(*)()) signal(SIGHUP, SIG_IGN); termstat = (void(*)()) signal(SIGTERM, SIG_IGN); enbint(intrupt); nfargs = 0; for (i = 1; i < argc; ++i) if ( s = argv[i] ) { if ( !(p = SRCHNAME(s)) ) p = makename(s); ++nfargs; (void)doname(p, 0, &tjunk ); if(IS_ON(PAR)){ #ifdef MKDEBUG if (IS_ON(DBUG)) printdesc(YES); #endif pwait(0); } #ifdef MKDEBUG if (IS_ON(DBUG)) printdesc(YES); #endif } /* * If no file arguments have been encountered, make the first * name encountered that doesn't start with a dot */ if ( !nfargs ) if ( !mainname ) fatal(":119:no arguments or description file (bu7)"); else { (void)doname(mainname, 0, &tjunk); if(IS_ON(PAR)){ #ifdef MKDEBUG if (IS_ON(DBUG)) printdesc(YES); #endif pwait(0); } #ifdef MKDEBUG if (IS_ON(DBUG)) printdesc(YES); #endif } mkexit(0); /* make succeeded; no fatal errors */ /*NOTREACHED*/ } void intrupt() { time_t exists(); int isprecious(), member_ar(), unlink(); void mkexit(); int lev, ret_isdir; CHARSTAR p; NAMEBLOCK lookup_name(); /* * wait for all children to finish so they can get any * errors out */ while (wait(NULL) != -1 && errno != ECHILD) ; if (okdel && IS_OFF(NOEX) && IS_OFF(TOUCH) && (p = (varptr("@")->varval.charstar)) && (exists( lookup_name(p), &lev) != -1) && (!isprecious(p)) && (!member_ar(p))) /* don't remove archives generated during make */ { if ((ret_isdir = isdir(p)) == 1) pfmt(stderr, MM_NOSTD, ":102:\n*** %s NOT removed.\n", p); else if ( !( ( ret_isdir == 2 ) || unlink(p) ) ) pfmt(stderr, MM_NOSTD, ":103:\n*** %s removed.\n", p); } fprintf(stderr, "\n"); mkexit(2); /*NOTREACHED*/ } void enbint(onintr) void (*onintr)(); { if (intstat == (void(*)())SIG_DFL) (void)sigset(SIGINT, onintr); if (quitstat == (void(*)())SIG_DFL) (void)sigset(SIGQUIT, onintr); if (hupstat == (void(*)())SIG_DFL) (void)sigset(SIGHUP, onintr); if (termstat == (void(*)())SIG_DFL) (void)sigset(SIGTERM, onintr); } static int rddescf(descfile, sflg) /* read and parse description file */ CHARSTAR descfile; int sflg; /* if YES try s.descfile */ { void setvar(); FILE *k; setvar("MAKEFILE", descfile); strcpy(yyfilename, descfile); if (STREQ(descfile, "-")) { cur_makefile = descfile; return( rdd1(stdin) ); } retry: strcpy(yyfilename, descfile); if (k = fopen(descfile, "r")) { #ifdef MKDEBUG if (IS_ON(DBUG)) printf("Reading %s\n", descfile); #endif cur_makefile = descfile; return( rdd1(k) ); } if ( !sflg || !get(descfile, varptr(RELEASE)->varval.charstar,0) ) return(1); sflg = NO; goto retry; } /** used by yyparse **/ extern int yylineno; extern CHARSTAR zznextc; static int rdd1(k) FILE *k; { int yyparse(); void fatal(); fin = k; yylineno = 0; zznextc = 0; if ( yyparse() ) fatal(":120:description file error (bu9)"); if ( ! (fin == NULL || fin == stdin) ) (void)fclose(fin); return(0); } static void printdesc(prntflag) int prntflag; { register NAMEBLOCK p; register VARBLOCK vp; register CHAIN pch; FILE *op; if (prntflag) op = stderr; else op = stdout; fflush(stdout); fflush(stderr); if (prntflag) { register OPENDIR od; pfmt(op, MM_NOSTD, ":104:Open directories:\n"); for (od = firstod; od; od = od->nextopendir) fprintf(op, "\t%s\n", od->dirn); } if (firstvar) pfmt(op, MM_NOSTD, ":105:Macros:\n"); for (vp = firstvar; vp; vp = vp->nextvar) if ( !(vp->v_aflg) ) fprintf(op, "%s = %s\n", vp->varname, ((vp->varval.charstar) == NULL? " ":vp->varval.charstar)); else { pfmt(op, MM_NOSTD, ":106:Lookup chain: %s\n\t", vp->varname); for (pch = (vp->varval.chain); pch; pch = pch->nextchain) fprintf(op, " %s", (pch->datap.nameblock)->namep); fprintf(op, "\n"); } for (p = firstname; p; p = p->nextname) prname(p, prntflag); fprintf(op, "\n"); (void)fflush(op); } #include "termio.h" static void prname(p, prntflag) register NAMEBLOCK p; { register DEPBLOCK dp; register SHBLOCK sp; register LINEBLOCK lp; FILE *op; static int cols = -1; register int deplen; if (prntflag) op = stderr; else op = stdout; if (cols < 0) { /* determine # columns on screen */ struct winsize w; if (ioctl(fileno(op), TIOCGWINSZ, &w) < 0) cols = 80; else cols = w.ws_col; } fprintf(op, "\nTARGET:%s:", p->namep); if (prntflag) fprintf(op, " done=%d", p->done); if (p == mainname) pfmt(op, MM_NOSTD, ":107:(MAIN NAME)"); for (lp = p->linep; lp; lp = lp->nextline) { if ( dp = lp->depp ) { pfmt(op, MM_NOSTD, ":108:\n depends on:"); for (; dp; dp = dp->nextdep) if ( dp->depname) { register ilen; ilen = strlen(dp->depname->namep) + 1; if (ilen + deplen >= cols) { deplen = 12; fprintf(op, "\n\t "); } deplen += ilen; fprintf(op, "%s ", dp->depname->namep); } } if (sp = lp->shp) { fprintf(op, "\n"); pfmt(op, MM_NOSTD, ":109:commands:\n"); for ( ; sp; sp = sp->nextsh) fprintf(op, "\t%s\n", sp->shbp); } } } /* * POSIX: $(MAKEFLAGS) now contains options and command line and user * defined macros. * Options can be "abcd" or "-a -b -c -d" * Macros are white space seperated with no spaces around '=' char. */ static void getmflgs() /* export command line flags for future invocation */ { void setvar(); int sindex(); register CHARSTAR m, args, mf, eq; register VARBLOCK vpr = varptr(Makeflags); args = ck_malloc(outmax); setvar(Makeflags, args); vpr->varval.charstar[0] = CNULL; vpr->envflg = YES; vpr->noreset = YES; /*optswitch('b');*/ if(!(mf = getenv("MAKEFLAGS"))) return; m = mf; while(m=strchr(m,'=')){ if(isspace(*(m-1))) { printf("Environment MAKEFLAGS: No white space before '=' char"); mkexit(1); } ++m; } while(*mf) { char *mac; int len; switch(*mf) { case '-': /* Handle single letter dashed option */ ++mf_dashed; ++mf; optswitch(*mf); if(*mf == 'f') { /* Skip past possible f option arg */ while(isspace(*mf))++mf; while(*mf && !isspace(*mf)) ++mf; } else ++mf; break; case ' ': case '\t': ++mf; break; case '\'': case '\"': ++mf; /* Skip user imbedded chars */ break; default: /* Handle undashed options or macros */ m=mf; if(!strchr(mf,'=')) { /* No macros - just options */ optswitch(*mf++); break; } eq = strchr(mf,'='); while(*m && !isspace(*m))++m; /* Past starting chars */ if(m < eq) { optswitch(*mf++); /* Options */ break; } /* Macros */ m=mf; while(*m && !isspace(*m)) ++m; mac = ck_malloc(m-mf+1); strncpy(mac,mf,m-mf); mac[m-mf] = CNULL; callyacc(mac); setmmacs(mac); free(mac); mf = m; break; } } } static void setflags(ac, av) register int ac; CHARSTAR *av; { register int i, j; register char c; int flflg = 0; /* flag to note '-f' option. */ for (i = 1; i < ac; ++i) { if (flflg ) { flflg = 0; continue; } if (av[i] && av[i][0] == MINUS) { if (ANY(av[i], 'f')) flflg++; for (j = 1 ; (c = av[i][j]) != CNULL ; ++j) if(optswitch(c)) break; if (flflg) av[i] = "-f"; else av[i] = 0; } } } static int optswitch(c) /* Handle a single character option */ char c; { switch (c) { case 's': /* silent flag */ TURNON(SIL); setmflgs(c); return(0); case 'n': /* do not exec any commands, just print */ TURNON(NOEX); setmflgs(c); return(0); case 'e': /* environment override flag */ setmflgs(c); return(0); case 'p': /* print description */ TURNON(PRTR); return(0); case 'i': /* ignore errors */ TURNON(IGNERR); setmflgs(c); return(0); case 'S': TURNOFF(KEEPGO); setmflgs(c); return(0); case 'k': TURNON(KEEPGO); setmflgs(c); return(0); case 'r': /* turn off internal rules */ TURNOFF(INTRULE); return(0); case 't': /* touch flag */ TURNON(TOUCH); setmflgs(c); return(0); case 'q': /* question flag */ TURNON(QUEST); setmflgs(c); return(0); case 'g': /* turn default $(GET) of files not found */ TURNON(GET); setmflgs(c); return(0); case 'b': /* use MH version of test for whether cmd exists */ TURNON(MH_DEP); setmflgs(c); return(0); /* turn off -b flag */ case 'O': TURNOFF(MH_DEP); setmflgs(c); return(0); case 'd': /* debug flag */ case 'D': #ifdef MKDEBUG if (c == 'd') TURNON(DBUG2); else TURNON(DBUG); setmflgs(c); setlinebuf(stdout); setlinebuf(stderr); #endif return(0); case 'm': /* print memory map is not supported any more */ return(0); case 'f': /* named makefile: handled by setflags() */ return(0); case 'u': /* unconditional build indicator */ TURNON(UCBLD); setmflgs(c); return(0); case 'w': /* Set off warning msgs */ TURNON(WARN); setmflgs(c); return(0); case 'P': /* Set on parallel */ TURNON(PAR); setmflgs(c); return(0); case 'B': /* Set on target's output blocking */ TURNON(BLOCK); setmflgs(c); return(0); case 'M': /* deny explicit null suffix dependencies */ TURNOFF(NULLSFX); setmflgs(c); return(0); case 'N': /* permit explicit null suffix dependencies */ TURNON(NULLSFX); setmflgs(c); return(0); case '-': return(1); } usage(c); /* NOTREACHED */ } static void usage(c) char c; { pfmt(stderr, MM_ACTION, _SGI_MMX_make_usage ":Usage: make [-f makefile] [-p] [-i] [-k] [-s] [-r] [-n] [-u]\n\t"); #ifdef MKDEBUG fprintf(stderr, "[-d] [-D] "); #endif fprintf(stderr, "[-S] [-g] [-w] [-P] [-B] [-b] [-O] [-e] [-t] [-q] [-M] [-N] [names]\n"); mkexit(1); } /* Called from parser to reconvert MAKEFLAGS variable back to original * format, that is, without macros and single letter dashed options. */ void convtmflgs() { register CHARSTAR m = (varptr(Makeflags))->varval.charstar; register CHARSTAR s, args; void setvar(); int off = 0; if(s = strchr(m,'=')){ /* Macros */ /* Search backwards for start of macro */ --s; while(s > m && !isspace(*s)) --s; *s = CNULL; } args = ck_malloc(29); /* Old style was 29 'Z' letters */ args[off] = CNULL; s = m; while(*s) { if(*s != '-' && !isspace(*s)) args[off++] = *s; ++s; } args[off] = CNULL; free(m); (varptr(Makeflags))->noreset = NO; setvar(Makeflags, args); (varptr(Makeflags))->noreset = YES; } /* Called from parser to establish POSIX environment */ void posix_env() { VARBLOCK srchvar(); void setvar(); register VARBLOCK mp,sp; if(mp = srchvar("MAKEFLAGS_POSIX")){ strcpy((srchvar(Makeflags))->varval.charstar,mp->varval.charstar); free(mp->varval.charstar); mp->varval.charstar = ""; } if(sp = srchvar("SHELL_POSIX")){ strcpy((srchvar("SHELL"))->varval.charstar,sp->varval.charstar); free(sp->varval.charstar); sp->varval.charstar = ""; } (srchvar(Makeflags))->noreset = NO; } /* * POSIX: Called from readenv() to prevent overwriting the MAKEFLAGS and SHELL * variables and to prevent overwriting any macros included in the MAKEFLAGS variable. * We only know if we are in a POSIX environment after the makefile is parsed. * Save the "MAKEFLAGS" and "SHELL" variables and restore from the parser when * we know we are POSIX. See posix_env(). */ static int chkmmacs(mac) register char *mac; { register CHARSTAR m = (varptr(Makeflags))->varval.charstar; register CHARSTAR s = (varptr("SHELL"))->varval.charstar; register CHARSTAR a,l,mp,sp; register int mlen; void setvar(); /* Insure new invocations do not inherit these flags */ if(strncmp(mac,"MAKEFLAGS_POSIX=",16)==0 || strncmp(mac,"SHELL_POSIX=",12)==0) return(0); if(strncmp(mac,"MAKEFLAGS=",10)==0) { mp = ck_malloc(outmax); strcpy(mp,m); setvar("MAKEFLAGS_POSIX",mp); /* Save and allow to be overwritten */ return(1); } if(strncmp(mac,"SHELL=",6)==0 ) { sp = ck_malloc(strlen(s)+1); strcpy(sp,s); setvar("SHELL_POSIX",sp); /* Save and allow to be overwritten */ return(0); } a = m; mlen = (strchr(mac,'=') - mac); while(a = strchr(a,'=')) { l = a; while(!isspace(*a) && a > m)--a; /* Beginning of macro */ if(isspace(*a)) ++a; if(strncmp(a,mac,mlen)==0) return(0); a = l+1; } return(1); } static void setmmacs(mac) /* POSIX: Add macro to $(MAKEFLAGS) */ register char *mac; { register CHARSTAR p = (varptr(Makeflags))->varval.charstar; register CHARSTAR s; register int mlen = 0; s = mac; while(*s) { if(!isspace(*s)) ++mlen; ++s; } if((mlen + strlen(p) + 2) > outmax) { fatal(":169:MAKEFLAGS buffer overrun"); } s = p + strlen(p); if(s != p) *s++ = ' '; while(*mac){ if(!isspace(*mac)) /* Trim out spaces */ *s++ = *mac; ++mac; } *s = CNULL; } static int chkmflgs(c) /* Check $(MAKEFLAGS) for option */ register char c; { register CHARSTAR p = (varptr(Makeflags))->varval.charstar; register CHARSTAR mac,o; if(mac = strchr(p,'=')) while(!isspace(*mac) && mac > p)--mac; if((!mac && *p) || (mac && mac > p)) { /* We have options */ if(*p == '-') { for(o=p;o = strchr(o,'-');) if(c == *++o) return(1); /* Duplicate */ return(0); } else { for (; *p && !isspace(*p); p++) if (*p == c) return(1); /* Duplicate */ return(0); } } return(0); } /* Add the option to $(MAKEFLAGS) */ static void setmflgs(c) /* set up the cmd line input flags for EXPORT. */ register char c; { register CHARSTAR p = (varptr(Makeflags))->varval.charstar; register int mlen = strlen(p); register CHARSTAR mac, sv, o; if((mlen+(mf_dashed?3:1)) > outmax) { /* Overrun */ fatal(":169:MAKEFLAGS buffer overrun"); } /* If macros exist, save and append them after option insertion */ if(mac = strchr(p,'=')) { while(!isspace(*mac) && mac > p)--mac; if(isspace(*mac)) { *mac = CNULL; ++mac; sv = ck_malloc(strlen(mac)+1); strcpy(sv,mac); } else { sv = ck_malloc(strlen(mac)+1); strcpy(sv,mac); *p = CNULL; } } if(*p) { /* Existing options */ char opt[4]; if(*p == '-') { for(o=p;o = strchr(o,'-');) if(c == *++o) return; /* Duplicate */ sprintf(opt," -%c",c); /* Append */ strcat(p,opt); } else { for (; *p && !isspace(*p); p++) if (*p == c) return; /* Duplicate */ sprintf(opt,"%c",c); /* Append */ strcat(p,opt); } } else { /* No options */ if(mf_dashed) { *p++ = '-'; *p++ = c; *p = CNULL; } else { *p++ = c; *p = CNULL; } } if(mac) { strcat(p," "); strcat(p,sv); free(sv); } } /* * If a string like "CC=" occurs then CC is not put in environment. * This is because there is no good way to remove a variable * from the environment within the shell. * Note: POSIX wants these empty variables, so in setenv(), don't * export them if in non-POSIX environment. */ static void readenv() { register CHARSTAR *ea, p; ea = environ; for (; *ea; ea++) { for (p = *ea; *p && *p != EQUALS; p++) ; /* if ((*p == EQUALS) && *(p + 1)) */ if (*p == EQUALS) { /* POSIX */ if(chkmmacs(*ea)) /* POSIX Don't overwrite certain var or macros */ (void)eqsign(*ea); } } } static int eqsign(a) register CHARSTAR a; { register CHARSTAR p; /* allow most anything in a macro name - this begins to help * porting from VMS etc where file names have strange chars */ for (p = "="; *p; p++) if (ANY(a, *p)) { callyacc(a); return(YES); } return(NO); } static void callyacc(str) register CHARSTAR str; { CHARSTAR lines[2]; FILE *finsave = fin; CHARSTAR *lpsave = linesptr; char fnsave[PATH_MAX]; strcpy(fnsave, yyfilename); fin = 0; lines[0] = str; lines[1] = 0; linesptr = lines; (void)yyparse(); fin = finsave; linesptr = lpsave; strcpy(yyfilename, fnsave); } NAMEBLOCK lookup_name(namep) CHARSTAR namep; { NAMEBLOCK p; for (p = firstname; p; p = p->nextname) { if (STREQ(namep, p->namep)) return (p); } return ( NULL ); } char * m_getcwd() { char *getcwd(); char *p; /* * SGI - this is ONLY used for printing error messages in * parallel mode - but some customers like to run make in * an area they can't do a pwd in :-) so we make this optional */ if(getcwd(temp_path, MAXPATHLEN) == NULL) strcpy(temp_path, "."); p = ck_malloc(strlen(temp_path) + 1); strcpy(p, temp_path); return(p); } #include "sys/stat.h" CHARSTAR findfl(CHARSTAR, CHARSTAR); CHARSTAR execat(CHARSTAR, CHARSTAR, CHARSTAR); static char *sstr(char *); /* * donmake - handle #! on 1st line of makefile */ void donmake(line) char *line; { int len; char *from = line; char buf[128]; char *ncmd, *nCmd; char **nargs; char **nnargs, **pnnargs; int i, ncargs; int havefflag = 0; int fflgloc; struct stat sc, sn; /* grab additional options on #! line */ nargs = malloc(sizeof(char *)); nargs[0] = NULL; ncargs = 0; for(; len=getword(from,buf); from += len) { if (buf[0] == TAB || buf[0] == BLANK) continue; /* * If a makefile is suitable to be run as a shell * script it may have a line like: * #!/bin/make -kf * where exec will add the name of the makefile AFTER * the f... this is incompatible from the way we do * things. * Also, it would be nice if it were possible that * in makes #! line one could specify an alternate * makefile: * #!smake -f smakefile * * So: if we find a lone f option - we squash it * if we find an f option with an argument - we squash * any command line f options */ if (buf[0] == '-' && ANY(&buf[1], 'f')) { havefflag = 1; fflgloc = ncargs; } else if (havefflag == 1) { /* have a -f flag and now an argument - set * flag so that we squash any original -f arg */ havefflag = 2; } nargs = realloc(nargs, (ncargs+1)*sizeof(char *)); nargs[ncargs++] = sstr(buf); } /* if we had a lone -f option then havefflag will be 1 - * we need to go back and erase it */ if (havefflag == 1) { char *floc; if (nargs[fflgloc][1] == 'f') { /* lone flag */ nargs[fflgloc] = NULL; } else { floc = strchr(nargs[fflgloc], 'f'); *floc = '\0'; } } /* now have all args */ if (nargs[0] == NULL || ((ncmd = findfl(nargs[0], "PATH")) == (CHARSTAR) -1) || (stat(ncmd, &sn) != 0)) { /* if fail - just proceed */ free(nargs); if(IS_ON(DBUG) || IS_ON(DBUG2)) pfmt(stdout, MM_NOSTD, _SGI_MMX_make_noaltmake ":Cannot find alternate make:%s\n", nargs[0]); return; } ncmd = sstr(ncmd); /* findfl overwrites */ nCmd = Cmd; if (*Cmd == '/' || (nCmd = findfl(Cmd, "PATH")) != (CHARSTAR) -1) { /* do a stab at making sure we don't exec ourselves */ if (stat(nCmd, &sc) == 0 && stat(ncmd, &sn) == 0) { if (sc.st_dev == sn.st_dev && sc.st_ino == sn.st_ino) { if(IS_ON(DBUG)) pfmt(stdout, MM_NOSTD, _SGI_MMX_make_ignaltmake ":Ignoring alternate make; its me!:%s\n", ncmd); return; } } } /* now insert all #! args before command line args */ nnargs = malloc((ncargs+sargc+1) * sizeof (char*)); pnnargs = nnargs; for (i = 0; i < ncargs; i++) if (nargs[i]) *pnnargs++ = nargs[i]; for (i = 0; i < sargc; i++) { if (havefflag == 2 && sargv[i][0] == '-' && ANY(&sargv[i][1], 'f')) { /* remove -f and next arg * note that 'f' MUST be last */ if (sargv[i][1] == 'f') /* skip sargv[i] & sargv[i+1] */ i++; else { char *floc; /* remove f and sargv[i+1] */ *pnnargs = sstr(sargv[i]); floc = strchr(*pnnargs, 'f'); *floc = '\0'; pnnargs++; i++; } continue; } *pnnargs++ = sargv[i]; } *pnnargs = NULL; if (IS_ON(DBUG) || IS_ON(DBUG2)) { pfmt(stdout, MM_NOSTD, _SGI_MMX_make_swaltmake ":Switching to alternate make:%s\nargs:", ncmd); for (pnnargs = nnargs; *pnnargs; pnnargs++) printf("%s ", *pnnargs); printf("\n"); } execv(ncmd, nnargs); /* if fail - just proceed */ free(nnargs); free(nargs); } static char * sstr(s) char *s; { char *r; r = ck_malloc(strlen(s) + 1); strcpy(r, s); return(r); } /* * findfl(name) (like execvp, but does path search and finds files) */ static char fname[PATH_MAX]; CHARSTAR findfl(name, varnm) register CHARSTAR name; CHARSTAR varnm; /* variable containing path information */ { register CHARSTAR p; register VARBLOCK cp; char tempbuf[PATH_MAX]; char *tempval = tempbuf; size_t len; if(name[0] == SLASH) return(name); cp = varptr(varnm); if(*cp->varval.charstar == 0) p = ":"; else p = cp->varval.charstar; /* Since subst() doesn't take into account the length of the * variable, if input path is greater than PATH_MAX then * fail-over to dynamic allocation. */ if ((len = strlen(p)) >= PATH_MAX) { tempval = ck_malloc(len + 1); } subst(p, tempval, 0); p = tempval; do { p = execat(p, name, fname); if(access(fname, 4) == 0) { if (tempval != tempbuf) free(tempval); return(fname); } } while (p); if (tempval != tempbuf) free(tempval); return((CHARSTAR )-1); } CHARSTAR execat(s1, s2, si) register CHARSTAR s1, s2; CHARSTAR si; { register CHARSTAR s; s = si; while (*s1 && *s1 != KOLON) *s++ = *s1++; if (si != s) *s++ = SLASH; while (*s2) *s++ = *s2++; *s = CNULL; return(*s1? ++s1: 0); }