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 | # include "debug.h" |
---|
125 | # include "filesys.h" |
---|
126 | |
---|
127 | /* Macintosh is "special" */ |
---|
128 | |
---|
129 | # ifdef OS_MAC |
---|
130 | # include <QuickDraw.h> |
---|
131 | # endif |
---|
132 | |
---|
133 | /* And UNIX for this */ |
---|
134 | |
---|
135 | # ifdef unix |
---|
136 | # include <sys/utsname.h> |
---|
137 | # endif |
---|
138 | |
---|
139 | struct globs globs = { |
---|
140 | 0, /* noexec */ |
---|
141 | 1, /* jobs */ |
---|
142 | 0, /* quitquick */ |
---|
143 | 0, /* newestfirst */ |
---|
144 | # ifdef OS_MAC |
---|
145 | { 0, 0 }, /* debug - suppress tracing output */ |
---|
146 | # else |
---|
147 | { 0, 1 }, /* debug ... */ |
---|
148 | # endif |
---|
149 | 0, /* output commands, not run them */ |
---|
150 | 0 /* action timeout */ |
---|
151 | } ; |
---|
152 | |
---|
153 | /* Symbols to be defined as true for use in Jambase */ |
---|
154 | |
---|
155 | static char *othersyms[] = { OSMAJOR, OSMINOR, OSPLAT, JAMVERSYM, 0 } ; |
---|
156 | |
---|
157 | /* Known for sure: |
---|
158 | * mac needs arg_enviro |
---|
159 | * OS2 needs extern environ |
---|
160 | */ |
---|
161 | |
---|
162 | # ifdef OS_MAC |
---|
163 | # define use_environ arg_environ |
---|
164 | # ifdef MPW |
---|
165 | QDGlobals qd; |
---|
166 | # endif |
---|
167 | # endif |
---|
168 | |
---|
169 | /* on Win32-LCC */ |
---|
170 | # if defined( OS_NT ) && defined( __LCC__ ) |
---|
171 | # define use_environ _environ |
---|
172 | # endif |
---|
173 | |
---|
174 | # if defined( __MWERKS__) |
---|
175 | # define use_environ _environ |
---|
176 | extern char **_environ; |
---|
177 | #endif |
---|
178 | |
---|
179 | # ifndef use_environ |
---|
180 | # define use_environ environ |
---|
181 | # if !defined( __WATCOM__ ) && !defined( OS_OS2 ) && !defined( OS_NT ) |
---|
182 | extern char **environ; |
---|
183 | # endif |
---|
184 | # endif |
---|
185 | |
---|
186 | # if YYDEBUG != 0 |
---|
187 | extern int yydebug; |
---|
188 | # endif |
---|
189 | |
---|
190 | #ifndef NDEBUG |
---|
191 | static void run_unit_tests() |
---|
192 | { |
---|
193 | # if defined( USE_EXECNT ) |
---|
194 | extern void execnt_unit_test(); |
---|
195 | execnt_unit_test(); |
---|
196 | # endif |
---|
197 | string_unit_test(); |
---|
198 | var_expand_unit_test(); |
---|
199 | } |
---|
200 | #endif |
---|
201 | |
---|
202 | #ifdef HAVE_PYTHON |
---|
203 | extern PyObject* |
---|
204 | bjam_call(PyObject *self, PyObject *args); |
---|
205 | |
---|
206 | extern PyObject* |
---|
207 | bjam_import_rule(PyObject* self, PyObject* args); |
---|
208 | #endif |
---|
209 | |
---|
210 | int main( int argc, char **argv, char **arg_environ ) |
---|
211 | { |
---|
212 | int n; |
---|
213 | char *s; |
---|
214 | struct option optv[N_OPTS]; |
---|
215 | const char *all = "all"; |
---|
216 | int anyhow = 0; |
---|
217 | int status; |
---|
218 | int arg_c = argc; |
---|
219 | char ** arg_v = argv; |
---|
220 | const char *progname = argv[0]; |
---|
221 | |
---|
222 | # ifdef OS_MAC |
---|
223 | InitGraf(&qd.thePort); |
---|
224 | # endif |
---|
225 | |
---|
226 | argc--, argv++; |
---|
227 | |
---|
228 | if( getoptions( argc, argv, "-:l:d:j:f:gs:t:ano:qv", optv ) < 0 ) |
---|
229 | { |
---|
230 | printf( "\nusage: %s [ options ] targets...\n\n", progname ); |
---|
231 | |
---|
232 | printf( "-a Build all targets, even if they are current.\n" ); |
---|
233 | printf( "-dx Set the debug level to x (0-9).\n" ); |
---|
234 | printf( "-fx Read x instead of Jambase.\n" ); |
---|
235 | /* printf( "-g Build from newest sources first.\n" ); */ |
---|
236 | printf( "-jx Run up to x shell commands concurrently.\n" ); |
---|
237 | printf( "-lx Limit actions to x number of seconds after which they are stopped.\n" ); |
---|
238 | printf( "-n Don't actually execute the updating actions.\n" ); |
---|
239 | printf( "-ox Write the updating actions to file x.\n" ); |
---|
240 | printf( "-q Quit quickly as soon as a target fails.\n" ); |
---|
241 | printf( "-sx=y Set variable x=y, overriding environment.\n" ); |
---|
242 | printf( "-tx Rebuild x, even if it is up-to-date.\n" ); |
---|
243 | printf( "-v Print the version of jam and exit.\n" ); |
---|
244 | printf( "--x Option is ignored.\n\n" ); |
---|
245 | |
---|
246 | exit( EXITBAD ); |
---|
247 | } |
---|
248 | |
---|
249 | /* Version info. */ |
---|
250 | |
---|
251 | if( ( s = getoptval( optv, 'v', 0 ) ) ) |
---|
252 | { |
---|
253 | printf( "Boost.Jam " ); |
---|
254 | printf( "Version %s. %s.\n", VERSION, OSMINOR ); |
---|
255 | printf( " Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. \n" ); |
---|
256 | printf( " Copyright 2001 David Turner.\n" ); |
---|
257 | printf( " Copyright 2001-2004 David Abrahams.\n" ); |
---|
258 | printf( " Copyright 2002-2005 Rene Rivera.\n" ); |
---|
259 | printf( " Copyright 2003-2005 Vladimir Prus.\n" ); |
---|
260 | |
---|
261 | return EXITOK; |
---|
262 | } |
---|
263 | |
---|
264 | /* Pick up interesting options */ |
---|
265 | |
---|
266 | if( ( s = getoptval( optv, 'n', 0 ) ) ) |
---|
267 | globs.noexec++, globs.debug[2] = 1; |
---|
268 | |
---|
269 | if( ( s = getoptval( optv, 'q', 0 ) ) ) |
---|
270 | globs.quitquick = 1; |
---|
271 | if( ( s = getoptval( optv, 'a', 0 ) ) ) |
---|
272 | anyhow++; |
---|
273 | |
---|
274 | if( ( s = getoptval( optv, 'j', 0 ) ) ) |
---|
275 | globs.jobs = atoi( s ); |
---|
276 | |
---|
277 | if( ( s = getoptval( optv, 'g', 0 ) ) ) |
---|
278 | globs.newestfirst = 1; |
---|
279 | |
---|
280 | if( ( s = getoptval( optv, 'l', 0 ) ) ) |
---|
281 | globs.timeout = atoi( s ); |
---|
282 | |
---|
283 | /* Turn on/off debugging */ |
---|
284 | |
---|
285 | for( n = 0; s = getoptval( optv, 'd', n ); n++ ) |
---|
286 | { |
---|
287 | int i; |
---|
288 | |
---|
289 | /* First -d, turn off defaults. */ |
---|
290 | |
---|
291 | if( !n ) |
---|
292 | for( i = 0; i < DEBUG_MAX; i++ ) |
---|
293 | globs.debug[i] = 0; |
---|
294 | |
---|
295 | i = atoi( s ); |
---|
296 | |
---|
297 | if( i < 0 || i >= DEBUG_MAX ) |
---|
298 | { |
---|
299 | printf( "Invalid debug level '%s'.\n", s ); |
---|
300 | continue; |
---|
301 | } |
---|
302 | |
---|
303 | /* n turns on levels 1-n */ |
---|
304 | /* +n turns on level n */ |
---|
305 | |
---|
306 | if( *s == '+' ) |
---|
307 | globs.debug[i] = 1; |
---|
308 | else while( i ) |
---|
309 | globs.debug[i--] = 1; |
---|
310 | } |
---|
311 | |
---|
312 | { PROFILE_ENTER(MAIN); |
---|
313 | |
---|
314 | #ifdef HAVE_PYTHON |
---|
315 | { |
---|
316 | PROFILE_ENTER(MAIN_PYTHON); |
---|
317 | Py_Initialize(); |
---|
318 | |
---|
319 | { |
---|
320 | static PyMethodDef BjamMethods[] = { |
---|
321 | {"call", bjam_call, METH_VARARGS, |
---|
322 | "Call the specified bjam rule."}, |
---|
323 | {"import_rule", bjam_import_rule, METH_VARARGS, |
---|
324 | "Imports Python callable to bjam."}, |
---|
325 | {NULL, NULL, 0, NULL} |
---|
326 | }; |
---|
327 | |
---|
328 | Py_InitModule("bjam", BjamMethods); |
---|
329 | } |
---|
330 | PROFILE_EXIT(MAIN_PYTHON); |
---|
331 | } |
---|
332 | #endif |
---|
333 | |
---|
334 | #ifndef NDEBUG |
---|
335 | run_unit_tests(); |
---|
336 | #endif |
---|
337 | #if YYDEBUG != 0 |
---|
338 | if ( DEBUG_PARSE ) |
---|
339 | yydebug = 1; |
---|
340 | #endif |
---|
341 | |
---|
342 | /* Set JAMDATE first */ |
---|
343 | |
---|
344 | { |
---|
345 | char *date; |
---|
346 | time_t clock; |
---|
347 | time( &clock ); |
---|
348 | date = newstr( ctime( &clock ) ); |
---|
349 | |
---|
350 | /* Trim newline from date */ |
---|
351 | |
---|
352 | if( strlen( date ) == 25 ) |
---|
353 | date[ 24 ] = 0; |
---|
354 | |
---|
355 | var_set( "JAMDATE", list_new( L0, newstr( date ) ), VAR_SET ); |
---|
356 | } |
---|
357 | |
---|
358 | |
---|
359 | var_set( "JAM_VERSION", |
---|
360 | list_new( list_new( list_new( L0, newstr( VERSION_MAJOR_SYM ) ), |
---|
361 | newstr( VERSION_MINOR_SYM ) ), |
---|
362 | newstr( VERSION_PATCH_SYM ) ), |
---|
363 | VAR_SET ); |
---|
364 | |
---|
365 | /* And JAMUNAME */ |
---|
366 | # ifdef unix |
---|
367 | { |
---|
368 | struct utsname u; |
---|
369 | |
---|
370 | if( uname( &u ) >= 0 ) |
---|
371 | { |
---|
372 | var_set( "JAMUNAME", |
---|
373 | list_new( |
---|
374 | list_new( |
---|
375 | list_new( |
---|
376 | list_new( |
---|
377 | list_new( L0, |
---|
378 | newstr( u.sysname ) ), |
---|
379 | newstr( u.nodename ) ), |
---|
380 | newstr( u.release ) ), |
---|
381 | newstr( u.version ) ), |
---|
382 | newstr( u.machine ) ), VAR_SET ); |
---|
383 | } |
---|
384 | } |
---|
385 | # endif /* unix */ |
---|
386 | |
---|
387 | /* load up environment variables */ |
---|
388 | |
---|
389 | /* first into global module, with splitting, for backward compatibility */ |
---|
390 | var_defines( use_environ, 1 ); |
---|
391 | |
---|
392 | /* then into .ENVIRON, without splitting */ |
---|
393 | enter_module( bindmodule(".ENVIRON") ); |
---|
394 | var_defines( use_environ, 0 ); |
---|
395 | exit_module( bindmodule(".ENVIRON") ); |
---|
396 | |
---|
397 | /* |
---|
398 | * Jam defined variables OS, OSPLAT |
---|
399 | * We load them after environment, so that |
---|
400 | * setting OS in environment does not |
---|
401 | * change Jam notion of the current platform. |
---|
402 | */ |
---|
403 | |
---|
404 | var_defines( othersyms, 1 ); |
---|
405 | |
---|
406 | |
---|
407 | /* Load up variables set on command line. */ |
---|
408 | |
---|
409 | for( n = 0; s = getoptval( optv, 's', n ); n++ ) |
---|
410 | { |
---|
411 | char *symv[2]; |
---|
412 | symv[0] = s; |
---|
413 | symv[1] = 0; |
---|
414 | var_defines( symv, 1 ); |
---|
415 | } |
---|
416 | |
---|
417 | /* Set the ARGV to reflect the complete list of arguments of invocation. */ |
---|
418 | |
---|
419 | for ( n = 0; n < arg_c; ++n ) |
---|
420 | { |
---|
421 | var_set( "ARGV", list_new( L0, newstr( arg_v[n] ) ), VAR_APPEND ); |
---|
422 | } |
---|
423 | |
---|
424 | /* Initialize built-in rules */ |
---|
425 | |
---|
426 | load_builtins(); |
---|
427 | |
---|
428 | /* Add the targets in the command line to update list */ |
---|
429 | |
---|
430 | for ( n = 1; n < arg_c; ++n ) |
---|
431 | { |
---|
432 | if ( arg_v[n][0] == '-' ) |
---|
433 | { |
---|
434 | char *f = "-:l:d:j:f:gs:t:ano:qv"; |
---|
435 | for( ; *f; f++ ) if( *f == arg_v[n][1] ) break; |
---|
436 | if ( f[1] == ':' && arg_v[n][2] == '\0' ) { ++n; } |
---|
437 | } |
---|
438 | else |
---|
439 | { |
---|
440 | mark_target_for_updating(arg_v[n]); |
---|
441 | } |
---|
442 | } |
---|
443 | |
---|
444 | /* Parse ruleset */ |
---|
445 | |
---|
446 | { |
---|
447 | FRAME frame[1]; |
---|
448 | frame_init( frame ); |
---|
449 | for( n = 0; s = getoptval( optv, 'f', n ); n++ ) |
---|
450 | parse_file( s, frame ); |
---|
451 | |
---|
452 | if( !n ) |
---|
453 | parse_file( "+", frame ); |
---|
454 | } |
---|
455 | |
---|
456 | status = yyanyerrors(); |
---|
457 | |
---|
458 | /* Manually touch -t targets */ |
---|
459 | |
---|
460 | for( n = 0; s = getoptval( optv, 't', n ); n++ ) |
---|
461 | touchtarget( s ); |
---|
462 | |
---|
463 | /* If an output file is specified, set globs.cmdout to that */ |
---|
464 | |
---|
465 | if( s = getoptval( optv, 'o', 0 ) ) |
---|
466 | { |
---|
467 | if( !( globs.cmdout = fopen( s, "w" ) ) ) |
---|
468 | { |
---|
469 | printf( "Failed to write to '%s'\n", s ); |
---|
470 | exit( EXITBAD ); |
---|
471 | } |
---|
472 | globs.noexec++; |
---|
473 | } |
---|
474 | |
---|
475 | /* Now make target */ |
---|
476 | |
---|
477 | { |
---|
478 | PROFILE_ENTER(MAIN_MAKE); |
---|
479 | |
---|
480 | LIST* targets = targets_to_update(); |
---|
481 | if ( !targets ) |
---|
482 | { |
---|
483 | status |= make( 1, &all, anyhow ); |
---|
484 | } |
---|
485 | else |
---|
486 | { |
---|
487 | int targets_count = list_length(targets); |
---|
488 | const char **targets2 = (const char **)malloc(targets_count * sizeof(char *)); |
---|
489 | int n = 0; |
---|
490 | if ( DEBUG_PROFILE ) |
---|
491 | profile_memory( targets_count * sizeof(char *) ); |
---|
492 | for ( ; targets; targets = list_next(targets) ) |
---|
493 | { |
---|
494 | targets2[n++] = targets->string; |
---|
495 | } |
---|
496 | status |= make( targets_count, targets2, anyhow ); |
---|
497 | free(targets); |
---|
498 | } |
---|
499 | |
---|
500 | PROFILE_EXIT(MAIN_MAKE); |
---|
501 | } |
---|
502 | |
---|
503 | |
---|
504 | PROFILE_EXIT(MAIN); } |
---|
505 | |
---|
506 | if ( DEBUG_PROFILE ) |
---|
507 | profile_dump(); |
---|
508 | |
---|
509 | /* Widely scattered cleanup */ |
---|
510 | |
---|
511 | var_done(); |
---|
512 | file_done(); |
---|
513 | donerules(); |
---|
514 | donestamps(); |
---|
515 | donestr(); |
---|
516 | |
---|
517 | /* close cmdout */ |
---|
518 | |
---|
519 | if( globs.cmdout ) |
---|
520 | fclose( globs.cmdout ); |
---|
521 | |
---|
522 | #ifdef HAVE_PYTHON |
---|
523 | Py_Finalize(); |
---|
524 | #endif |
---|
525 | |
---|
526 | |
---|
527 | return status ? EXITBAD : EXITOK; |
---|
528 | } |
---|