3 * +\ Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
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
12 * ALL WARRANTIES ARE HEREBY DISCLAIMED.
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)
24 * See Jam.html for usage information.
26 * These comments document the code.
28 * The top half of the code is structured such:
42 * jambase parse | rules search make1
46 * builtins timestamp command execute
53 * The support routines are called by all of the above, but themselves
70 * Roughly, the modules are:
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
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
109 #include "patchlevel.h"
111 /* These get various function declarations. */
114 #include "variable.h"
116 #include "builtins.h"
120 #include "timestamp.h"
127 /* Macintosh is "special" */
129 #include <QuickDraw.h>
132 /* And UNIX for this. */
134 #include <sys/utsname.h>
144 0, /* pipes action stdout and stderr merged to action output */
146 { 0, 0 }, /* debug - suppress tracing output */
148 { 0, 1 }, /* debug ... */
150 0, /* output commands, not run them */
151 0 /* action timeout */
154 /* Symbols to be defined as true for use in Jambase. */
155 static char * othersyms[] = { OSMAJOR, OSMINOR, OSPLAT, JAMVERSYM, 0 };
159 * mac needs arg_enviro
160 * OS2 needs extern environ
164 #define use_environ arg_environ
171 #if defined( OS_NT ) && defined( __LCC__ )
172 #define use_environ _environ
175 # if defined( __MWERKS__)
176 #define use_environ _environ
177 extern char * * _environ;
181 #define use_environ environ
182 #if !defined( __WATCOM__ ) && !defined( OS_OS2 ) && !defined( OS_NT )
183 extern char **environ;
192 static void run_unit_tests()
194 #if defined( USE_EXECNT )
195 extern void execnt_unit_test();
199 var_expand_unit_test();
206 extern PyObject * bjam_call ( PyObject * self, PyObject * args );
207 extern PyObject * bjam_import_rule ( PyObject * self, PyObject * args );
208 extern PyObject * bjam_define_action( PyObject * self, PyObject * args );
209 extern PyObject * bjam_variable ( PyObject * self, PyObject * args );
210 extern PyObject * bjam_backtrace ( PyObject * self, PyObject * args );
211 extern PyObject * bjam_caller ( PyObject * self, PyObject * args );
216 int main( int argc, char * * argv, char * * arg_environ )
220 struct bjam_option optv[N_OPTS];
221 char const * all = "all";
224 char * * arg_v = argv;
225 char const * progname = argv[0];
227 saved_argv0 = argv[0];
232 InitGraf(&qd.thePort);
238 if ( getoptions( argc, argv, "-:l:d:j:p:f:gs:t:ano:qv", optv ) < 0 )
240 printf( "\nusage: %s [ options ] targets...\n\n", progname );
242 printf( "-a Build all targets, even if they are current.\n" );
243 printf( "-dx Set the debug level to x (0-9).\n" );
244 printf( "-fx Read x instead of Jambase.\n" );
245 /* printf( "-g Build from newest sources first.\n" ); */
246 printf( "-jx Run up to x shell commands concurrently.\n" );
247 printf( "-lx Limit actions to x number of seconds after which they are stopped.\n" );
248 printf( "-n Don't actually execute the updating actions.\n" );
249 printf( "-ox Write the updating actions to file x.\n" );
250 printf( "-px x=0, pipes action stdout and stderr merged into action output.\n" );
251 printf( "-q Quit quickly as soon as a target fails.\n" );
252 printf( "-sx=y Set variable x=y, overriding environment.\n" );
253 printf( "-tx Rebuild x, even if it is up-to-date.\n" );
254 printf( "-v Print the version of jam and exit.\n" );
255 printf( "--x Option is ignored.\n\n" );
261 if ( ( s = getoptval( optv, 'v', 0 ) ) )
263 printf( "Boost.Jam " );
264 printf( "Version %s. %s.\n", VERSION, OSMINOR );
265 printf( " Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. \n" );
266 printf( " Copyright 2001 David Turner.\n" );
267 printf( " Copyright 2001-2004 David Abrahams.\n" );
268 printf( " Copyright 2002-2008 Rene Rivera.\n" );
269 printf( " Copyright 2003-2008 Vladimir Prus.\n" );
274 /* Pick up interesting options. */
275 if ( ( s = getoptval( optv, 'n', 0 ) ) )
276 globs.noexec++, globs.debug[2] = 1;
278 if ( ( s = getoptval( optv, 'p', 0 ) ) )
280 /* Undocumented -p3 (acts like both -p1 -p2) means separate pipe action
283 globs.pipe_action = atoi( s );
284 if ( ( 3 < globs.pipe_action ) || ( globs.pipe_action < 0 ) )
287 "Invalid pipe descriptor '%d', valid values are -p[0..3].\n",
293 if ( ( s = getoptval( optv, 'q', 0 ) ) )
296 if ( ( s = getoptval( optv, 'a', 0 ) ) )
299 if ( ( s = getoptval( optv, 'j', 0 ) ) )
301 globs.jobs = atoi( s );
304 printf("Invalid value for the '-j' option.\n");
309 if ( ( s = getoptval( optv, 'g', 0 ) ) )
310 globs.newestfirst = 1;
312 if ( ( s = getoptval( optv, 'l', 0 ) ) )
313 globs.timeout = atoi( s );
315 /* Turn on/off debugging */
316 for ( n = 0; ( s = getoptval( optv, 'd', n ) ); ++n )
320 /* First -d, turn off defaults. */
322 for ( i = 0; i < DEBUG_MAX; ++i )
327 if ( ( i < 0 ) || ( i >= DEBUG_MAX ) )
329 printf( "Invalid debug level '%s'.\n", s );
333 /* n turns on levels 1-n. */
334 /* +n turns on level n. */
338 globs.debug[i--] = 1;
342 PROFILE_ENTER( MAIN );
346 PROFILE_ENTER( MAIN_PYTHON );
349 static PyMethodDef BjamMethods[] = {
350 {"call", bjam_call, METH_VARARGS,
351 "Call the specified bjam rule."},
352 {"import_rule", bjam_import_rule, METH_VARARGS,
353 "Imports Python callable to bjam."},
354 {"define_action", bjam_define_action, METH_VARARGS,
355 "Defines a command line action."},
356 {"variable", bjam_variable, METH_VARARGS,
357 "Obtains a variable from bjam's global module."},
358 {"backtrace", bjam_backtrace, METH_VARARGS,
359 "Returns bjam backtrace from the last call into Python."},
360 {"caller", bjam_caller, METH_VARARGS,
361 "Returns the module from which the last call into Python is made."},
362 {NULL, NULL, 0, NULL}
365 Py_InitModule( "bjam", BjamMethods );
367 PROFILE_EXIT( MAIN_PYTHON );
380 var_set( "JAMDATE", list_new( L0, outf_time(time(0)) ), VAR_SET );
382 /* Set JAM_VERSION. */
383 var_set( "JAM_VERSION",
384 list_new( list_new( list_new( L0,
385 newstr( VERSION_MAJOR_SYM ) ),
386 newstr( VERSION_MINOR_SYM ) ),
387 newstr( VERSION_PATCH_SYM ) ),
395 if ( uname( &u ) >= 0 )
403 newstr( u.sysname ) ),
404 newstr( u.nodename ) ),
405 newstr( u.release ) ),
406 newstr( u.version ) ),
407 newstr( u.machine ) ), VAR_SET );
412 /* Load up environment variables. */
414 /* First into the global module, with splitting, for backward
417 var_defines( use_environ, 1 );
419 /* Then into .ENVIRON, without splitting. */
420 enter_module( bindmodule(".ENVIRON") );
421 var_defines( use_environ, 0 );
422 exit_module( bindmodule(".ENVIRON") );
425 * Jam defined variables OS & OSPLAT. We load them after environment, so
426 * that setting OS in environment does not change Jam's notion of the
429 var_defines( othersyms, 1 );
431 /* Load up variables set on command line. */
432 for ( n = 0; ( s = getoptval( optv, 's', n ) ); ++n )
437 var_defines( symv, 1 );
438 enter_module( bindmodule(".ENVIRON") );
439 var_defines( symv, 0 );
440 exit_module( bindmodule(".ENVIRON") );
443 /* Set the ARGV to reflect the complete list of arguments of invocation.
445 for ( n = 0; n < arg_c; ++n )
446 var_set( "ARGV", list_new( L0, newstr( arg_v[n] ) ), VAR_APPEND );
448 /* Initialize built-in rules. */
451 /* Add the targets in the command line to the update list. */
452 for ( n = 1; n < arg_c; ++n )
454 if ( arg_v[ n ][ 0 ] == '-' )
456 char * f = "-:l:d:j:f:gs:t:ano:qv";
457 for ( ; *f; ++f ) if ( *f == arg_v[ n ][ 1 ] ) break;
458 if ( ( f[ 1 ] == ':' ) && ( arg_v[ n ][ 2 ] == '\0' ) ) ++n;
462 mark_target_for_updating( arg_v[ n ] );
466 if (!targets_to_update())
467 mark_target_for_updating("all");
473 for ( n = 0; ( s = getoptval( optv, 'f', n ) ); ++n )
474 parse_file( s, frame );
477 parse_file( "+", frame );
480 status = yyanyerrors();
482 /* Manually touch -t targets. */
483 for ( n = 0; ( s = getoptval( optv, 't', n ) ); ++n )
486 /* If an output file is specified, set globs.cmdout to that. */
487 if ( ( s = getoptval( optv, 'o', 0 ) ) )
489 if ( !( globs.cmdout = fopen( s, "w" ) ) )
491 printf( "Failed to write to '%s'\n", s );
497 /* The build system may set the PARALLELISM variable to override -j
501 p = var_get ("PARALLELISM");
504 int j = atoi (p->string);
507 printf( "Invalid value of PARALLELISM: %s\n", p->string);
516 /* KEEP_GOING overrides -q option. */
519 p = var_get ("KEEP_GOING");
522 int v = atoi (p->string);
530 /* Now make target. */
532 PROFILE_ENTER( MAIN_MAKE );
534 LIST * targets = targets_to_update();
537 int targets_count = list_length( targets );
538 const char * * targets2 = (const char * *)
539 BJAM_MALLOC( targets_count * sizeof( char * ) );
541 for ( ; targets; targets = list_next( targets ) )
542 targets2[ n++ ] = targets->string;
543 status |= make( targets_count, targets2, anyhow );
548 status = last_update_now_status;
551 PROFILE_EXIT( MAIN_MAKE );
554 PROFILE_EXIT( MAIN );
560 /* Widely scattered cleanup. */
569 fclose( globs.cmdout );
577 return status ? EXITBAD : EXITOK;
582 char *executable_path(char *argv0) {
584 DWORD ret = GetModuleFileName(NULL, buf, sizeof(buf));
585 if (ret == 0 || ret == sizeof(buf)) return NULL;
588 #elif defined(__APPLE__) /* Not tested */
589 #include <mach-o/dyld.h>
590 char *executable_path(char *argv0) {
592 uint32_t size = sizeof(buf);
593 int ret = _NSGetExecutablePath(buf, &size);
594 if (ret != 0) return NULL;
597 #elif defined(sun) || defined(__sun) /* Not tested */
600 char *executable_path(char *argv0) {
601 return strdup(getexecname());
603 #elif defined(__FreeBSD__)
604 #include <sys/sysctl.h>
605 char *executable_path(char *argv0) {
609 mib[2] = KERN_PROC_PATHNAME;
612 size_t size = sizeof(buf);
613 sysctl(mib, 4, buf, &size, NULL, 0);
614 if (size == 0 || size == sizeof(buf)) return NULL;
615 return strndup(buf, size);
617 #elif defined(__linux__)
619 char *executable_path(char *argv0) {
621 ssize_t ret = readlink("/proc/self/exe", buf, sizeof(buf));
622 if (ret == 0 || ret == sizeof(buf)) return NULL;
623 return strndup(buf, ret);
626 char *executable_path(char *argv0) {
627 /* If argv0 is absolute path, assume it's the right absolute path. */
629 return strdup(argv0);