module_t * bindmodule( OBJECT * name ) { if ( !name ) { return &root; } else { PROFILE_ENTER( BINDMODULE ); module_t m_; module_t * m = &m_; if ( !module_hash ) module_hash = hashinit( sizeof( module_t ), "modules" ); m->name = name; if ( hashenter( module_hash, (HASHDATA * *)&m ) ) { m->name = object_copy( name ); m->variables = 0; m->rules = 0; m->imported_modules = 0; m->class_module = 0; m->native_rules = 0; m->user_module = 0; } PROFILE_EXIT( BINDMODULE ); return m; } }
static TARGETS * make0sort( TARGETS * chain ) { PROFILE_ENTER( MAKE_MAKE0SORT ); TARGETS * result = 0; /* Walk the current target list. */ while ( chain ) { TARGETS * c = chain; TARGETS * s = result; chain = chain->next; /* Find point s in result for c. */ while ( s && timestamp_cmp( &s->target->time, &c->target->time ) > 0 ) s = s->next; /* Insert c in front of s (might be 0). */ c->next = s; /* good even if s = 0 */ if ( result == s ) result = c; /* new head of chain? */ if ( !s ) s = result; /* wrap to ensure a next */ if ( result != c ) s->tail->next = c; /* not head? be prev's next */ c->tail = s->tail; /* take on next's prev */ s->tail = c; /* make next's prev us */ } PROFILE_EXIT( MAKE_MAKE0SORT ); return result; }
static void builtin_glob_back( void *closure, char *file, int status, time_t time ) { PROFILE_ENTER(BUILTIN_GLOB_BACK); struct globbing *globbing = (struct globbing *)closure; LIST *l; PATHNAME f; string buf[1]; /* Null out directory for matching. */ /* We wish we had file_dirscan() pass up a PATHNAME. */ path_parse( file, &f ); f.f_dir.len = 0; /* For globbing, we unconditionally ignore current and parent directory items. Since they items always exist, there's not reason why caller of GLOB would want to see them. We could also change file_dirscan, but then paths with embedded "." and ".." won't work anywhere. */ if (strcmp(f.f_base.ptr, ".") == 0 || strcmp(f.f_base.ptr, "..") == 0) { PROFILE_EXIT(BUILTIN_GLOB_BACK); return; } string_new( buf ); path_build( &f, buf, 0 ); if (globbing->case_insensitive) { downcase_inplace( buf->value ); } for( l = globbing->patterns; l; l = l->next ) { if( !glob( l->string, buf->value ) ) { globbing->results = list_new( globbing->results, newstr( file ) ); break; } } string_free( buf ); PROFILE_EXIT(BUILTIN_GLOB_BACK); }
void timestamp_from_path( timestamp * const time, OBJECT * const path ) { PROFILE_ENTER( timestamp ); PATHNAME f1; PATHNAME f2; int found; BINDING * b; string buf[ 1 ]; if ( file_time( path, time ) < 0 ) timestamp_clear( time ); PROFILE_EXIT( timestamp ); }
static TARGETS * make0sort( TARGETS *chain ) { PROFILE_ENTER(MAKE_MAKE0SORT); TARGETS *result = 0; /* We walk chain, taking each item and inserting it on the */ /* sorted result, with newest items at the front. This involves */ /* updating each TARGETS' c->next and c->tail. Note that we */ /* make c->tail a valid prev pointer for every entry. Normally, */ /* it is only valid at the head, where prev == tail. Note also */ /* that while tail is a loop, next ends at the end of the chain. */ /* Walk current target list */ while( chain ) { TARGETS *c = chain; TARGETS *s = result; chain = chain->next; /* Find point s in result for c */ while( s && s->target->time > c->target->time ) s = s->next; /* Insert c in front of s (might be 0). */ /* Don't even think of deciphering this. */ c->next = s; /* good even if s = 0 */ if( result == s ) result = c; /* new head of chain? */ if( !s ) s = result; /* wrap to ensure a next */ if( result != c ) s->tail->next = c; /* not head? be prev's next */ c->tail = s->tail; /* take on next's prev */ s->tail = c; /* make next's prev us */ } PROFILE_EXIT(MAKE_MAKE0SORT); return result; }
void import_module( LIST * module_names, module_t * target_module ) { PROFILE_ENTER( IMPORT_MODULE ); struct hash * h; if ( !target_module->imported_modules ) target_module->imported_modules = hashinit( sizeof( char * ), "imported" ); h = target_module->imported_modules; for ( ; module_names; module_names = module_names->next ) { OBJECT * s = module_names->value; OBJECT * * ss = &s; if( hashenter( h, (HASHDATA * *)&ss ) ) { *ss = object_copy( s ); } } PROFILE_EXIT( IMPORT_MODULE ); }
int make( int n_targets, const char **targets, int anyhow ) { int i; COUNTS counts[1]; int status = 0; /* 1 if anything fails */ #ifdef OPT_HEADER_CACHE_EXT hcache_init(); #endif memset( (char *)counts, 0, sizeof( *counts ) ); /* First bind all targets with LOCATE_TARGET setting. This is needed to correctly handle dependencies to generated headers. */ bind_explicitly_located_targets(); { PROFILE_ENTER(MAKE_MAKE0); for( i = 0; i < n_targets; i++ ) { TARGET *t = bindtarget( targets[i] ); make0( t, 0, 0, counts, anyhow ); } PROFILE_EXIT(MAKE_MAKE0); } #ifdef OPT_GRAPH_DEBUG_EXT if( DEBUG_GRAPH ) { for( i = 0; i < n_targets; i++ ) { TARGET *t = bindtarget( targets[i] ); dependGraphOutput( t, 0 ); } } #endif if( DEBUG_MAKE ) { if( counts->targets ) printf( "...found %d target%s...\n", counts->targets, counts->targets > 1 ? "s" : "" ); if( counts->temp ) printf( "...using %d temp target%s...\n", counts->temp, counts->temp > 1 ? "s" : "" ); if( counts->updating ) printf( "...updating %d target%s...\n", counts->updating, counts->updating > 1 ? "s" : "" ); if( counts->cantfind ) printf( "...can't find %d target%s...\n", counts->cantfind, counts->cantfind > 1 ? "s" : "" ); if( counts->cantmake ) printf( "...can't make %d target%s...\n", counts->cantmake, counts->cantmake > 1 ? "s" : "" ); } #ifdef OPT_HEADER_CACHE_EXT hcache_done(); #endif status = counts->cantfind || counts->cantmake; { PROFILE_ENTER(MAKE_MAKE1); for( i = 0; i < n_targets; i++ ) status |= make1( bindtarget( targets[i] ) ); PROFILE_EXIT(MAKE_MAKE1); } return status; }
void file_dirscan( OBJECT * dir, scanback func, void * closure ) { PROFILE_ENTER( FILE_DIRSCAN ); file_info_t * d = 0; d = file_query( dir ); if ( !d || !d->is_dir ) { PROFILE_EXIT( FILE_DIRSCAN ); return; } if ( ! d->files ) { LIST* files = L0; PATHNAME f; DIR *dd; STRUCT_DIRENT *dirent; string filename[1]; const char * dirstr = object_str( dir ); /* First enter directory itself */ memset( (char *)&f, '\0', sizeof( f ) ); f.f_dir.ptr = dirstr; f.f_dir.len = strlen( dirstr ); dirstr = *dirstr ? dirstr : "."; /* Now enter contents of directory. */ if ( !( dd = opendir( dirstr ) ) ) { PROFILE_EXIT( FILE_DIRSCAN ); return; } if ( DEBUG_BINDSCAN ) printf( "scan directory %s\n", dirstr ); string_new( filename ); while ( ( dirent = readdir( dd ) ) ) { OBJECT * filename_obj; # ifdef old_sinix /* Broken structure definition on sinix. */ f.f_base.ptr = dirent->d_name - 2; # else f.f_base.ptr = dirent->d_name; # endif f.f_base.len = strlen( f.f_base.ptr ); string_truncate( filename, 0 ); path_build( &f, filename, 0 ); filename_obj = object_new( filename->value ); files = list_new( files, filename_obj ); file_query( filename_obj ); } string_free( filename ); closedir( dd ); d->files = files; } /* Special case / : enter it */ { if ( strcmp( object_str( d->name ), "/" ) == 0 ) (*func)( closure, d->name, 1 /* stat()'ed */, d->time ); } /* Now enter contents of directory */ if ( d->files ) { LIST * files = d->files; while ( files ) { file_info_t * ff = file_info( files->value ); (*func)( closure, ff->name, 1 /* stat()'ed */, ff->time ); files = list_next( files ); } } PROFILE_EXIT( FILE_DIRSCAN ); }
int main( int argc, char * * argv, char * * arg_environ ) { int n; char * s; struct bjam_option optv[N_OPTS]; char const * all = "all"; int status; int arg_c = argc; char * * arg_v = argv; char const * progname = argv[0]; module_t * environ_module; #if defined(unix) || defined(__unix) sigset_t sigmask; struct sigaction sa; sigemptyset(&sigmask); sigaddset(&sigmask, SIGCHLD); sigprocmask(SIG_BLOCK, &sigmask, NULL); sa.sa_flags = 0; sa.sa_handler = child_sig_handler; sigemptyset(&sa.sa_mask); sigaction(SIGCHLD, &sa, NULL); sigemptyset(&empty_sigmask); #endif saved_argv0 = argv[0]; BJAM_MEM_INIT(); # ifdef OS_MAC InitGraf(&qd.thePort); # endif --argc; ++argv; if ( getoptions( argc, argv, "-:l:m:d:j:p:f:gs:t:ano:qv", optv ) < 0 ) { printf( "\nusage: %s [ options ] targets...\n\n", progname ); printf( "-a Build all targets, even if they are current.\n" ); printf( "-dx Set the debug level to x (0-9).\n" ); printf( "-fx Read x instead of Jambase.\n" ); /* printf( "-g Build from newest sources first.\n" ); */ printf( "-jx Run up to x shell commands concurrently.\n" ); printf( "-lx Limit actions to x number of seconds after which they are stopped.\n" ); printf( "-mx Limit action output buffer to x kb's of data, after which action output is read and ignored.\n" ); printf( "-n Don't actually execute the updating actions.\n" ); printf( "-ox Write the updating actions to file x.\n" ); printf( "-px x=0, pipes action stdout and stderr merged into action output.\n" ); printf( "-q Quit quickly as soon as a target fails.\n" ); printf( "-sx=y Set variable x=y, overriding environment.\n" ); printf( "-tx Rebuild x, even if it is up-to-date.\n" ); printf( "-v Print the version of jam and exit.\n" ); printf( "--x Option is ignored.\n\n" ); exit( EXITBAD ); } /* Version info. */ if ( ( s = getoptval( optv, 'v', 0 ) ) ) { printf( "Boost.Jam " ); printf( "Version %s. %s.\n", VERSION, OSMINOR ); printf( " Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. \n" ); printf( " Copyright 2001 David Turner.\n" ); printf( " Copyright 2001-2004 David Abrahams.\n" ); printf( " Copyright 2002-2008 Rene Rivera.\n" ); printf( " Copyright 2003-2008 Vladimir Prus.\n" ); return EXITOK; } /* Pick up interesting options. */ if ( ( s = getoptval( optv, 'n', 0 ) ) ) globs.noexec++, globs.debug[2] = 1; if ( ( s = getoptval( optv, 'p', 0 ) ) ) { /* Undocumented -p3 (acts like both -p1 -p2) means separate pipe action * stdout and stderr. */ globs.pipe_action = atoi( s ); if ( ( 3 < globs.pipe_action ) || ( globs.pipe_action < 0 ) ) { printf( "Invalid pipe descriptor '%d', valid values are -p[0..3].\n", globs.pipe_action ); exit( EXITBAD ); } } if ( ( s = getoptval( optv, 'q', 0 ) ) ) globs.quitquick = 1; if ( ( s = getoptval( optv, 'a', 0 ) ) ) anyhow++; if ( ( s = getoptval( optv, 'j', 0 ) ) ) { globs.jobs = atoi( s ); if (globs.jobs == 0) { printf("Invalid value for the '-j' option.\n"); exit(EXITBAD); } } if ( ( s = getoptval( optv, 'g', 0 ) ) ) globs.newestfirst = 1; if ( ( s = getoptval( optv, 'l', 0 ) ) ) globs.timeout = atoi( s ); if ( ( s = getoptval( optv, 'm', 0 ) ) ) globs.maxbuf = atoi( s ) * 1024; /* Turn on/off debugging */ for ( n = 0; ( s = getoptval( optv, 'd', n ) ); ++n ) { int i; /* First -d, turn off defaults. */ if ( !n ) for ( i = 0; i < DEBUG_MAX; ++i ) globs.debug[i] = 0; i = atoi( s ); if ( ( i < 0 ) || ( i >= DEBUG_MAX ) ) { printf( "Invalid debug level '%s'.\n", s ); continue; } /* n turns on levels 1-n. */ /* +n turns on level n. */ if ( *s == '+' ) globs.debug[i] = 1; else while ( i ) globs.debug[i--] = 1; } constants_init(); { PROFILE_ENTER( MAIN ); #ifdef HAVE_PYTHON { PROFILE_ENTER( MAIN_PYTHON ); Py_Initialize(); { static PyMethodDef BjamMethods[] = { {"call", bjam_call, METH_VARARGS, "Call the specified bjam rule."}, {"import_rule", bjam_import_rule, METH_VARARGS, "Imports Python callable to bjam."}, {"define_action", bjam_define_action, METH_VARARGS, "Defines a command line action."}, {"variable", bjam_variable, METH_VARARGS, "Obtains a variable from bjam's global module."}, {"backtrace", bjam_backtrace, METH_VARARGS, "Returns bjam backtrace from the last call into Python."}, {"caller", bjam_caller, METH_VARARGS, "Returns the module from which the last call into Python is made."}, {NULL, NULL, 0, NULL} }; Py_InitModule( "bjam", BjamMethods ); } PROFILE_EXIT( MAIN_PYTHON ); } #endif #ifndef NDEBUG run_unit_tests(); #endif #if YYDEBUG != 0 if ( DEBUG_PARSE ) yydebug = 1; #endif /* Set JAMDATE. */ var_set( root_module(), constant_JAMDATE, list_new( L0, outf_time(time(0)) ), VAR_SET ); /* Set JAM_VERSION. */ var_set( root_module(), constant_JAM_VERSION, list_new( list_new( list_new( L0, object_new( VERSION_MAJOR_SYM ) ), object_new( VERSION_MINOR_SYM ) ), object_new( VERSION_PATCH_SYM ) ), VAR_SET ); /* Set JAMUNAME. */ #if defined(unix) || defined(__unix) { struct utsname u; if ( uname( &u ) >= 0 ) { var_set( root_module(), constant_JAMUNAME, list_new( list_new( list_new( list_new( list_new( L0, object_new( u.sysname ) ), object_new( u.nodename ) ), object_new( u.release ) ), object_new( u.version ) ), object_new( u.machine ) ), VAR_SET ); } } #endif /* unix */ /* Load up environment variables. */ /* First into the global module, with splitting, for backward * compatibility. */ var_defines( root_module(), use_environ, 1 ); environ_module = bindmodule( constant_ENVIRON ); /* Then into .ENVIRON, without splitting. */ var_defines( environ_module, use_environ, 0 ); /* * Jam defined variables OS & OSPLAT. We load them after environment, so * that setting OS in environment does not change Jam's notion of the * current platform. */ var_defines( root_module(), othersyms, 1 ); /* Load up variables set on command line. */ for ( n = 0; ( s = getoptval( optv, 's', n ) ); ++n ) { char *symv[2]; symv[ 0 ] = s; symv[ 1 ] = 0; var_defines( root_module(), symv, 1 ); var_defines( environ_module, symv, 0 ); } /* Set the ARGV to reflect the complete list of arguments of invocation. */ for ( n = 0; n < arg_c; ++n ) { var_set( root_module(), constant_ARGV, list_new( L0, object_new( arg_v[n] ) ), VAR_APPEND ); } /* Initialize built-in rules. */ load_builtins(); /* Add the targets in the command line to the update list. */ for ( n = 1; n < arg_c; ++n ) { if ( arg_v[ n ][ 0 ] == '-' ) { char * f = "-:l:d:j:f:gs:t:ano:qv"; for ( ; *f; ++f ) if ( *f == arg_v[ n ][ 1 ] ) break; if ( ( f[ 1 ] == ':' ) && ( arg_v[ n ][ 2 ] == '\0' ) ) ++n; } else { OBJECT * target = object_new( arg_v[ n ] ); mark_target_for_updating( target ); object_free( target ); } } if (!targets_to_update()) { mark_target_for_updating( constant_all ); } /* Parse ruleset. */ { FRAME frame[ 1 ]; frame_init( frame ); for ( n = 0; ( s = getoptval( optv, 'f', n ) ); ++n ) { OBJECT * filename = object_new( s ); parse_file( filename, frame ); object_free( filename ); } if ( !n ) { parse_file( constant_plus, frame ); } } status = yyanyerrors(); /* Manually touch -t targets. */ for ( n = 0; ( s = getoptval( optv, 't', n ) ); ++n ) { OBJECT * target = object_new( s ); touch_target( target ); object_free( target ); } /* If an output file is specified, set globs.cmdout to that. */ if ( ( s = getoptval( optv, 'o', 0 ) ) ) { if ( !( globs.cmdout = fopen( s, "w" ) ) ) { printf( "Failed to write to '%s'\n", s ); exit( EXITBAD ); } ++globs.noexec; } /* The build system may set the PARALLELISM variable to override -j options. */ { LIST *p = L0; p = var_get ( root_module(), constant_PARALLELISM ); if ( p ) { int j = atoi( object_str( p->value ) ); if ( j == -1 ) { printf( "Invalid value of PARALLELISM: %s\n", object_str( p->value ) ); } else { globs.jobs = j; } } } /* KEEP_GOING overrides -q option. */ { LIST *p = L0; p = var_get( root_module(), constant_KEEP_GOING ); if ( p ) { int v = atoi( object_str( p->value ) ); if ( v == 0 ) globs.quitquick = 1; else globs.quitquick = 0; } } /* Now make target. */ { PROFILE_ENTER( MAIN_MAKE ); LIST * targets = targets_to_update(); if (targets) { int targets_count = list_length( targets ); OBJECT * * targets2 = (OBJECT * *) BJAM_MALLOC( targets_count * sizeof( OBJECT * ) ); int n = 0; for ( ; targets; targets = list_next( targets ) ) targets2[ n++ ] = targets->value; status |= make( targets_count, targets2, anyhow ); BJAM_FREE( (void *)targets2 ); } else { status = last_update_now_status; } PROFILE_EXIT( MAIN_MAKE ); } PROFILE_EXIT( MAIN ); } if ( DEBUG_PROFILE ) profile_dump(); #ifdef OPT_HEADER_CACHE_EXT hcache_done(); #endif clear_targets_to_update(); /* Widely scattered cleanup. */ file_done(); rules_done(); stamps_done(); search_done(); class_done(); modules_done(); regex_done(); exec_done(); pwd_done(); path_done(); function_done(); list_done(); constants_done(); object_done(); /* Close cmdout. */ if ( globs.cmdout ) fclose( globs.cmdout ); #ifdef HAVE_PYTHON Py_Finalize(); #endif BJAM_MEM_CLOSE(); return status ? EXITBAD : EXITOK; }
void file_dirscan( char * dir, scanback func, void * closure ) { PROFILE_ENTER( FILE_DIRSCAN ); file_info_t * d = 0; dir = short_path_to_long_path( dir ); /* First enter directory itself */ d = file_query( dir ); if ( !d || !d->is_dir ) { PROFILE_EXIT( FILE_DIRSCAN ); return; } if ( !d->files ) { PATHNAME f; string filespec[ 1 ]; string filename[ 1 ]; long handle; int ret; struct _finddata_t finfo[ 1 ]; LIST * files = L0; int d_length = strlen( d->name ); memset( (char *)&f, '\0', sizeof( f ) ); f.f_dir.ptr = d->name; f.f_dir.len = d_length; /* Now enter contents of directory */ /* Prepare file search specification for the findfirst() API. */ if ( d_length == 0 ) string_copy( filespec, ".\\*" ); else { /* * We can not simply assume the given folder name will never include * its trailing path separator or otherwise we would not support the * Windows root folder specified without its drive letter, i.e. '\'. */ char trailingChar = d->name[ d_length - 1 ] ; string_copy( filespec, d->name ); if ( ( trailingChar != '\\' ) && ( trailingChar != '/' ) ) string_append( filespec, "\\" ); string_append( filespec, "*" ); } if ( DEBUG_BINDSCAN ) printf( "scan directory %s\n", dir ); #if defined(__BORLANDC__) && __BORLANDC__ < 0x550 if ( ret = findfirst( filespec->value, finfo, FA_NORMAL | FA_DIREC ) ) { string_free( filespec ); PROFILE_EXIT( FILE_DIRSCAN ); return; } string_new ( filename ); while ( !ret ) { file_info_t * ff = 0; f.f_base.ptr = finfo->ff_name; f.f_base.len = strlen( finfo->ff_name ); string_truncate( filename, 0 ); path_build( &f, filename ); files = list_new( files, newstr(filename->value) ); ff = file_info( filename->value ); ff->is_file = finfo->ff_attrib & FA_DIREC ? 0 : 1; ff->is_dir = finfo->ff_attrib & FA_DIREC ? 1 : 0; ff->size = finfo->ff_fsize; ff->time = (finfo->ff_ftime << 16) | finfo->ff_ftime; ret = findnext( finfo ); } # else handle = _findfirst( filespec->value, finfo ); if ( ret = ( handle < 0L ) ) { string_free( filespec ); PROFILE_EXIT( FILE_DIRSCAN ); return; } string_new( filename ); while ( !ret ) { file_info_t * ff = 0; f.f_base.ptr = finfo->name; f.f_base.len = strlen( finfo->name ); string_truncate( filename, 0 ); path_build( &f, filename, 0 ); files = list_new( files, newstr( filename->value ) ); ff = file_info( filename->value ); ff->is_file = finfo->attrib & _A_SUBDIR ? 0 : 1; ff->is_dir = finfo->attrib & _A_SUBDIR ? 1 : 0; ff->size = finfo->size; ff->time = finfo->time_write; ret = _findnext( handle, finfo ); } _findclose( handle ); # endif string_free( filename ); string_free( filespec ); d->files = files; } /* Special case \ or d:\ : enter it */ { unsigned long len = strlen(d->name); if ( len == 1 && d->name[0] == '\\' ) (*func)( closure, d->name, 1 /* stat()'ed */, d->time ); else if ( len == 3 && d->name[1] == ':' ) { (*func)( closure, d->name, 1 /* stat()'ed */, d->time ); /* We've just entered 3-letter drive name spelling (with trailing slash), into the hash table. Now enter two-letter variant, without trailing slash, so that if we try to check whether "c:" exists, we hit it. Jam core has workarounds for that. Given: x = c:\whatever\foo ; p = $(x:D) ; p2 = $(p:D) ; There will be no trailing slash in $(p), but there will be one in $(p2). But, that seems rather fragile. */ d->name[2] = 0; (*func)( closure, d->name, 1 /* stat()'ed */, d->time ); } } /* Now enter contents of directory */ if ( d->files ) { LIST * files = d->files; while ( files ) { file_info_t * ff = file_info( files->string ); (*func)( closure, ff->name, 1 /* stat()'ed */, ff->time ); files = list_next( files ); } } PROFILE_EXIT( FILE_DIRSCAN ); }
void file_dirscan( OBJECT * dir, scanback func, void * closure ) { PROFILE_ENTER( FILE_DIRSCAN ); file_dirscan_impl( dir, func, closure ); PROFILE_EXIT( FILE_DIRSCAN ); }
void file_archivescan( OBJECT * path, archive_scanback func, void * closure ) { PROFILE_ENTER( FILE_ARCHIVESCAN ); file_archivescan_impl( path, func, closure ); PROFILE_EXIT( FILE_ARCHIVESCAN ); }
int make( LIST * targets, int anyhow ) { COUNTS counts[ 1 ]; int status = 0; /* 1 if anything fails */ #ifdef OPT_HEADER_CACHE_EXT hcache_init(); #endif memset( (char *)counts, 0, sizeof( *counts ) ); /* Make sure that the tables are set up correctly. */ exec_init(); /* First bind all targets with LOCATE_TARGET setting. This is needed to * correctly handle dependencies to generated headers. */ bind_explicitly_located_targets(); { LISTITER iter, end; PROFILE_ENTER( MAKE_MAKE0 ); for ( iter = list_begin( targets ), end = list_end( targets ); iter != end; iter = list_next( iter ) ) { TARGET * t = bindtarget( list_item( iter ) ); if ( t->fate == T_FATE_INIT ) make0( t, 0, 0, counts, anyhow, 0 ); } PROFILE_EXIT( MAKE_MAKE0 ); } #ifdef OPT_GRAPH_DEBUG_EXT if ( DEBUG_GRAPH ) { LISTITER iter, end; for ( iter = list_begin( targets ), end = list_end( targets ); iter != end; iter = list_next( iter ) ) dependGraphOutput( bindtarget( list_item( iter ) ), 0 ); } #endif if ( DEBUG_MAKE ) { if ( counts->targets ) out_printf( "...found %d target%s...\n", counts->targets, counts->targets > 1 ? "s" : "" ); if ( counts->temp ) out_printf( "...using %d temp target%s...\n", counts->temp, counts->temp > 1 ? "s" : "" ); if ( counts->updating ) out_printf( "...updating %d target%s...\n", counts->updating, counts->updating > 1 ? "s" : "" ); if ( counts->cantfind ) out_printf( "...can't find %d target%s...\n", counts->cantfind, counts->cantfind > 1 ? "s" : "" ); if ( counts->cantmake ) out_printf( "...can't make %d target%s...\n", counts->cantmake, counts->cantmake > 1 ? "s" : "" ); } status = counts->cantfind || counts->cantmake; { PROFILE_ENTER( MAKE_MAKE1 ); status |= make1( targets ); PROFILE_EXIT( MAKE_MAKE1 ); } return status; }
int main( int argc, char * * argv, char * * arg_environ ) { int n; char * s; struct bjam_option optv[ N_OPTS ]; char const * all = "all"; int status; int arg_c = argc; char * * arg_v = argv; char const * progname = argv[ 0 ]; module_t * environ_module; saved_argv0 = argv[ 0 ]; BJAM_MEM_INIT(); #ifdef OS_MAC InitGraf( &qd.thePort ); #endif --argc; ++argv; #ifdef HAVE_PYTHON #define OPTSTRING "-:l:m:d:j:p:f:gs:t:ano:qvz" #else #define OPTSTRING "-:l:m:d:j:p:f:gs:t:ano:qv" #endif if ( getoptions( argc, argv, OPTSTRING, optv ) < 0 ) { err_printf( "\nusage: %s [ options ] targets...\n\n", progname ); err_printf( "-a Build all targets, even if they are current.\n" ); err_printf( "-dx Set the debug level to x (0-9).\n" ); err_printf( "-fx Read x instead of Jambase.\n" ); /* err_printf( "-g Build from newest sources first.\n" ); */ err_printf( "-jx Run up to x shell commands concurrently.\n" ); err_printf( "-lx Limit actions to x number of seconds after which they are stopped.\n" ); err_printf( "-mx Maximum target output saved (kb), default is to save all output.\n" ); err_printf( "-n Don't actually execute the updating actions.\n" ); err_printf( "-ox Mirror all output to file x.\n" ); err_printf( "-px x=0, pipes action stdout and stderr merged into action output.\n" ); err_printf( "-q Quit quickly as soon as a target fails.\n" ); err_printf( "-sx=y Set variable x=y, overriding environment.\n" ); err_printf( "-tx Rebuild x, even if it is up-to-date.\n" ); err_printf( "-v Print the version of jam and exit.\n" ); #ifdef HAVE_PYTHON err_printf( "-z Disable Python Optimization and enable asserts\n" ); #endif err_printf( "--x Option is ignored.\n\n" ); exit( EXITBAD ); } /* Version info. */ if ( ( s = getoptval( optv, 'v', 0 ) ) ) { out_printf( "Boost.Jam Version %s. %s.\n", VERSION, OSMINOR ); out_printf( " Copyright 1993-2002 Christopher Seiwald and Perforce " "Software, Inc.\n" ); out_printf( " Copyright 2001 David Turner.\n" ); out_printf( " Copyright 2001-2004 David Abrahams.\n" ); out_printf( " Copyright 2002-2015 Rene Rivera.\n" ); out_printf( " Copyright 2003-2015 Vladimir Prus.\n" ); return EXITOK; } /* Pick up interesting options. */ if ( ( s = getoptval( optv, 'n', 0 ) ) ) { ++globs.noexec; globs.debug[ 2 ] = 1; } if ( ( s = getoptval( optv, 'p', 0 ) ) ) { /* Undocumented -p3 (acts like both -p1 -p2) means separate pipe action * stdout and stderr. */ globs.pipe_action = atoi( s ); if ( globs.pipe_action < 0 || 3 < globs.pipe_action ) { err_printf( "Invalid pipe descriptor '%d', valid values are -p[0..3]." "\n", globs.pipe_action ); exit( EXITBAD ); } } if ( ( s = getoptval( optv, 'q', 0 ) ) ) globs.quitquick = 1; if ( ( s = getoptval( optv, 'a', 0 ) ) ) anyhow++; if ( ( s = getoptval( optv, 'j', 0 ) ) ) { globs.jobs = atoi( s ); if ( globs.jobs < 1 || globs.jobs > MAXJOBS ) { err_printf( "Invalid value for the '-j' option, valid values are 1 " "through %d.\n", MAXJOBS ); exit( EXITBAD ); } } if ( ( s = getoptval( optv, 'g', 0 ) ) ) globs.newestfirst = 1; if ( ( s = getoptval( optv, 'l', 0 ) ) ) globs.timeout = atoi( s ); if ( ( s = getoptval( optv, 'm', 0 ) ) ) globs.max_buf = atoi( s ) * 1024; /* convert to kb */ #ifdef HAVE_PYTHON if ( ( s = getoptval( optv, 'z', 0 ) ) ) python_optimize = 0; /* disable python optimization */ #endif /* Turn on/off debugging */ for ( n = 0; ( s = getoptval( optv, 'd', n ) ); ++n ) { int i; /* First -d, turn off defaults. */ if ( !n ) for ( i = 0; i < DEBUG_MAX; ++i ) globs.debug[i] = 0; i = atoi( s ); if ( ( i < 0 ) || ( i >= DEBUG_MAX ) ) { out_printf( "Invalid debug level '%s'.\n", s ); continue; } /* n turns on levels 1-n. */ /* +n turns on level n. */ if ( *s == '+' ) globs.debug[ i ] = 1; else while ( i ) globs.debug[ i-- ] = 1; } /* If an output file is specified, set globs.out to that. */ if ( ( s = getoptval( optv, 'o', 0 ) ) ) { if ( !( globs.out = fopen( s, "w" ) ) ) { err_printf( "Failed to write to '%s'\n", s ); exit( EXITBAD ); } /* ++globs.noexec; */ } constants_init(); cwd_init(); { PROFILE_ENTER( MAIN ); #ifdef HAVE_PYTHON { PROFILE_ENTER( MAIN_PYTHON ); Py_OptimizeFlag = python_optimize; Py_Initialize(); { static PyMethodDef BjamMethods[] = { {"call", bjam_call, METH_VARARGS, "Call the specified bjam rule."}, {"import_rule", bjam_import_rule, METH_VARARGS, "Imports Python callable to bjam."}, {"define_action", bjam_define_action, METH_VARARGS, "Defines a command line action."}, {"variable", bjam_variable, METH_VARARGS, "Obtains a variable from bjam's global module."}, {"backtrace", bjam_backtrace, METH_VARARGS, "Returns bjam backtrace from the last call into Python."}, {"caller", bjam_caller, METH_VARARGS, "Returns the module from which the last call into Python is made."}, {NULL, NULL, 0, NULL} }; Py_InitModule( "bjam", BjamMethods ); } PROFILE_EXIT( MAIN_PYTHON ); } #endif #ifndef NDEBUG run_unit_tests(); #endif #if YYDEBUG != 0 if ( DEBUG_PARSE ) yydebug = 1; #endif /* Set JAMDATE. */ { timestamp current; timestamp_current( ¤t ); var_set( root_module(), constant_JAMDATE, list_new( outf_time( ¤t ) ), VAR_SET ); } /* Set JAM_VERSION. */ var_set( root_module(), constant_JAM_VERSION, list_push_back( list_push_back( list_new( object_new( VERSION_MAJOR_SYM ) ), object_new( VERSION_MINOR_SYM ) ), object_new( VERSION_PATCH_SYM ) ), VAR_SET ); /* Set JAMUNAME. */ #ifdef unix { struct utsname u; if ( uname( &u ) >= 0 ) { var_set( root_module(), constant_JAMUNAME, list_push_back( list_push_back( list_push_back( list_push_back( list_new( object_new( u.sysname ) ), object_new( u.nodename ) ), object_new( u.release ) ), object_new( u.version ) ), object_new( u.machine ) ), VAR_SET ); } } #endif /* unix */ /* Set JAM_TIMESTAMP_RESOLUTION. */ { timestamp fmt_resolution[ 1 ]; file_supported_fmt_resolution( fmt_resolution ); var_set( root_module(), constant_JAM_TIMESTAMP_RESOLUTION, list_new( object_new( timestamp_timestr( fmt_resolution ) ) ), VAR_SET ); } /* Load up environment variables. */ /* First into the global module, with splitting, for backward * compatibility. */ var_defines( root_module(), use_environ, 1 ); environ_module = bindmodule( constant_ENVIRON ); /* Then into .ENVIRON, without splitting. */ var_defines( environ_module, use_environ, 0 ); /* * Jam defined variables OS & OSPLAT. We load them after environment, so * that setting OS in environment does not change Jam's notion of the * current platform. */ var_defines( root_module(), othersyms, 1 ); /* Load up variables set on command line. */ for ( n = 0; ( s = getoptval( optv, 's', n ) ); ++n ) { char * symv[ 2 ]; symv[ 0 ] = s; symv[ 1 ] = 0; var_defines( root_module(), symv, 1 ); var_defines( environ_module, symv, 0 ); } /* Set the ARGV to reflect the complete list of arguments of invocation. */ for ( n = 0; n < arg_c; ++n ) var_set( root_module(), constant_ARGV, list_new( object_new( arg_v[ n ] ) ), VAR_APPEND ); /* Initialize built-in rules. */ load_builtins(); /* Add the targets in the command line to the update list. */ for ( n = 1; n < arg_c; ++n ) { if ( arg_v[ n ][ 0 ] == '-' ) { char * f = "-:l:d:j:f:gs:t:ano:qv"; for ( ; *f; ++f ) if ( *f == arg_v[ n ][ 1 ] ) break; if ( ( f[ 1 ] == ':' ) && ( arg_v[ n ][ 2 ] == '\0' ) ) ++n; } else { OBJECT * const target = object_new( arg_v[ n ] ); mark_target_for_updating( target ); object_free( target ); } } if ( list_empty( targets_to_update() ) ) mark_target_for_updating( constant_all ); /* Parse ruleset. */ { FRAME frame[ 1 ]; frame_init( frame ); for ( n = 0; ( s = getoptval( optv, 'f', n ) ); ++n ) { OBJECT * const filename = object_new( s ); parse_file( filename, frame ); object_free( filename ); } if ( !n ) parse_file( constant_plus, frame ); } status = yyanyerrors(); /* Manually touch -t targets. */ for ( n = 0; ( s = getoptval( optv, 't', n ) ); ++n ) { OBJECT * const target = object_new( s ); touch_target( target ); object_free( target ); } /* The build system may set the PARALLELISM variable to override -j * options. */ { LIST * const p = var_get( root_module(), constant_PARALLELISM ); if ( !list_empty( p ) ) { int const j = atoi( object_str( list_front( p ) ) ); if ( j < 1 || j > MAXJOBS ) out_printf( "Invalid value of PARALLELISM: %s. Valid values " "are 1 through %d.\n", object_str( list_front( p ) ), MAXJOBS ); else globs.jobs = j; } } /* KEEP_GOING overrides -q option. */ { LIST * const p = var_get( root_module(), constant_KEEP_GOING ); if ( !list_empty( p ) ) globs.quitquick = atoi( object_str( list_front( p ) ) ) ? 0 : 1; } /* Now make target. */ { PROFILE_ENTER( MAIN_MAKE ); LIST * const targets = targets_to_update(); if ( !list_empty( targets ) ) status |= make( targets, anyhow ); else status = last_update_now_status; PROFILE_EXIT( MAIN_MAKE ); } PROFILE_EXIT( MAIN ); } if ( DEBUG_PROFILE ) profile_dump(); #ifdef OPT_HEADER_CACHE_EXT hcache_done(); #endif clear_targets_to_update(); /* Widely scattered cleanup. */ property_set_done(); file_done(); rules_done(); timestamp_done(); search_done(); class_done(); modules_done(); regex_done(); cwd_done(); path_done(); function_done(); list_done(); constants_done(); object_done(); /* Close log out. */ if ( globs.out ) fclose( globs.out ); #ifdef HAVE_PYTHON Py_Finalize(); #endif BJAM_MEM_CLOSE(); return status ? EXITBAD : EXITOK; }
int main( int argc, char **argv, char **arg_environ ) { int n; char *s; struct option optv[N_OPTS]; const char *all = "all"; int anyhow = 0; int status; int arg_c = argc; char ** arg_v = argv; const char *progname = argv[0]; # ifdef OS_MAC InitGraf(&qd.thePort); # endif argc--, argv++; if( getoptions( argc, argv, "-:l:d:j:f:gs:t:ano:qv", optv ) < 0 ) { printf( "\nusage: %s [ options ] targets...\n\n", progname ); printf( "-a Build all targets, even if they are current.\n" ); printf( "-dx Set the debug level to x (0-9).\n" ); printf( "-fx Read x instead of Jambase.\n" ); /* printf( "-g Build from newest sources first.\n" ); */ printf( "-jx Run up to x shell commands concurrently.\n" ); printf( "-lx Limit actions to x number of seconds after which they are stopped.\n" ); printf( "-n Don't actually execute the updating actions.\n" ); printf( "-ox Write the updating actions to file x.\n" ); printf( "-q Quit quickly as soon as a target fails.\n" ); printf( "-sx=y Set variable x=y, overriding environment.\n" ); printf( "-tx Rebuild x, even if it is up-to-date.\n" ); printf( "-v Print the version of jam and exit.\n" ); printf( "--x Option is ignored.\n\n" ); exit( EXITBAD ); } /* Version info. */ if( ( s = getoptval( optv, 'v', 0 ) ) ) { printf( "Boost.Jam " ); printf( "Version %s. %s.\n", VERSION, OSMINOR ); printf( " Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. \n" ); printf( " Copyright 2001 David Turner.\n" ); printf( " Copyright 2001-2004 David Abrahams.\n" ); printf( " Copyright 2002-2005 Rene Rivera.\n" ); printf( " Copyright 2003-2005 Vladimir Prus.\n" ); return EXITOK; } /* Pick up interesting options */ if( ( s = getoptval( optv, 'n', 0 ) ) ) globs.noexec++, globs.debug[2] = 1; if( ( s = getoptval( optv, 'q', 0 ) ) ) globs.quitquick = 1; if( ( s = getoptval( optv, 'a', 0 ) ) ) anyhow++; if( ( s = getoptval( optv, 'j', 0 ) ) ) globs.jobs = atoi( s ); if( ( s = getoptval( optv, 'g', 0 ) ) ) globs.newestfirst = 1; if( ( s = getoptval( optv, 'l', 0 ) ) ) globs.timeout = atoi( s ); /* Turn on/off debugging */ for( n = 0; s = getoptval( optv, 'd', n ); n++ ) { int i; /* First -d, turn off defaults. */ if( !n ) for( i = 0; i < DEBUG_MAX; i++ ) globs.debug[i] = 0; i = atoi( s ); if( i < 0 || i >= DEBUG_MAX ) { printf( "Invalid debug level '%s'.\n", s ); continue; } /* n turns on levels 1-n */ /* +n turns on level n */ if( *s == '+' ) globs.debug[i] = 1; else while( i ) globs.debug[i--] = 1; } { PROFILE_ENTER(MAIN); #ifdef HAVE_PYTHON { PROFILE_ENTER(MAIN_PYTHON); Py_Initialize(); { static PyMethodDef BjamMethods[] = { {"call", bjam_call, METH_VARARGS, "Call the specified bjam rule."}, {"import_rule", bjam_import_rule, METH_VARARGS, "Imports Python callable to bjam."}, {NULL, NULL, 0, NULL} }; Py_InitModule("bjam", BjamMethods); } PROFILE_EXIT(MAIN_PYTHON); } #endif #ifndef NDEBUG run_unit_tests(); #endif #if YYDEBUG != 0 if ( DEBUG_PARSE ) yydebug = 1; #endif /* Set JAMDATE first */ { char *date; time_t clock; time( &clock ); date = newstr( ctime( &clock ) ); /* Trim newline from date */ if( strlen( date ) == 25 ) date[ 24 ] = 0; var_set( "JAMDATE", list_new( L0, newstr( date ) ), VAR_SET ); } var_set( "JAM_VERSION", list_new( list_new( list_new( L0, newstr( VERSION_MAJOR_SYM ) ), newstr( VERSION_MINOR_SYM ) ), newstr( VERSION_PATCH_SYM ) ), VAR_SET ); /* And JAMUNAME */ # ifdef unix { struct utsname u; if( uname( &u ) >= 0 ) { var_set( "JAMUNAME", list_new( list_new( list_new( list_new( list_new( L0, newstr( u.sysname ) ), newstr( u.nodename ) ), newstr( u.release ) ), newstr( u.version ) ), newstr( u.machine ) ), VAR_SET ); } } # endif /* unix */ /* load up environment variables */ /* first into global module, with splitting, for backward compatibility */ var_defines( use_environ, 1 ); /* then into .ENVIRON, without splitting */ enter_module( bindmodule(".ENVIRON") ); var_defines( use_environ, 0 ); exit_module( bindmodule(".ENVIRON") ); /* * Jam defined variables OS, OSPLAT * We load them after environment, so that * setting OS in environment does not * change Jam notion of the current platform. */ var_defines( othersyms, 1 ); /* Load up variables set on command line. */ for( n = 0; s = getoptval( optv, 's', n ); n++ ) { char *symv[2]; symv[0] = s; symv[1] = 0; var_defines( symv, 1 ); } /* Set the ARGV to reflect the complete list of arguments of invocation. */ for ( n = 0; n < arg_c; ++n ) { var_set( "ARGV", list_new( L0, newstr( arg_v[n] ) ), VAR_APPEND ); } /* Initialize built-in rules */ load_builtins(); /* Add the targets in the command line to update list */ for ( n = 1; n < arg_c; ++n ) { if ( arg_v[n][0] == '-' ) { char *f = "-:l:d:j:f:gs:t:ano:qv"; for( ; *f; f++ ) if( *f == arg_v[n][1] ) break; if ( f[1] == ':' && arg_v[n][2] == '\0' ) { ++n; } } else { mark_target_for_updating(arg_v[n]); } } /* Parse ruleset */ { FRAME frame[1]; frame_init( frame ); for( n = 0; s = getoptval( optv, 'f', n ); n++ ) parse_file( s, frame ); if( !n ) parse_file( "+", frame ); } status = yyanyerrors(); /* Manually touch -t targets */ for( n = 0; s = getoptval( optv, 't', n ); n++ ) touchtarget( s ); /* If an output file is specified, set globs.cmdout to that */ if( s = getoptval( optv, 'o', 0 ) ) { if( !( globs.cmdout = fopen( s, "w" ) ) ) { printf( "Failed to write to '%s'\n", s ); exit( EXITBAD ); } globs.noexec++; } /* Now make target */ { PROFILE_ENTER(MAIN_MAKE); LIST* targets = targets_to_update(); if ( !targets ) { status |= make( 1, &all, anyhow ); } else { int targets_count = list_length(targets); const char **targets2 = (const char **)malloc(targets_count * sizeof(char *)); int n = 0; if ( DEBUG_PROFILE ) profile_memory( targets_count * sizeof(char *) ); for ( ; targets; targets = list_next(targets) ) { targets2[n++] = targets->string; } status |= make( targets_count, targets2, anyhow ); free(targets); } PROFILE_EXIT(MAIN_MAKE); } PROFILE_EXIT(MAIN); } if ( DEBUG_PROFILE ) profile_dump(); /* Widely scattered cleanup */ var_done(); file_done(); donerules(); donestamps(); donestr(); /* close cmdout */ if( globs.cmdout ) fclose( globs.cmdout ); #ifdef HAVE_PYTHON Py_Finalize(); #endif return status ? EXITBAD : EXITOK; }