1 | /* |
---|
2 | * /+\ |
---|
3 | * +\ Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. |
---|
4 | * \+/ |
---|
5 | * |
---|
6 | * This file is part of jam. |
---|
7 | * |
---|
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. |
---|
11 | * |
---|
12 | * ALL WARRANTIES ARE HEREBY DISCLAIMED. |
---|
13 | */ |
---|
14 | |
---|
15 | /* This file is ALSO: |
---|
16 | * Copyright 2001-2004 David Abrahams. |
---|
17 | * Distributed under the Boost Software License, Version 1.0. |
---|
18 | * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) |
---|
19 | */ |
---|
20 | |
---|
21 | /* |
---|
22 | * jam.c - make redux |
---|
23 | * |
---|
24 | * See Jam.html for usage information. |
---|
25 | * |
---|
26 | * These comments document the code. |
---|
27 | * |
---|
28 | * The top half of the code is structured such: |
---|
29 | * |
---|
30 | * jam |
---|
31 | * / | \ |
---|
32 | * +---+ | \ |
---|
33 | * / | \ |
---|
34 | * jamgram option \ |
---|
35 | * / | \ \ |
---|
36 | * / | \ \ |
---|
37 | * / | \ | |
---|
38 | * scan | compile make |
---|
39 | * | | / | \ / | \ |
---|
40 | * | | / | \ / | \ |
---|
41 | * | | / | \ / | \ |
---|
42 | * jambase parse | rules search make1 |
---|
43 | * | | | \ |
---|
44 | * | | | \ |
---|
45 | * | | | \ |
---|
46 | * builtins timestamp command execute |
---|
47 | * | |
---|
48 | * | |
---|
49 | * | |
---|
50 | * filesys |
---|
51 | * |
---|
52 | * |
---|
53 | * The support routines are called by all of the above, but themselves |
---|
54 | * are layered thus: |
---|
55 | * |
---|
56 | * variable|expand |
---|
57 | * / | | | |
---|
58 | * / | | | |
---|
59 | * / | | | |
---|
60 | * lists | | pathsys |
---|
61 | * \ | | |
---|
62 | * \ | | |
---|
63 | * \ | | |
---|
64 | * newstr | |
---|
65 | * \ | |
---|
66 | * \ | |
---|
67 | * \ | |
---|
68 | * hash |
---|
69 | * |
---|
70 | * Roughly, the modules are: |
---|
71 | * |
---|
72 | * builtins.c - jam's built-in rules |
---|
73 | * command.c - maintain lists of commands |
---|
74 | * compile.c - compile parsed jam statements |
---|
75 | * execunix.c - execute a shell script on UNIX |
---|
76 | * execvms.c - execute a shell script, ala VMS |
---|
77 | * expand.c - expand a buffer, given variable values |
---|
78 | * file*.c - scan directories and archives on * |
---|
79 | * hash.c - simple in-memory hashing routines |
---|
80 | * hdrmacro.c - handle header file parsing for filename macro definitions |
---|
81 | * headers.c - handle #includes in source files |
---|
82 | * jambase.c - compilable copy of Jambase |
---|
83 | * jamgram.y - jam grammar |
---|
84 | * lists.c - maintain lists of strings |
---|
85 | * make.c - bring a target up to date, once rules are in place |
---|
86 | * make1.c - execute command to bring targets up to date |
---|
87 | * newstr.c - string manipulation routines |
---|
88 | * option.c - command line option processing |
---|
89 | * parse.c - make and destroy parse trees as driven by the parser |
---|
90 | * path*.c - manipulate file names on * |
---|
91 | * hash.c - simple in-memory hashing routines |
---|
92 | * regexp.c - Henry Spencer's regexp |
---|
93 | * rules.c - access to RULEs, TARGETs, and ACTIONs |
---|
94 | * scan.c - the jam yacc scanner |
---|
95 | * search.c - find a target along $(SEARCH) or $(LOCATE) |
---|
96 | * timestamp.c - get the timestamp of a file or archive member |
---|
97 | * variable.c - handle jam multi-element variables |
---|
98 | * |
---|
99 | * 05/04/94 (seiwald) - async multiprocess (-j) support |
---|
100 | * 02/08/95 (seiwald) - -n implies -d2. |
---|
101 | * 02/22/95 (seiwald) - -v for version info. |
---|
102 | * 09/11/00 (seiwald) - PATCHLEVEL folded into VERSION. |
---|
103 | * 01/10/01 (seiwald) - pathsys.h split from filesys.h |
---|
104 | */ |
---|
105 | |
---|
106 | # include "jam.h" |
---|
107 | # include "option.h" |
---|
108 | # include "patchlevel.h" |
---|
109 | |
---|
110 | /* These get various function declarations. */ |
---|
111 | |
---|
112 | # include "lists.h" |
---|
113 | # include "parse.h" |
---|
114 | # include "variable.h" |
---|
115 | # include "compile.h" |
---|
116 | # include "builtins.h" |
---|
117 | # include "rules.h" |
---|
118 | # include "newstr.h" |
---|
119 | # include "scan.h" |
---|
120 | # include "timestamp.h" |
---|
121 | # include "make.h" |
---|
122 | # include "strings.h" |
---|
123 | # include "expand.h" |
---|
124 | |
---|
125 | /* Macintosh is "special" */ |
---|
126 | |
---|
127 | # ifdef OS_MAC |
---|
128 | # include <QuickDraw.h> |
---|
129 | # endif |
---|
130 | |
---|
131 | /* And UNIX for this */ |
---|
132 | |
---|
133 | # ifdef unix |
---|
134 | # include <sys/utsname.h> |
---|
135 | # endif |
---|
136 | |
---|
137 | struct globs globs = { |
---|
138 | 0, /* noexec */ |
---|
139 | 1, /* jobs */ |
---|
140 | 0, /* quitquick */ |
---|
141 | 0, /* newestfirst */ |
---|
142 | # ifdef OS_MAC |
---|
143 | { 0, 0 }, /* debug - suppress tracing output */ |
---|
144 | # else |
---|
145 | { 0, 1 }, /* debug ... */ |
---|
146 | # endif |
---|
147 | 0 /* output commands, not run them */ |
---|
148 | } ; |
---|
149 | |
---|
150 | /* Symbols to be defined as true for use in Jambase */ |
---|
151 | |
---|
152 | static char *othersyms[] = { OSMAJOR, OSMINOR, OSPLAT, JAMVERSYM, 0 } ; |
---|
153 | |
---|
154 | /* Known for sure: |
---|
155 | * mac needs arg_enviro |
---|
156 | * OS2 needs extern environ |
---|
157 | */ |
---|
158 | |
---|
159 | # ifdef OS_MAC |
---|
160 | # define use_environ arg_environ |
---|
161 | # ifdef MPW |
---|
162 | QDGlobals qd; |
---|
163 | # endif |
---|
164 | # endif |
---|
165 | |
---|
166 | /* on Win32-LCC */ |
---|
167 | # if defined( OS_NT ) && defined( __LCC__ ) |
---|
168 | # define use_environ _environ |
---|
169 | # endif |
---|
170 | |
---|
171 | # if defined( __MWERKS__) |
---|
172 | # define use_environ _environ |
---|
173 | extern char **_environ; |
---|
174 | #endif |
---|
175 | |
---|
176 | # ifndef use_environ |
---|
177 | # define use_environ environ |
---|
178 | # if !defined( __WATCOM__ ) && !defined( OS_OS2 ) && !defined( OS_NT ) |
---|
179 | extern char **environ; |
---|
180 | # endif |
---|
181 | # endif |
---|
182 | |
---|
183 | # if YYDEBUG != 0 |
---|
184 | extern int yydebug; |
---|
185 | # endif |
---|
186 | |
---|
187 | #ifndef NDEBUG |
---|
188 | static void run_unit_tests() |
---|
189 | { |
---|
190 | # if defined( USE_EXECNT ) |
---|
191 | extern void execnt_unit_test(); |
---|
192 | execnt_unit_test(); |
---|
193 | # endif |
---|
194 | string_unit_test(); |
---|
195 | var_expand_unit_test(); |
---|
196 | } |
---|
197 | #endif |
---|
198 | |
---|
199 | #ifdef HAVE_PYTHON |
---|
200 | extern PyObject* |
---|
201 | bjam_call(PyObject *self, PyObject *args); |
---|
202 | |
---|
203 | extern PyObject* |
---|
204 | bjam_import_rule(PyObject* self, PyObject* args); |
---|
205 | #endif |
---|
206 | |
---|
207 | int main( int argc, char **argv, char **arg_environ ) |
---|
208 | { |
---|
209 | int n; |
---|
210 | char *s; |
---|
211 | struct option optv[N_OPTS]; |
---|
212 | const char *all = "all"; |
---|
213 | int anyhow = 0; |
---|
214 | int status; |
---|
215 | int arg_c = argc; |
---|
216 | char ** arg_v = argv; |
---|
217 | const char *progname = argv[0]; |
---|
218 | |
---|
219 | # ifdef OS_MAC |
---|
220 | InitGraf(&qd.thePort); |
---|
221 | # endif |
---|
222 | |
---|
223 | #ifdef HAVE_PYTHON |
---|
224 | Py_Initialize(); |
---|
225 | |
---|
226 | { |
---|
227 | static PyMethodDef BjamMethods[] = { |
---|
228 | {"call", bjam_call, METH_VARARGS, |
---|
229 | "Call the specified bjam rule."}, |
---|
230 | {"import_rule", bjam_import_rule, METH_VARARGS, |
---|
231 | "Imports Python callable to bjam."}, |
---|
232 | {NULL, NULL, 0, NULL} |
---|
233 | }; |
---|
234 | |
---|
235 | Py_InitModule("bjam", BjamMethods); |
---|
236 | } |
---|
237 | |
---|
238 | #endif |
---|
239 | |
---|
240 | argc--, argv++; |
---|
241 | |
---|
242 | if( getoptions( argc, argv, "-:d:j:f:gs:t:ano:qv", optv ) < 0 ) |
---|
243 | { |
---|
244 | printf( "\nusage: %s [ options ] targets...\n\n", progname ); |
---|
245 | |
---|
246 | printf( "-a Build all targets, even if they are current.\n" ); |
---|
247 | printf( "-dx Set the debug level to x (0-9).\n" ); |
---|
248 | printf( "-fx Read x instead of Jambase.\n" ); |
---|
249 | /* printf( "-g Build from newest sources first.\n" ); */ |
---|
250 | printf( "-jx Run up to x shell commands concurrently.\n" ); |
---|
251 | printf( "-n Don't actually execute the updating actions.\n" ); |
---|
252 | printf( "-ox Write the updating actions to file x.\n" ); |
---|
253 | printf( "-q Quit quickly as soon as a target fails.\n" ); |
---|
254 | printf( "-sx=y Set variable x=y, overriding environment.\n" ); |
---|
255 | printf( "-tx Rebuild x, even if it is up-to-date.\n" ); |
---|
256 | printf( "-v Print the version of jam and exit.\n" ); |
---|
257 | printf( "--x Option is ignored.\n\n" ); |
---|
258 | |
---|
259 | exit( EXITBAD ); |
---|
260 | } |
---|
261 | |
---|
262 | /* Version info. */ |
---|
263 | |
---|
264 | if( ( s = getoptval( optv, 'v', 0 ) ) ) |
---|
265 | { |
---|
266 | printf( "Boost.Jam " ); |
---|
267 | printf( "Version %s. %s.\n", VERSION, OSMINOR ); |
---|
268 | printf( " Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. \n" ); |
---|
269 | printf( " Copyright 2001 David Turner.\n" ); |
---|
270 | printf( " Copyright 2001-2004 David Abrahams.\n" ); |
---|
271 | printf( " Copyright 2002-2005 Rene Rivera.\n" ); |
---|
272 | printf( " Copyright 2003-2005 Vladimir Prus.\n" ); |
---|
273 | |
---|
274 | return EXITOK; |
---|
275 | } |
---|
276 | |
---|
277 | /* Pick up interesting options */ |
---|
278 | |
---|
279 | if( ( s = getoptval( optv, 'n', 0 ) ) ) |
---|
280 | globs.noexec++, globs.debug[2] = 1; |
---|
281 | |
---|
282 | if( ( s = getoptval( optv, 'q', 0 ) ) ) |
---|
283 | globs.quitquick = 1; |
---|
284 | if( ( s = getoptval( optv, 'a', 0 ) ) ) |
---|
285 | anyhow++; |
---|
286 | |
---|
287 | if( ( s = getoptval( optv, 'j', 0 ) ) ) |
---|
288 | globs.jobs = atoi( s ); |
---|
289 | |
---|
290 | if( ( s = getoptval( optv, 'g', 0 ) ) ) |
---|
291 | globs.newestfirst = 1; |
---|
292 | |
---|
293 | /* Turn on/off debugging */ |
---|
294 | |
---|
295 | for( n = 0; s = getoptval( optv, 'd', n ); n++ ) |
---|
296 | { |
---|
297 | int i; |
---|
298 | |
---|
299 | /* First -d, turn off defaults. */ |
---|
300 | |
---|
301 | if( !n ) |
---|
302 | for( i = 0; i < DEBUG_MAX; i++ ) |
---|
303 | globs.debug[i] = 0; |
---|
304 | |
---|
305 | i = atoi( s ); |
---|
306 | |
---|
307 | if( i < 0 || i >= DEBUG_MAX ) |
---|
308 | { |
---|
309 | printf( "Invalid debug level '%s'.\n", s ); |
---|
310 | continue; |
---|
311 | } |
---|
312 | |
---|
313 | /* n turns on levels 1-n */ |
---|
314 | /* +n turns on level n */ |
---|
315 | |
---|
316 | if( *s == '+' ) |
---|
317 | globs.debug[i] = 1; |
---|
318 | else while( i ) |
---|
319 | globs.debug[i--] = 1; |
---|
320 | } |
---|
321 | |
---|
322 | #ifndef NDEBUG |
---|
323 | run_unit_tests(); |
---|
324 | #endif |
---|
325 | #if YYDEBUG != 0 |
---|
326 | if ( DEBUG_PARSE ) |
---|
327 | yydebug = 1; |
---|
328 | #endif |
---|
329 | |
---|
330 | /* Set JAMDATE first */ |
---|
331 | |
---|
332 | { |
---|
333 | char *date; |
---|
334 | time_t clock; |
---|
335 | time( &clock ); |
---|
336 | date = newstr( ctime( &clock ) ); |
---|
337 | |
---|
338 | /* Trim newline from date */ |
---|
339 | |
---|
340 | if( strlen( date ) == 25 ) |
---|
341 | date[ 24 ] = 0; |
---|
342 | |
---|
343 | var_set( "JAMDATE", list_new( L0, newstr( date ) ), VAR_SET ); |
---|
344 | } |
---|
345 | |
---|
346 | |
---|
347 | { |
---|
348 | /* Pleace don't change the following line. The 'bump_version.py' script |
---|
349 | expect a specific format of it. */ |
---|
350 | char *major_version = "03", *minor_version = "01", *changenum = "11"; |
---|
351 | var_set( "JAM_VERSION", |
---|
352 | list_new( list_new( list_new( L0, newstr( major_version ) ), |
---|
353 | newstr( minor_version ) ), |
---|
354 | newstr( changenum ) ), |
---|
355 | VAR_SET ); |
---|
356 | } |
---|
357 | |
---|
358 | /* And JAMUNAME */ |
---|
359 | # ifdef unix |
---|
360 | { |
---|
361 | struct utsname u; |
---|
362 | |
---|
363 | if( uname( &u ) >= 0 ) |
---|
364 | { |
---|
365 | var_set( "JAMUNAME", |
---|
366 | list_new( |
---|
367 | list_new( |
---|
368 | list_new( |
---|
369 | list_new( |
---|
370 | list_new( L0, |
---|
371 | newstr( u.sysname ) ), |
---|
372 | newstr( u.nodename ) ), |
---|
373 | newstr( u.release ) ), |
---|
374 | newstr( u.version ) ), |
---|
375 | newstr( u.machine ) ), VAR_SET ); |
---|
376 | } |
---|
377 | } |
---|
378 | # endif /* unix */ |
---|
379 | |
---|
380 | /* load up environment variables */ |
---|
381 | |
---|
382 | /* first into global module, with splitting, for backward compatibility */ |
---|
383 | var_defines( use_environ, 1 ); |
---|
384 | |
---|
385 | /* then into .ENVIRON, without splitting */ |
---|
386 | enter_module( bindmodule(".ENVIRON") ); |
---|
387 | var_defines( use_environ, 0 ); |
---|
388 | exit_module( bindmodule(".ENVIRON") ); |
---|
389 | |
---|
390 | /* |
---|
391 | * Jam defined variables OS, OSPLAT |
---|
392 | * We load them after environment, so that |
---|
393 | * setting OS in environment does not |
---|
394 | * change Jam notion of the current platform. |
---|
395 | */ |
---|
396 | |
---|
397 | var_defines( othersyms, 1 ); |
---|
398 | |
---|
399 | |
---|
400 | /* Load up variables set on command line. */ |
---|
401 | |
---|
402 | for( n = 0; s = getoptval( optv, 's', n ); n++ ) |
---|
403 | { |
---|
404 | char *symv[2]; |
---|
405 | symv[0] = s; |
---|
406 | symv[1] = 0; |
---|
407 | var_defines( symv, 1 ); |
---|
408 | } |
---|
409 | |
---|
410 | /* Set the ARGV to reflect the complete list of arguments of invocation. */ |
---|
411 | |
---|
412 | for ( n = 0; n < arg_c; ++n ) |
---|
413 | { |
---|
414 | var_set( "ARGV", list_new( L0, newstr( arg_v[n] ) ), VAR_APPEND ); |
---|
415 | } |
---|
416 | |
---|
417 | /* Initialize built-in rules */ |
---|
418 | |
---|
419 | load_builtins(); |
---|
420 | |
---|
421 | /* Add the targets in the command line to update list */ |
---|
422 | |
---|
423 | for ( n = 1; n < arg_c; ++n ) |
---|
424 | { |
---|
425 | if ( arg_v[n][0] == '-' ) |
---|
426 | { |
---|
427 | char *f = "-:d:j:f:gs:t:ano:qv"; |
---|
428 | for( ; *f; f++ ) if( *f == arg_v[n][1] ) break; |
---|
429 | if ( f[1] == ':' && arg_v[n][2] == '\0' ) { ++n; } |
---|
430 | } |
---|
431 | else |
---|
432 | { |
---|
433 | mark_target_for_updating(arg_v[n]); |
---|
434 | } |
---|
435 | } |
---|
436 | |
---|
437 | /* Parse ruleset */ |
---|
438 | |
---|
439 | { |
---|
440 | FRAME frame[1]; |
---|
441 | frame_init( frame ); |
---|
442 | for( n = 0; s = getoptval( optv, 'f', n ); n++ ) |
---|
443 | parse_file( s, frame ); |
---|
444 | |
---|
445 | if( !n ) |
---|
446 | parse_file( "+", frame ); |
---|
447 | } |
---|
448 | |
---|
449 | status = yyanyerrors(); |
---|
450 | |
---|
451 | /* Manually touch -t targets */ |
---|
452 | |
---|
453 | for( n = 0; s = getoptval( optv, 't', n ); n++ ) |
---|
454 | touchtarget( s ); |
---|
455 | |
---|
456 | /* If an output file is specified, set globs.cmdout to that */ |
---|
457 | |
---|
458 | if( s = getoptval( optv, 'o', 0 ) ) |
---|
459 | { |
---|
460 | if( !( globs.cmdout = fopen( s, "w" ) ) ) |
---|
461 | { |
---|
462 | printf( "Failed to write to '%s'\n", s ); |
---|
463 | exit( EXITBAD ); |
---|
464 | } |
---|
465 | globs.noexec++; |
---|
466 | } |
---|
467 | |
---|
468 | /* Now make target */ |
---|
469 | |
---|
470 | { |
---|
471 | LIST* targets = targets_to_update(); |
---|
472 | if ( !targets ) |
---|
473 | { |
---|
474 | status |= make( 1, &all, anyhow ); |
---|
475 | } |
---|
476 | else |
---|
477 | { |
---|
478 | int targets_count = list_length(targets); |
---|
479 | const char **targets2 = (const char **)malloc(targets_count * sizeof(char *)); |
---|
480 | int n = 0; |
---|
481 | for ( ; targets; targets = list_next(targets) ) |
---|
482 | { |
---|
483 | targets2[n++] = targets->string; |
---|
484 | } |
---|
485 | status |= make( targets_count, targets2, anyhow ); |
---|
486 | free(targets); |
---|
487 | } |
---|
488 | } |
---|
489 | |
---|
490 | |
---|
491 | if ( DEBUG_PROFILE ) |
---|
492 | profile_dump(); |
---|
493 | |
---|
494 | /* Widely scattered cleanup */ |
---|
495 | |
---|
496 | var_done(); |
---|
497 | donerules(); |
---|
498 | donestamps(); |
---|
499 | donestr(); |
---|
500 | |
---|
501 | /* close cmdout */ |
---|
502 | |
---|
503 | if( globs.cmdout ) |
---|
504 | fclose( globs.cmdout ); |
---|
505 | |
---|
506 | #ifdef HAVE_PYTHON |
---|
507 | Py_Finalize(); |
---|
508 | #endif |
---|
509 | |
---|
510 | |
---|
511 | return status ? EXITBAD : EXITOK; |
---|
512 | } |
---|