version upgraded; added JAM_TARGET and fixed JAMCMDARGS vars
[k8jam.git] / jam.c
blob9768efb7fe9139618bfd2eb66bcabed691baa0ad
1 /*
2 * /+\
3 * +\ Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
4 * \+/
6 * This file is part of jam.
8 * License is hereby granted to use this software and distribute it
9 * freely, as long as this copyright notice is retained and modifications
10 * are clearly marked.
12 * ALL WARRANTIES ARE HEREBY DISCLAIMED.
16 * jam.c - make redux
18 * See Jam.html for usage information.
20 * These comments document the code.
22 * The top half of the code is structured such:
24 * jam
25 * / | \
26 * +---+ | \
27 * / | \
28 * jamgram option \
29 * / | \ \
30 * / | \ \
31 * / | \ |
32 * scan | compile make
33 * | | / | \ / | \
34 * | | / | \ / | \
35 * | | / | \ / | \
36 * jambase parse | rules search make1
37 * | | | \
38 * | | | \
39 * | | | \
40 * builtins timestamp command execute
41 * |
42 * |
43 * |
44 * filesys
47 * The support routines are called by all of the above, but themselves
48 * are layered thus:
50 * variable|expand
51 * / | | |
52 * / | | |
53 * / | | |
54 * lists | | pathsys
55 * \ | |
56 * \ | |
57 * \ | |
58 * newstr |
59 * \ |
60 * \ |
61 * \ |
62 * hash
64 * Roughly, the modules are:
66 * builtins.c - jam's built-in rules
67 * command.c - maintain lists of commands
68 * compile.c - compile parsed jam statements
69 * execunix.c - execute a shell script on UNIX
70 * execvms.c - execute a shell script, ala VMS
71 * expand.c - expand a buffer, given variable values
72 * file*.c - scan directories and archives on *
73 * hash.c - simple in-memory hashing routines
74 * headers.c - handle #includes in source files
75 * jambase.c - compilable copy of Jambase
76 * jamgram.y - jam grammar
77 * lists.c - maintain lists of strings
78 * make.c - bring a target up to date, once rules are in place
79 * make1.c - execute command to bring targets up to date
80 * newstr.c - string manipulation routines
81 * option.c - command line option processing
82 * parse.c - make and destroy parse trees as driven by the parser
83 * path*.c - manipulate file names on *
84 * hash.c - simple in-memory hashing routines
85 * regexp.c - Henry Spencer's regexp
86 * rules.c - access to RULEs, TARGETs, and ACTIONs
87 * scan.c - the jam yacc scanner
88 * search.c - find a target along $(SEARCH) or $(LOCATE)
89 * timestamp.c - get the timestamp of a file or archive member
90 * variable.c - handle jam multi-element variables
92 * 05/04/94 (seiwald) - async multiprocess (-j) support
93 * 02/08/95 (seiwald) - -n implies -d2.
94 * 02/22/95 (seiwald) - -v for version info.
95 * 09/11/00 (seiwald) - PATCHLEVEL folded into VERSION.
96 * 01/10/01 (seiwald) - pathsys.h split from filesys.h
97 * 01/21/02 (seiwald) - new -q to quit quickly on build failure
98 * 03/16/02 (seiwald) - support for -g (reorder builds by source time)
99 * 09/19/02 (seiwald) - new -d displays
100 * 10/22/02 (seiwald) - list_new() now does its own newstr()/copystr()
101 * 11/04/02 (seiwald) - const-ing for string literals
104 # include "jam.h"
105 # include "option.h"
106 # include "patchlevel.h"
108 /* These get various function declarations. */
110 # include "lists.h"
111 # include "parse.h"
112 # include "variable.h"
113 # include "compile.h"
114 # include "builtins.h"
115 # include "rules.h"
116 # include "newstr.h"
117 # include "scan.h"
118 # include "timestamp.h"
119 # include "make.h"
121 /* Macintosh is "special" */
123 # ifdef OS_MAC
124 # include <QuickDraw.h>
125 # endif
127 /* And UNIX for this */
129 # ifdef unix
130 # include <sys/utsname.h>
131 # endif
134 struct globs globs = {
135 0, /* noexec */
136 1, /* jobs */
137 0, /* quitquick */
138 0, /* newestfirst */
139 # ifdef OS_MAC
140 { 0 }, /* display - suppress actions output */
141 # else
142 { 0, 1 }, /* display actions */
143 # endif
144 0 /* output commands, not run them */
148 /* Symbols to be defined as true for use in Jambase */
149 static const char *othersyms[] = { OSMAJOR, OSMINOR, OSPLAT, JAMVERSYM, 0 } ;
152 /* Known for sure:
153 * mac needs arg_enviro
154 * OS2 needs extern environ
156 # ifdef OS_MAC
157 # define use_environ arg_environ
158 # ifdef MPW
159 QDGlobals qd;
160 # endif
161 # endif
163 # ifndef use_environ
164 # define use_environ environ
165 # if !defined( __WATCOM__ ) && !defined( OS_OS2 ) && !defined( OS_NT )
166 extern char **environ;
167 # endif
168 # endif
171 int main (int argc, char **argv, char **arg_environ) {
172 int n, num_targets;
173 const char *s;
174 struct option optv[N_OPTS];
175 char *targets[N_TARGETS];
176 const char *all = "all";
177 int anyhow = 0;
178 int status;
180 #ifdef OS_MAC
181 InitGraf(&qd.thePort);
182 #endif
184 argc--, argv++;
185 if ((num_targets = getoptions(argc, argv, "d:j:f:gs:t:ano:qv", optv, targets)) < 0) {
186 printf("\nusage: jam [ options ] targets...\n\n"
187 "-a Build all targets, even if they are current.\n"
188 "-dx Display (a)actions (c)causes (d)dependencies\n"
189 " (m)make tree (x)commands (0-9) debug levels.\n"
190 "-fx Read x instead of Jambase.\n"
191 "-g Build from newest sources first.\n"
192 "-jx Run up to x shell commands concurrently.\n"
193 "-n Don't actually execute the updating actions.\n"
194 "-ox Write the updating actions to file x.\n"
195 "-q Quit quickly as soon as a target fails.\n"
196 "-sx=y Set variable x=y, overriding environment.\n"
197 "-tx Rebuild x, even if it is up-to-date.\n"
198 "-v Print the version of jam and exit.\n\n"
200 exit(EXITBAD);
203 /* Version info. */
204 if ((s = getoptval(optv, 'v', 0))) {
205 printf( "K8-Jam %s. %s. ", VERSION, OSMINOR );
206 printf( "(C) 1993-2003 Christopher Seiwald, see www.freetype.org/jam/\n" );
207 printf( "changes by Ketmar, psyc://ketmar.no-ip.org/~ketmar\n" );
208 return EXITOK;
211 /* Pick up interesting options */
212 if ((s = getoptval(optv, 'n', 0))) globs.noexec++, DEBUG_MAKE = DEBUG_MAKEQ = DEBUG_EXEC = 1;
213 if ((s = getoptval(optv, 'q', 0))) globs.quitquick = 1;
214 if ((s = getoptval(optv, 'a', 0))) anyhow++;
215 if ((s = getoptval(optv, 'j', 0))) globs.jobs = atoi(s);
216 if ((s = getoptval(optv, 'g', 0))) globs.newestfirst = 1;
218 /* Turn on/off debugging */
219 for (n = 0; (s = getoptval(optv, 'd', n)) != 0; n++) {
220 int i = atoi(s);
221 /* First -d, turn off defaults. */
222 if (!n) DEBUG_MAKE = DEBUG_MAKEQ = DEBUG_EXEC = 0;
223 /* n turns on levels 1-n */
224 /* +n turns on level n */
225 /* c turns on named display c */
226 if (i < 0 || i >= DEBUG_MAX) {
227 printf( "Invalid debug level '%s'.\n", s );
228 } else if (*s == '+') {
229 globs.debug[i] = 1;
230 } else if (i) {
231 while (i) globs.debug[i--] = 1;
232 } else {
233 while (*s) {
234 switch (*s++) {
235 case 'a': DEBUG_MAKE = DEBUG_MAKEQ = 1; break;
236 case 'c': DEBUG_CAUSES = 1; break;
237 case 'd': DEBUG_DEPENDS = 1; break;
238 case 'm': DEBUG_MAKEPROG = 1; break;
239 case 'x': DEBUG_EXEC = 1; break;
240 case '0': break;
241 default: printf("Invalid debug flag '%c'.\n", s[-1]);
247 /* Set JAMDATE first */
249 char buf[128], *p;
250 time_t clock;
252 time(&clock);
253 strcpy(buf, ctime(&clock));
254 /* Trim newline from date */
255 /*if (strlen(buf) == 25) buf[24] = 0;*/
256 p = buf+strlen(buf);
257 while (p >= buf && *((unsigned char *)p) <= ' ') p--;
258 *(++p) = '\0';
259 var_set("JAMDATE", list_new(L0, buf, 0), VAR_SET);
262 /* And JAMUNAME */
263 # ifdef unix
265 struct utsname u;
267 if (uname(&u) >= 0) {
268 LIST *l = L0;
269 l = list_new(l, u.machine, 0);
270 l = list_new(l, u.version, 0);
271 l = list_new(l, u.release, 0);
272 l = list_new(l, u.nodename, 0);
273 l = list_new(l, u.sysname, 0);
274 var_set("JAMUNAME", l, VAR_SET);
277 # endif /* unix */
280 * Jam defined variables OS, OSPLAT
282 var_defines(othersyms);
283 /* load up environment variables */
284 var_defines((const char **)use_environ);
286 /* Load up variables set on command line. */
287 for (n = 0; (s = getoptval(optv, 's', n)) != 0; n++) {
288 const char *symv[2];
289 symv[0] = s;
290 symv[1] = 0;
291 var_defines(symv);
294 /* Add JAMCMDARGS */
296 LIST *l0 = L0, *l1 = L0;
298 if (num_targets < 1) {
299 l0 = list_new(l0, "all", 0);
300 l1 = list_new(l1, "all", 0);
301 } else {
302 for (n = 0; n < num_targets; n++) {
303 /*printf("target %i: %s\n", n, targets[n]);*/
304 l0 = list_new(l0, targets[n], 0);
305 l1 = list_new(l1, targets[n], 0);
308 var_set("JAMCMDARGS", l0, VAR_SET);
309 var_set("JAM_TARGETS", l1, VAR_SET); /* k8 */
312 /* Initialize built-in rules */
313 load_builtins();
315 /* Parse ruleset */
316 for (n = 0; (s = getoptval(optv, 'f', n)) != 0; n++) parse_file(s);
317 if (!n) parse_file("+");
319 status = yyanyerrors();
321 /* Manually touch -t targets */
322 for (n = 0; (s = getoptval(optv, 't', n)) != 0; n++) touchtarget(s);
324 /* If an output file is specified, set globs.cmdout to that */
325 if ((s = getoptval(optv, 'o', 0)) != 0) {
326 if (!(globs.cmdout = fopen(s, "w"))) {
327 printf("Failed to write to '%s'\n", s);
328 exit(EXITBAD);
330 globs.noexec++;
333 #ifndef NO_OPT_JAM_TARGETS_VARIABLE_EXT
334 /* ported from Haiku */
335 /* get value of variable JAM_TARGETS and build the targets */
337 LIST *l = var_get("JAM_TARGETS");
338 int targetCount = list_length(l);
339 int i;
341 if (targetCount == 0) {
342 /* No targets. Nothing to do. */
343 printf("No targets. Nothing to do.\n");
344 exit(EXITOK);
347 if (targetCount >= N_TARGETS) {
348 printf("ERROR: Too many targets!\n");
349 exit(EXITBAD);
352 for (i = 0; i < targetCount; i++) {
353 const char *s0 = l->string;
354 targets[i] = malloc((strlen(s0)+1)*sizeof(char));
355 if (!targets[i]) {
356 printf("ERROR: Out of memory!\n");
357 exit(EXITBAD);
359 strcpy(targets[i], s0);
360 l = l->next;
362 num_targets = targetCount;
364 printf("new targets:\n");
365 for (i = 0; i < num_targets; i++) {
366 printf("target %i: %s\n", i, targets[i]);
370 #endif
372 /* Now make target */
373 if (!num_targets) status |= make(1, &all, anyhow);
374 else status |= make(num_targets, (const char **)targets, anyhow);
376 /* Widely scattered cleanup */
377 var_done();
378 donerules();
379 donestamps();
380 donestr();
382 /* close cmdout */
383 if (globs.cmdout) fclose(globs.cmdout);
385 return status ? EXITBAD : EXITOK;