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
);
277 if ( getoptions( argc
- 1, argv
+ 1, "-:l:m:d:j:p:f:gs:t:ano:qv", optv
) < 0 )
280 if ( ( s
= getoptval( optv
, 'd', 0 ) ) )
282 if ( strcmp( s
, "mi" ) == 0 )
284 debug_interface
= DEBUG_INTERFACE_MI
;
287 else if ( strcmp( s
, "console" ) == 0 )
289 debug_interface
= DEBUG_INTERFACE_CONSOLE
;
298 /* Check whether this instance is being run by the debugger. */
299 size_t opt_len
= strlen( debugger_opt
);
300 if ( strncmp( argv
[ 1 ], debugger_opt
, opt_len
) == 0 &&
301 strncmp( argv
[ 2 ], debugger_opt
, opt_len
) == 0 )
303 debug_init_handles( argv
[ 1 ] + opt_len
, argv
[ 2 ] + opt_len
);
304 /* Fix up argc/argv to hide the internal options */
305 arg_c
= argc
= (argc
- 2);
306 argv
[ 2 ] = argv
[ 0 ];
307 arg_v
= argv
= (argv
+ 2);
308 debug_interface
= DEBUG_INTERFACE_CHILD
;
321 if ( setjmp( debug_child_data
.jmp
) != 0 )
323 arg_c
= argc
= debug_child_data
.argc
;
324 arg_v
= argv
= (char * *)debug_child_data
.argv
;
325 debug_interface
= DEBUG_INTERFACE_CHILD
;
341 #define OPTSTRING "-:l:m:d:j:p:f:gs:t:ano:qvz"
343 #define OPTSTRING "-:l:m:d:j:p:f:gs:t:ano:qv"
346 if ( getoptions( argc
, argv
, OPTSTRING
, optv
) < 0 )
352 if ( ( s
= getoptval( optv
, 'v', 0 ) ) )
354 out_printf( "Boost.Jam Version %s. %s.\n", VERSION
, OSMINOR
);
355 out_printf( " Copyright 1993-2002 Christopher Seiwald and Perforce "
356 "Software, Inc.\n" );
357 out_printf( " Copyright 2001 David Turner.\n" );
358 out_printf( " Copyright 2001-2004 David Abrahams.\n" );
359 out_printf( " Copyright 2002-2015 Rene Rivera.\n" );
360 out_printf( " Copyright 2003-2015 Vladimir Prus.\n" );
364 /* Pick up interesting options. */
365 if ( ( s
= getoptval( optv
, 'n', 0 ) ) )
368 globs
.debug
[ 2 ] = 1;
371 if ( ( s
= getoptval( optv
, 'p', 0 ) ) )
373 /* Undocumented -p3 (acts like both -p1 -p2) means separate pipe action
376 globs
.pipe_action
= atoi( s
);
377 if ( globs
.pipe_action
< 0 || 3 < globs
.pipe_action
)
379 err_printf( "Invalid pipe descriptor '%d', valid values are -p[0..3]."
380 "\n", globs
.pipe_action
);
385 if ( ( s
= getoptval( optv
, 'q', 0 ) ) )
388 if ( ( s
= getoptval( optv
, 'a', 0 ) ) )
391 if ( ( s
= getoptval( optv
, 'j', 0 ) ) )
393 globs
.jobs
= atoi( s
);
394 if ( globs
.jobs
< 1 )
396 err_printf( "Invalid value for the '-j' option.\n" );
401 if ( ( s
= getoptval( optv
, 'g', 0 ) ) )
402 globs
.newestfirst
= 1;
404 if ( ( s
= getoptval( optv
, 'l', 0 ) ) )
405 globs
.timeout
= atoi( s
);
407 if ( ( s
= getoptval( optv
, 'm', 0 ) ) )
408 globs
.max_buf
= atoi( s
) * 1024; /* convert to kb */
411 if ( ( s
= getoptval( optv
, 'z', 0 ) ) )
412 python_optimize
= 0; /* disable python optimization */
415 /* Turn on/off debugging */
416 for ( n
= 0; ( s
= getoptval( optv
, 'd', n
) ); ++n
)
420 /* First -d, turn off defaults. */
422 for ( i
= 0; i
< DEBUG_MAX
; ++i
)
427 if ( ( i
< 0 ) || ( i
>= DEBUG_MAX
) )
429 out_printf( "Invalid debug level '%s'.\n", s
);
433 /* n turns on levels 1-n. */
434 /* +n turns on level n. */
436 globs
.debug
[ i
] = 1;
438 globs
.debug
[ i
-- ] = 1;
441 /* If an output file is specified, set globs.out to that. */
442 if ( ( s
= getoptval( optv
, 'o', 0 ) ) )
444 if ( !( globs
.out
= fopen( s
, "w" ) ) )
446 err_printf( "Failed to write to '%s'\n", s
);
449 /* ++globs.noexec; */
455 PROFILE_ENTER( MAIN
);
459 PROFILE_ENTER( MAIN_PYTHON
);
460 Py_OptimizeFlag
= python_optimize
;
463 static PyMethodDef BjamMethods
[] = {
464 {"call", bjam_call
, METH_VARARGS
,
465 "Call the specified bjam rule."},
466 {"import_rule", bjam_import_rule
, METH_VARARGS
,
467 "Imports Python callable to bjam."},
468 {"define_action", bjam_define_action
, METH_VARARGS
,
469 "Defines a command line action."},
470 {"variable", bjam_variable
, METH_VARARGS
,
471 "Obtains a variable from bjam's global module."},
472 {"backtrace", bjam_backtrace
, METH_VARARGS
,
473 "Returns bjam backtrace from the last call into Python."},
474 {"caller", bjam_caller
, METH_VARARGS
,
475 "Returns the module from which the last call into Python is made."},
476 {NULL
, NULL
, 0, NULL
}
479 Py_InitModule( "bjam", BjamMethods
);
481 PROFILE_EXIT( MAIN_PYTHON
);
496 timestamp_current( ¤t
);
497 var_set( root_module(), constant_JAMDATE
, list_new( outf_time(
498 ¤t
) ), VAR_SET
);
501 /* Set JAM_VERSION. */
502 var_set( root_module(), constant_JAM_VERSION
,
503 list_push_back( list_push_back( list_new(
504 object_new( VERSION_MAJOR_SYM
) ),
505 object_new( VERSION_MINOR_SYM
) ),
506 object_new( VERSION_PATCH_SYM
) ),
514 if ( uname( &u
) >= 0 )
516 var_set( root_module(), constant_JAMUNAME
,
522 object_new( u
.sysname
) ),
523 object_new( u
.nodename
) ),
524 object_new( u
.release
) ),
525 object_new( u
.version
) ),
526 object_new( u
.machine
) ), VAR_SET
);
531 /* Set JAM_TIMESTAMP_RESOLUTION. */
533 timestamp fmt_resolution
[ 1 ];
534 file_supported_fmt_resolution( fmt_resolution
);
535 var_set( root_module(), constant_JAM_TIMESTAMP_RESOLUTION
, list_new(
536 object_new( timestamp_timestr( fmt_resolution
) ) ), VAR_SET
);
539 /* Load up environment variables. */
541 /* First into the global module, with splitting, for backward
544 var_defines( root_module(), use_environ
, 1 );
546 environ_module
= bindmodule( constant_ENVIRON
);
547 /* Then into .ENVIRON, without splitting. */
548 var_defines( environ_module
, use_environ
, 0 );
551 * Jam defined variables OS & OSPLAT. We load them after environment, so
552 * that setting OS in environment does not change Jam's notion of the
555 var_defines( root_module(), othersyms
, 1 );
557 /* Load up variables set on command line. */
558 for ( n
= 0; ( s
= getoptval( optv
, 's', n
) ); ++n
)
563 var_defines( root_module(), symv
, 1 );
564 var_defines( environ_module
, symv
, 0 );
567 /* Set the ARGV to reflect the complete list of arguments of invocation.
569 for ( n
= 0; n
< arg_c
; ++n
)
570 var_set( root_module(), constant_ARGV
, list_new( object_new(
571 arg_v
[ n
] ) ), VAR_APPEND
);
573 /* Initialize built-in rules. */
576 /* Add the targets in the command line to the update list. */
577 for ( n
= 1; n
< arg_c
; ++n
)
579 if ( arg_v
[ n
][ 0 ] == '-' )
581 char * f
= "-:l:d:j:f:gs:t:ano:qv";
582 for ( ; *f
; ++f
) if ( *f
== arg_v
[ n
][ 1 ] ) break;
583 if ( ( f
[ 1 ] == ':' ) && ( arg_v
[ n
][ 2 ] == '\0' ) ) ++n
;
587 OBJECT
* const target
= object_new( arg_v
[ n
] );
588 mark_target_for_updating( target
);
589 object_free( target
);
593 if ( list_empty( targets_to_update() ) )
594 mark_target_for_updating( constant_all
);
600 for ( n
= 0; ( s
= getoptval( optv
, 'f', n
) ); ++n
)
602 OBJECT
* const filename
= object_new( s
);
603 parse_file( filename
, frame
);
604 object_free( filename
);
608 parse_file( constant_plus
, frame
);
611 status
= yyanyerrors();
613 /* Manually touch -t targets. */
614 for ( n
= 0; ( s
= getoptval( optv
, 't', n
) ); ++n
)
616 OBJECT
* const target
= object_new( s
);
617 touch_target( target
);
618 object_free( target
);
621 /* The build system may set the PARALLELISM variable to override -j
625 LIST
* const p
= var_get( root_module(), constant_PARALLELISM
);
626 if ( !list_empty( p
) )
628 int const j
= atoi( object_str( list_front( p
) ) );
630 out_printf( "Invalid value of PARALLELISM: %s.\n",
631 object_str( list_front( p
) ) );
637 /* KEEP_GOING overrides -q option. */
639 LIST
* const p
= var_get( root_module(), constant_KEEP_GOING
);
640 if ( !list_empty( p
) )
641 globs
.quitquick
= atoi( object_str( list_front( p
) ) ) ? 0 : 1;
644 /* Now make target. */
646 PROFILE_ENTER( MAIN_MAKE
);
647 LIST
* const targets
= targets_to_update();
648 if ( !list_empty( targets
) )
649 status
|= make( targets
, anyhow
);
651 status
= last_update_now_status
;
652 PROFILE_EXIT( MAIN_MAKE
);
655 PROFILE_EXIT( MAIN
);
662 #ifdef OPT_HEADER_CACHE_EXT
666 clear_targets_to_update();
668 /* Widely scattered cleanup. */
695 return status
? EXITBAD
: EXITOK
;
704 # define WIN32_LEAN_AND_MEAN
705 # include <windows.h>
706 char * executable_path( char const * argv0
)
709 DWORD
const ret
= GetModuleFileName( NULL
, buf
, sizeof( buf
) );
710 return ( !ret
|| ret
== sizeof( buf
) ) ? NULL
: strdup( buf
);
712 #elif defined(__APPLE__) /* Not tested */
713 # include <mach-o/dyld.h>
714 char *executable_path( char const * argv0
)
717 uint32_t size
= sizeof( buf
);
718 return _NSGetExecutablePath( buf
, &size
) ? NULL
: strdup( buf
);
720 #elif defined(sun) || defined(__sun) /* Not tested */
722 char * executable_path( char const * argv0
)
724 const char * execname
= getexecname();
725 return execname
? strdup( execname
) : NULL
;
727 #elif defined(__FreeBSD__)
728 # include <sys/sysctl.h>
729 char * executable_path( char const * argv0
)
731 int mib
[ 4 ] = { CTL_KERN
, KERN_PROC
, KERN_PROC_PATHNAME
, -1 };
733 size_t size
= sizeof( buf
);
734 sysctl( mib
, 4, buf
, &size
, NULL
, 0 );
735 return ( !size
|| size
== sizeof( buf
) ) ? NULL
: strndup( buf
, size
);
737 #elif defined(__linux__)
739 char * executable_path( char const * argv0
)
742 ssize_t
const ret
= readlink( "/proc/self/exe", buf
, sizeof( buf
) );
743 return ( !ret
|| ret
== sizeof( buf
) ) ? NULL
: strndup( buf
, ret
);
745 #elif defined(OS_VMS)
746 # include <unixlib.h>
747 char * executable_path( char const * argv0
)
749 char * vms_path
= NULL
;
750 char * posix_path
= NULL
;
753 /* On VMS argv[0] shows absolute path to the image file.
754 * So, just remove VMS file version and translate path to POSIX-style.
756 vms_path
= strdup( argv0
);
757 if ( vms_path
&& ( p
= strchr( vms_path
, ';') ) ) *p
= '\0';
758 posix_path
= decc$
translate_vms( vms_path
);
759 if ( vms_path
) free( vms_path
);
761 return posix_path
> 0 ? strdup( posix_path
) : NULL
;
764 char * executable_path( char const * argv0
)
766 /* If argv0 is an absolute path, assume it is the right absolute path. */
767 return argv0
[ 0 ] == '/' ? strdup( argv0
) : NULL
;