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 freely, as
9 * long as this copyright notice is retained and modifications are clearly
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 copy at
19 * http://www.boost.org/LICENSE_1_0.txt)
25 * See Jam.html for usage information.
27 * These comments document the code.
29 * The top half of the code is structured such:
43 * jambase parse | rules search make1
47 * builtins timestamp command execute
54 * The support routines are called by all of the above, but themselves are
71 * Roughly, the modules are:
73 * builtins.c - jam's built-in rules
74 * command.c - maintain lists of commands
75 * compile.c - compile parsed jam statements
76 * exec*.c - execute a shell script on a specific OS
77 * file*.c - scan directories and archives on a specific OS
78 * hash.c - simple in-memory hashing routines
79 * hdrmacro.c - handle header file parsing for filename macro definitions
80 * headers.c - handle #includes in source files
81 * jambase.c - compilable copy of Jambase
82 * jamgram.y - jam grammar
83 * lists.c - maintain lists of strings
84 * make.c - bring a target up to date, once rules are in place
85 * make1.c - execute command to bring targets up to date
86 * object.c - string manipulation routines
87 * option.c - command line option processing
88 * parse.c - make and destroy parse trees as driven by the parser
89 * path*.c - manipulate file names on a specific OS
90 * hash.c - simple in-memory hashing routines
91 * regexp.c - Henry Spencer's regexp
92 * rules.c - access to RULEs, TARGETs, and ACTIONs
93 * scan.c - the jam yacc scanner
94 * search.c - find a target along $(SEARCH) or $(LOCATE)
95 * timestamp.c - get the timestamp of a file or archive member
96 * variable.c - handle jam multi-element variables
101 #include "patchlevel.h"
103 #include "builtins.h"
106 #include "constants.h"
107 #include "debugger.h"
109 #include "function.h"
122 #include "timestamp.h"
123 #include "variable.h"
126 /* Macintosh is "special" */
128 # include <QuickDraw.h>
131 /* And UNIX for this. */
133 # include <sys/utsname.h>
143 0, /* pipes action stdout and stderr merged to action output */
145 { 0, 0 }, /* debug - suppress tracing output */
147 { 0, 1 }, /* debug ... */
149 0, /* output commands, not run them */
150 0, /* action timeout */
151 0 /* maximum buffer size zero is all output */
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
172 # define use_environ arg_environ
177 #if defined( OS_NT ) && defined( __LCC__ )
178 # define use_environ _environ
181 #if defined( __MWERKS__)
182 # define use_environ _environ
183 extern char * * _environ
;
187 # define use_environ environ
188 # if !defined( __WATCOM__ ) && !defined( OS_OS2 ) && !defined( OS_NT )
189 extern char **environ
;
198 static void run_unit_tests()
200 # if defined( USE_EXECNT )
201 extern void execnt_unit_test();
211 extern PyObject
* bjam_call ( PyObject
* self
, PyObject
* args
);
212 extern PyObject
* bjam_import_rule ( PyObject
* self
, PyObject
* args
);
213 extern PyObject
* bjam_define_action( PyObject
* self
, PyObject
* args
);
214 extern PyObject
* bjam_variable ( PyObject
* self
, PyObject
* args
);
215 extern PyObject
* bjam_backtrace ( PyObject
* self
, PyObject
* args
);
216 extern PyObject
* bjam_caller ( PyObject
* self
, PyObject
* args
);
217 int python_optimize
= 1; /* Set Python optimzation on by default */
222 char const * saved_argv0
;
224 static void usage( const char * progname
)
226 err_printf("\nusage: %s [ options ] targets...\n\n", progname
);
228 err_printf("-a Build all targets, even if they are current.\n");
229 err_printf("-dx Set the debug level to x (0-13,console,mi).\n");
230 err_printf("-fx Read x instead of Jambase.\n");
231 /* err_printf( "-g Build from newest sources first.\n" ); */
232 err_printf("-jx Run up to x shell commands concurrently.\n");
233 err_printf("-lx Limit actions to x number of seconds after which they are stopped.\n");
234 err_printf("-mx Maximum target output saved (kb), default is to save all output.\n");
235 err_printf("-n Don't actually execute the updating actions.\n");
236 err_printf("-ox Mirror all output to file x.\n");
237 err_printf("-px x=0, pipes action stdout and stderr merged into action output.\n");
238 err_printf("-q Quit quickly as soon as a target fails.\n");
239 err_printf("-sx=y Set variable x=y, overriding environment.\n");
240 err_printf("-tx Rebuild x, even if it is up-to-date.\n");
241 err_printf("-v Print the version of jam and exit.\n");
243 err_printf("-z Disable Python Optimization and enable asserts\n");
245 err_printf("--x Option is ignored.\n\n");
250 int main( int argc
, char * * argv
, char * * arg_environ
)
254 struct bjam_option optv
[ N_OPTS
];
255 char const * all
= "all";
258 char * * arg_v
= argv
;
259 char const * progname
= argv
[ 0 ];
260 module_t
* environ_module
;
263 saved_argv0
= argv
[ 0 ];
268 InitGraf( &qd
.thePort
);
278 if ( getoptions( argc
- 1, argv
+ 1, "-:l:m:d:j:p:f:gs:t:ano:qv", optv
) < 0 )
281 if ( ( s
= getoptval( optv
, 'd', 0 ) ) )
283 if ( strcmp( s
, "mi" ) == 0 )
285 debug_interface
= DEBUG_INTERFACE_MI
;
288 else if ( strcmp( s
, "console" ) == 0 )
290 debug_interface
= DEBUG_INTERFACE_CONSOLE
;
299 /* Check whether this instance is being run by the debugger. */
300 size_t opt_len
= strlen( debugger_opt
);
301 if ( strncmp( argv
[ 1 ], debugger_opt
, opt_len
) == 0 &&
302 strncmp( argv
[ 2 ], debugger_opt
, opt_len
) == 0 )
304 debug_init_handles( argv
[ 1 ] + opt_len
, argv
[ 2 ] + opt_len
);
305 /* Fix up argc/argv to hide the internal options */
306 arg_c
= argc
= (argc
- 2);
307 argv
[ 2 ] = argv
[ 0 ];
308 arg_v
= argv
= (argv
+ 2);
309 debug_interface
= DEBUG_INTERFACE_CHILD
;
322 if ( setjmp( debug_child_data
.jmp
) != 0 )
324 arg_c
= argc
= debug_child_data
.argc
;
325 arg_v
= argv
= (char * *)debug_child_data
.argv
;
326 debug_interface
= DEBUG_INTERFACE_CHILD
;
342 #define OPTSTRING "-:l:m:d:j:p:f:gs:t:ano:qvz"
344 #define OPTSTRING "-:l:m:d:j:p:f:gs:t:ano:qv"
347 if ( getoptions( argc
, argv
, OPTSTRING
, optv
) < 0 )
353 if ( ( s
= getoptval( optv
, 'v', 0 ) ) )
355 out_printf( "Boost.Jam Version %s. %s.\n", VERSION
, OSMINOR
);
356 out_printf( " Copyright 1993-2002 Christopher Seiwald and Perforce "
357 "Software, Inc.\n" );
358 out_printf( " Copyright 2001 David Turner.\n" );
359 out_printf( " Copyright 2001-2004 David Abrahams.\n" );
360 out_printf( " Copyright 2002-2015 Rene Rivera.\n" );
361 out_printf( " Copyright 2003-2015 Vladimir Prus.\n" );
365 /* Pick up interesting options. */
366 if ( ( s
= getoptval( optv
, 'n', 0 ) ) )
369 globs
.debug
[ 2 ] = 1;
372 if ( ( s
= getoptval( optv
, 'p', 0 ) ) )
374 /* Undocumented -p3 (acts like both -p1 -p2) means separate pipe action
377 globs
.pipe_action
= atoi( s
);
378 if ( globs
.pipe_action
< 0 || 3 < globs
.pipe_action
)
380 err_printf( "Invalid pipe descriptor '%d', valid values are -p[0..3]."
381 "\n", globs
.pipe_action
);
386 if ( ( s
= getoptval( optv
, 'q', 0 ) ) )
389 if ( ( s
= getoptval( optv
, 'a', 0 ) ) )
392 if ( ( s
= getoptval( optv
, 'j', 0 ) ) )
394 globs
.jobs
= atoi( s
);
395 if ( globs
.jobs
< 1 )
397 err_printf( "Invalid value for the '-j' option.\n" );
402 if ( ( s
= getoptval( optv
, 'g', 0 ) ) )
403 globs
.newestfirst
= 1;
405 if ( ( s
= getoptval( optv
, 'l', 0 ) ) )
406 globs
.timeout
= atoi( s
);
408 if ( ( s
= getoptval( optv
, 'm', 0 ) ) )
409 globs
.max_buf
= atoi( s
) * 1024; /* convert to kb */
412 if ( ( s
= getoptval( optv
, 'z', 0 ) ) )
413 python_optimize
= 0; /* disable python optimization */
416 /* Turn on/off debugging */
417 for ( n
= 0; ( s
= getoptval( optv
, 'd', n
) ); ++n
)
421 /* First -d, turn off defaults. */
423 for ( i
= 0; i
< DEBUG_MAX
; ++i
)
428 if ( ( i
< 0 ) || ( i
>= DEBUG_MAX
) )
430 out_printf( "Invalid debug level '%s'.\n", s
);
434 /* n turns on levels 1-n. */
435 /* +n turns on level n. */
437 globs
.debug
[ i
] = 1;
439 globs
.debug
[ i
-- ] = 1;
442 /* If an output file is specified, set globs.out to that. */
443 if ( ( s
= getoptval( optv
, 'o', 0 ) ) )
445 if ( !( globs
.out
= fopen( s
, "w" ) ) )
447 err_printf( "Failed to write to '%s'\n", s
);
450 /* ++globs.noexec; */
454 PROFILE_ENTER( MAIN
);
458 PROFILE_ENTER( MAIN_PYTHON
);
459 Py_OptimizeFlag
= python_optimize
;
462 static PyMethodDef BjamMethods
[] = {
463 {"call", bjam_call
, METH_VARARGS
,
464 "Call the specified bjam rule."},
465 {"import_rule", bjam_import_rule
, METH_VARARGS
,
466 "Imports Python callable to bjam."},
467 {"define_action", bjam_define_action
, METH_VARARGS
,
468 "Defines a command line action."},
469 {"variable", bjam_variable
, METH_VARARGS
,
470 "Obtains a variable from bjam's global module."},
471 {"backtrace", bjam_backtrace
, METH_VARARGS
,
472 "Returns bjam backtrace from the last call into Python."},
473 {"caller", bjam_caller
, METH_VARARGS
,
474 "Returns the module from which the last call into Python is made."},
475 {NULL
, NULL
, 0, NULL
}
478 Py_InitModule( "bjam", BjamMethods
);
480 PROFILE_EXIT( MAIN_PYTHON
);
495 timestamp_current( ¤t
);
496 var_set( root_module(), constant_JAMDATE
, list_new( outf_time(
497 ¤t
) ), VAR_SET
);
500 /* Set JAM_VERSION. */
501 var_set( root_module(), constant_JAM_VERSION
,
502 list_push_back( list_push_back( list_new(
503 object_new( VERSION_MAJOR_SYM
) ),
504 object_new( VERSION_MINOR_SYM
) ),
505 object_new( VERSION_PATCH_SYM
) ),
513 if ( uname( &u
) >= 0 )
515 var_set( root_module(), constant_JAMUNAME
,
521 object_new( u
.sysname
) ),
522 object_new( u
.nodename
) ),
523 object_new( u
.release
) ),
524 object_new( u
.version
) ),
525 object_new( u
.machine
) ), VAR_SET
);
530 /* Set JAM_TIMESTAMP_RESOLUTION. */
532 timestamp fmt_resolution
[ 1 ];
533 file_supported_fmt_resolution( fmt_resolution
);
534 var_set( root_module(), constant_JAM_TIMESTAMP_RESOLUTION
, list_new(
535 object_new( timestamp_timestr( fmt_resolution
) ) ), VAR_SET
);
538 /* Load up environment variables. */
540 /* First into the global module, with splitting, for backward
543 var_defines( root_module(), use_environ
, 1 );
545 environ_module
= bindmodule( constant_ENVIRON
);
546 /* Then into .ENVIRON, without splitting. */
547 var_defines( environ_module
, use_environ
, 0 );
550 * Jam defined variables OS & OSPLAT. We load them after environment, so
551 * that setting OS in environment does not change Jam's notion of the
554 var_defines( root_module(), othersyms
, 1 );
556 /* Load up variables set on command line. */
557 for ( n
= 0; ( s
= getoptval( optv
, 's', n
) ); ++n
)
562 var_defines( root_module(), symv
, 1 );
563 var_defines( environ_module
, symv
, 0 );
566 /* Set the ARGV to reflect the complete list of arguments of invocation.
568 for ( n
= 0; n
< arg_c
; ++n
)
569 var_set( root_module(), constant_ARGV
, list_new( object_new(
570 arg_v
[ n
] ) ), VAR_APPEND
);
572 /* Initialize built-in rules. */
575 /* Add the targets in the command line to the update list. */
576 for ( n
= 1; n
< arg_c
; ++n
)
578 if ( arg_v
[ n
][ 0 ] == '-' )
580 char * f
= "-:l:d:j:f:gs:t:ano:qv";
581 for ( ; *f
; ++f
) if ( *f
== arg_v
[ n
][ 1 ] ) break;
582 if ( ( f
[ 1 ] == ':' ) && ( arg_v
[ n
][ 2 ] == '\0' ) ) ++n
;
586 OBJECT
* const target
= object_new( arg_v
[ n
] );
587 mark_target_for_updating( target
);
588 object_free( target
);
592 if ( list_empty( targets_to_update() ) )
593 mark_target_for_updating( constant_all
);
599 for ( n
= 0; ( s
= getoptval( optv
, 'f', n
) ); ++n
)
601 OBJECT
* const filename
= object_new( s
);
602 parse_file( filename
, frame
);
603 object_free( filename
);
607 parse_file( constant_plus
, frame
);
610 status
= yyanyerrors();
612 /* Manually touch -t targets. */
613 for ( n
= 0; ( s
= getoptval( optv
, 't', n
) ); ++n
)
615 OBJECT
* const target
= object_new( s
);
616 touch_target( target
);
617 object_free( target
);
620 /* The build system may set the PARALLELISM variable to override -j
624 LIST
* const p
= var_get( root_module(), constant_PARALLELISM
);
625 if ( !list_empty( p
) )
627 int const j
= atoi( object_str( list_front( p
) ) );
629 out_printf( "Invalid value of PARALLELISM: %s.\n",
630 object_str( list_front( p
) ) );
636 /* KEEP_GOING overrides -q option. */
638 LIST
* const p
= var_get( root_module(), constant_KEEP_GOING
);
639 if ( !list_empty( p
) )
640 globs
.quitquick
= atoi( object_str( list_front( p
) ) ) ? 0 : 1;
643 /* Now make target. */
645 PROFILE_ENTER( MAIN_MAKE
);
646 LIST
* const targets
= targets_to_update();
647 if ( !list_empty( targets
) )
648 status
|= make( targets
, anyhow
);
650 status
= last_update_now_status
;
651 PROFILE_EXIT( MAIN_MAKE
);
654 PROFILE_EXIT( MAIN
);
661 #ifdef OPT_HEADER_CACHE_EXT
665 clear_targets_to_update();
667 /* Widely scattered cleanup. */
694 return status
? EXITBAD
: EXITOK
;
703 # define WIN32_LEAN_AND_MEAN
704 # include <windows.h>
705 char * executable_path( char const * argv0
)
708 DWORD
const ret
= GetModuleFileName( NULL
, buf
, sizeof( buf
) );
709 return ( !ret
|| ret
== sizeof( buf
) ) ? NULL
: strdup( buf
);
711 #elif defined(__APPLE__) /* Not tested */
712 # include <mach-o/dyld.h>
713 char *executable_path( char const * argv0
)
716 uint32_t size
= sizeof( buf
);
717 return _NSGetExecutablePath( buf
, &size
) ? NULL
: strdup( buf
);
719 #elif defined(sun) || defined(__sun) /* Not tested */
721 char * executable_path( char const * argv0
)
723 const char * execname
= getexecname();
724 return execname
? strdup( execname
) : NULL
;
726 #elif defined(__FreeBSD__)
727 # include <sys/sysctl.h>
728 char * executable_path( char const * argv0
)
730 int mib
[ 4 ] = { CTL_KERN
, KERN_PROC
, KERN_PROC_PATHNAME
, -1 };
732 size_t size
= sizeof( buf
);
733 sysctl( mib
, 4, buf
, &size
, NULL
, 0 );
734 return ( !size
|| size
== sizeof( buf
) ) ? NULL
: strndup( buf
, size
);
736 #elif defined(__linux__)
738 char * executable_path( char const * argv0
)
741 ssize_t
const ret
= readlink( "/proc/self/exe", buf
, sizeof( buf
) );
742 return ( !ret
|| ret
== sizeof( buf
) ) ? NULL
: strndup( buf
, ret
);
744 #elif defined(OS_VMS)
745 # include <unixlib.h>
746 char * executable_path( char const * argv0
)
748 char * vms_path
= NULL
;
749 char * posix_path
= NULL
;
752 /* On VMS argv[0] shows absolute path to the image file.
753 * So, just remove VMS file version and translate path to POSIX-style.
755 vms_path
= strdup( argv0
);
756 if ( vms_path
&& ( p
= strchr( vms_path
, ';') ) ) *p
= '\0';
757 posix_path
= decc$
translate_vms( vms_path
);
758 if ( vms_path
) free( vms_path
);
760 return posix_path
> 0 ? strdup( posix_path
) : NULL
;
763 char * executable_path( char const * argv0
)
765 /* If argv0 is an absolute path, assume it is the right absolute path. */
766 return argv0
[ 0 ] == '/' ? strdup( argv0
) : NULL
;