fixed broken header scanner
[k8jam.git] / src / jam.c
blob84c89ffdbe58f0dba0712aa6a5e088c7f3d48496
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.
15 * jam.c - make redux
17 * See Jam.html for usage information.
19 * These comments document the code.
21 * The top half of the code is structured such:
23 * jam
24 * / | \
25 * +---+ | \
26 * / | \
27 * jamgram option \
28 * / | \ \
29 * / | \ \
30 * / | \ |
31 * scan | compile make
32 * | | / | \ / | \
33 * | | / | \ / | \
34 * | | / | \ / | \
35 * jambase parse | rules search make1
36 * | | | \
37 * | | | \
38 * | | | \
39 * builtins timestamp command execute
40 * |
41 * |
42 * |
43 * filesys
46 * The support routines are called by all of the above, but themselves
47 * are layered thus:
49 * variable|expand
50 * / | | |
51 * / | | |
52 * / | | |
53 * lists | | pathsys
54 * \ | |
55 * \ | |
56 * \ | |
57 * newstr |
58 * \ |
59 * \ |
60 * \ |
61 * hash
63 * Roughly, the modules are:
65 * builtins.c - jam's built-in rules
66 * command.c - maintain lists of commands
67 * compile.c - compile parsed jam statements
68 * execcmd.c - execute a shell script on UNIX
69 * expand.c - expand a buffer, given variable values
70 * file*.c - scan directories and archives on *
71 * hash.c - simple in-memory hashing routines
72 * headers.c - handle #includes in source files
73 * jambase.c - compilable copy of Jambase
74 * jamgram.y - jam grammar
75 * lists.c - maintain lists of strings
76 * make.c - bring a target up to date, once rules are in place
77 * make1.c - execute command to bring targets up to date
78 * newstr.c - string manipulation routines
79 * option.c - command line option processing
80 * parse.c - make and destroy parse trees as driven by the parser
81 * path*.c - manipulate file names on *
82 * hash.c - simple in-memory hashing routines
83 * hsregexp.c - Henry Spencer's regexp
84 * rules.c - access to RULEs, TARGETs, and ACTIONs
85 * scan.c - the jam yacc scanner
86 * search.c - find a target along $(SEARCH) or $(LOCATE)
87 * timestamp.c - get the timestamp of a file or archive member
88 * variable.c - handle jam multi-element variables
90 * 05/04/94 (seiwald) - async multiprocess (-j) support
91 * 02/08/95 (seiwald) - -n implies -d2.
92 * 02/22/95 (seiwald) - -v for version info.
93 * 09/11/00 (seiwald) - PATCHLEVEL folded into VERSION.
94 * 01/10/01 (seiwald) - pathsys.h split from filesys.h
95 * 01/21/02 (seiwald) - new -q to quit quickly on build failure
96 * 03/16/02 (seiwald) - support for -g (reorder builds by source time)
97 * 09/19/02 (seiwald) - new -d displays
98 * 10/22/02 (seiwald) - list_new() now does its own newstr()/copystr()
99 * 11/04/02 (seiwald) - const-ing for string literals
101 #include "jam.h"
102 #include "option.h"
103 #include "patchlevel.h"
105 /* These get various function declarations. */
106 #include "lists.h"
107 #include "parse.h"
108 #include "variable.h"
109 #include "compile.h"
110 #include "builtins.h"
111 #include "rules.h"
112 #include "newstr.h"
113 #include "scan.h"
114 #include "timestamp.h"
115 #include "make.h"
116 #include "hcache.h"
118 /* And UNIX for this */
119 #ifdef unix
120 # include <sys/utsname.h>
121 #endif
124 struct globs globs = {
125 .noexec = 0,
126 .jobs = 1,
127 .quitquick = 0,
128 .newestfirst = 0, /* newestfirst */
129 .debug = { 0, 1 }, /* display actions */
130 .cmdout = NULL, /* output commands, not run them */
131 //#ifdef OPT_IMPROVED_PROGRESS_EXT
132 .updating = 0,
133 .progress = NULL,
134 //#endif
138 /* symbols to be defined as true for use in Jambase */
139 static const char *othersyms[] = { OSMAJOR, OSMINOR, OSPLAT, JAMVERSYM, 0 } ;
142 /* Known for sure:
143 * OS2 needs extern environ
145 #ifndef use_environ
146 # define use_environ environ
147 # if !defined(__WATCOM__) && !defined(OS_OS2) && !defined(OS_NT)
148 extern char **environ;
149 # endif
150 #endif
153 int main (int argc, char **argv, char **arg_environ) {
154 int n, num_targets;
155 const char *s;
156 struct option optv[N_OPTS];
157 char *targets[N_TARGETS];
158 const char *all = "all";
159 int anyhow = 0;
160 int status;
161 int wasOptH = 0;
163 --argc; ++argv;
164 if ((num_targets = getoptions(argc, argv, "H:d:j:f:gs:t:ano:qv", optv, targets)) < 0) {
165 printf("usage: jam [ options ] targets...\n\n"
166 "-a Build all targets, even if they are current.\n"
167 "-dx Display (a)actions (c)causes (d)dependencies\n"
168 " (m)make tree (x)commands (0-9) debug levels.\n"
169 "-fx Read x instead of Jambase.\n"
170 "-g Build from newest sources first.\n"
171 "-jx Run up to x shell commands concurrently.\n"
172 "-n Don't actually execute the updating actions.\n"
173 "-ox Write the updating actions to file x.\n"
174 "-q Quit quickly as soon as a target fails.\n"
175 "-sx=y Set variable x=y, overriding environment.\n"
176 "-tx Rebuild x, even if it is up-to-date.\n"
177 "-v Print the version of jam and exit.\n"
178 "-Hx show header cache statistics (a)ll, (h)its, (s)tats.\n"
180 exit(EXITBAD);
182 /* version info. */
183 if ((s = getoptval(optv, 'v', 0))) {
184 printf("K8-Jam %s. %s. ", VERSION, OSMINOR );
185 printf(
186 "(C) 1993-2003 Christopher Seiwald, see http://www.freetype.org/jam/\n"
187 "changes by Ketmar // Vampire Avalon, psyc://ketmar.no-ip.org/~ketmar\n"
189 return EXITOK;
191 /* pick up interesting options */
192 if ((s = getoptval(optv, 'n', 0))) globs.noexec++, DEBUG_MAKE = DEBUG_MAKEQ = DEBUG_EXEC = 1;
193 if ((s = getoptval(optv, 'q', 0))) globs.quitquick = 1;
194 if ((s = getoptval(optv, 'a', 0))) anyhow++;
195 if ((s = getoptval(optv, 'j', 0))) globs.jobs = atoi(s);
196 if ((s = getoptval(optv, 'g', 0))) globs.newestfirst = 1;
197 /* turn on/off debugging */
198 for (n = 0; (s = getoptval(optv, 'd', n)) != 0; ++n) {
199 int i = atoi(s);
200 /* first -d, turn off defaults. */
201 if (!n) DEBUG_MAKE = DEBUG_MAKEQ = DEBUG_EXEC = 0;
202 /* n turns on levels 1-n */
203 /* +n turns on level n */
204 /* c turns on named display c */
205 if (i < 0 || i >= DEBUG_MAX) {
206 printf( "Invalid debug level '%s'.\n", s );
207 } else if (*s == '+') {
208 globs.debug[i] = 1;
209 } else if (i) {
210 while (i) globs.debug[i--] = 1;
211 } else {
212 while (*s) {
213 switch (*s++) {
214 case 'a': DEBUG_MAKE = DEBUG_MAKEQ = 1; break;
215 case 'c': DEBUG_CAUSES = 1; break;
216 case 'd': DEBUG_DEPENDS = 1; break;
217 case 'm': DEBUG_MAKEPROG = 1; break;
218 case 'x': DEBUG_EXEC = 1; break;
219 case '0': break;
220 default: printf("Invalid debug flag '%c'.\n", s[-1]);
225 /* header cache statistics */
226 for (n = 0; (s = getoptval(optv, 'H', n)) != 0; ++n) {
227 wasOptH = 1;
228 for (; *s; ++s) {
229 switch (*s) {
230 case 'a': optShowHCacheStats = optShowHCacheInfo = 1; break;
231 case 'h': optShowHCacheInfo = 1; break;
232 case 's': optShowHCacheStats = 1; break;
236 if (wasOptH && (optShowHCacheStats == 0 && optShowHCacheInfo == 0)) optShowHCacheStats = optShowHCacheInfo = 1;
237 /* set JAMDATE first */
239 char buf[128], *p;
240 time_t clock;
242 time(&clock);
243 strcpy(buf, ctime(&clock));
244 /* trim newline from date */
245 p = buf+strlen(buf);
246 while (p >= buf && *((unsigned char *)p) <= ' ') --p;
247 *(++p) = '\0';
248 var_set("JAMDATE", list_new(L0, buf, 0), VAR_SET);
250 /* And JAMUNAME */
251 #ifdef unix
253 struct utsname u;
255 if (uname(&u) >= 0) {
256 LIST *l = L0;
257 l = list_new(l, u.machine, 0);
258 l = list_new(l, u.version, 0);
259 l = list_new(l, u.release, 0);
260 l = list_new(l, u.nodename, 0);
261 l = list_new(l, u.sysname, 0);
262 var_set("JAMUNAME", l, VAR_SET);
265 #endif /* unix */
266 /* Jam defined variables OS, OSPLAT */
267 var_defines(othersyms);
268 /* load up environment variables */
269 var_defines((const char **)use_environ);
270 /* load up variables set on command line. */
271 for (n = 0; (s = getoptval(optv, 's', n)) != 0; ++n) {
272 const char *symv[2];
273 symv[0] = s;
274 symv[1] = 0;
275 var_defines(symv);
277 /* add JAMCMDARGS */
279 LIST *l0 = L0, *l1 = L0;
281 if (num_targets < 1) {
282 l0 = list_new(l0, "all", 0);
283 l1 = list_new(l1, "all", 0);
284 } else {
285 for (n = 0; n < num_targets; ++n) {
286 /*printf("target %i: %s\n", n, targets[n]);*/
287 l0 = list_new(l0, targets[n], 0);
288 l1 = list_new(l1, targets[n], 0);
291 var_set("JAMCMDARGS", l0, VAR_SET);
292 var_set("JAM_TARGETS", l1, VAR_SET); /* k8 */
294 /* initialize built-in rules */
295 load_builtins();
296 /* parse ruleset */
297 for (n = 0; (s = getoptval(optv, 'f', n)) != 0; ++n) parse_file(s);
298 if (!n) parse_file("::Jambase");
299 status = yyanyerrors();
300 /* manually touch -t targets */
301 for (n = 0; (s = getoptval(optv, 't', n)) != 0; ++n) touchtarget(s);
302 /* if an output file is specified, set globs.cmdout to that */
303 if ((s = getoptval(optv, 'o', 0)) != 0) {
304 if (!(globs.cmdout = fopen(s, "w"))) {
305 printf("Failed to write to '%s'\n", s);
306 exit(EXITBAD);
308 ++globs.noexec;
310 #ifndef NO_OPT_JAM_TARGETS_VARIABLE_EXT
311 /* ported from Haiku */
312 /* get value of variable JAM_TARGETS and build the targets */
314 LIST *l = var_get("JAM_TARGETS");
315 int targetCount = list_length(l);
316 int i;
318 if (targetCount == 0) {
319 /* no targets: nothing to do */
320 printf("No targets. Nothing to do.\n");
321 exit(EXITOK);
323 if (targetCount >= N_TARGETS) {
324 printf("ERROR: Too many targets!\n");
325 exit(EXITBAD);
327 for (i = 0; i < targetCount; ++i) {
328 const char *s0 = l->string;
329 targets[i] = malloc((strlen(s0)+1)*sizeof(char));
330 if (!targets[i]) {
331 printf("ERROR: Out of memory!\n");
332 exit(EXITBAD);
334 strcpy(targets[i], s0);
335 l = l->next;
337 num_targets = targetCount;
339 printf("new targets:\n");
340 for (i = 0; i < num_targets; i++) {
341 printf("target %i: %s\n", i, targets[i]);
345 #endif
346 /* now make target */
347 if (!num_targets) status |= make(1, &all, anyhow);
348 else status |= make(num_targets, (const char **)targets, anyhow);
349 /* widely scattered cleanup */
350 var_done();
351 donerules();
352 donestamps();
353 donestr();
354 /* close cmdout */
355 if (globs.cmdout) fclose(globs.cmdout);
356 return status ? EXITBAD : EXITOK;