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/* 16 * jam.c - make redux 17 * 18 * See Jam.html for usage information. 19 * 20 * These comments document the code. 21 * 22 * The top half of the code is structured such: 23 * 24 * jam 25 * / | \ 26 * +---+ | \ 27 * / | \ 28 * jamgram option \ 29 * / | \ \ 30 * / | \ \ 31 * / | \ | 32 * scan | compile make 33 * | | / | \ / | \ 34 * | | / | \ / | \ 35 * | | / | \ / | \ 36 * jambase parse | rules search make1 37 * | | | \ 38 * | | | \ 39 * | | | \ 40 * builtins timestamp command execute 41 * | 42 * | 43 * | 44 * filesys 45 * 46 * 47 * The support routines are called by all of the above, but themselves 48 * are layered thus: 49 * 50 * variable|expand 51 * / | | | 52 * / | | | 53 * / | | | 54 * lists | | pathsys 55 * \ | | 56 * \ | | 57 * \ | | 58 * newstr | 59 * \ | 60 * \ | 61 * \ | 62 * hash 63 * 64 * Roughly, the modules are: 65 * 66 * builtins.c - jam's built-in rules 67 * command.c - maintain lists of commands 68 * compile.c - compile parsed jam statements 69 * execunix.c - execute a shell script on UNIX 70 * execvms.c - execute a shell script, ala VMS 71 * expand.c - expand a buffer, given variable values 72 * file*.c - scan directories and archives on * 73 * hash.c - simple in-memory hashing routines 74 * headers.c - handle #includes in source files 75 * jambase.c - compilable copy of Jambase 76 * jamgram.y - jam grammar 77 * lists.c - maintain lists of strings 78 * make.c - bring a target up to date, once rules are in place 79 * make1.c - execute command to bring targets up to date 80 * newstr.c - string manipulation routines 81 * option.c - command line option processing 82 * parse.c - make and destroy parse trees as driven by the parser 83 * path*.c - manipulate file names on * 84 * hash.c - simple in-memory hashing routines 85 * regexp.c - Henry Spencer's regexp 86 * rules.c - access to RULEs, TARGETs, and ACTIONs 87 * scan.c - the jam yacc scanner 88 * search.c - find a target along $(SEARCH) or $(LOCATE) 89 * timestamp.c - get the timestamp of a file or archive member 90 * variable.c - handle jam multi-element variables 91 * 92 * 05/04/94 (seiwald) - async multiprocess (-j) support 93 * 02/08/95 (seiwald) - -n implies -d2. 94 * 02/22/95 (seiwald) - -v for version info. 95 * 09/11/00 (seiwald) - PATCHLEVEL folded into VERSION. 96 * 01/10/01 (seiwald) - pathsys.h split from filesys.h 97 * 01/21/02 (seiwald) - new -q to quit quickly on build failure 98 * 03/16/02 (seiwald) - support for -g (reorder builds by source time) 99 * 09/19/02 (seiwald) - new -d displays 100 * 10/22/02 (seiwald) - list_new() now does its own newstr()/copystr() 101 * 11/04/02 (seiwald) - const-ing for string literals 102 */ 103 104# include "jam.h" 105# include "option.h" 106# include "patchlevel.h" 107 108/* These get various function declarations. */ 109 110# include "lists.h" 111# include "parse.h" 112# include "variable.h" 113# include "compile.h" 114# include "builtins.h" 115# include "jcache.h" 116# include "rules.h" 117# include "newstr.h" 118# include "scan.h" 119# include "timestamp.h" 120# include "make.h" 121 122/* Macintosh is "special" */ 123 124# ifdef OS_MAC 125# include <QuickDraw.h> 126# endif 127 128/* And UNIX for this */ 129 130# ifdef unix 131# include <sys/utsname.h> 132# endif 133 134struct globs globs = { 135 0, /* noexec */ 136 1, /* jobs */ 137 0, /* quitquick */ 138 0, /* newestfirst */ 139# ifdef OS_MAC 140 { 0 }, /* display - suppress actions output */ 141# else 142 { 0, 1 }, /* display actions */ 143# endif 144 0 /* output commands, not run them */ 145} ; 146 147/* Symbols to be defined as true for use in Jambase */ 148 149static const char *othersyms[] = { OSMAJOR, OSMINOR, OSPLAT, JAMVERSYM, 0 } ; 150 151/* Known for sure: 152 * mac needs arg_enviro 153 * OS2 needs extern environ 154 */ 155 156# ifdef OS_MAC 157# define use_environ arg_environ 158# ifdef MPW 159QDGlobals qd; 160# endif 161# endif 162 163# ifndef use_environ 164# define use_environ environ 165# if !defined( __WATCOM__ ) && !defined( OS_OS2 ) && !defined( OS_NT ) 166extern char **environ; 167# endif 168# endif 169 170main( int argc, char **argv, char **arg_environ ) 171{ 172 int n; 173 const char *s; 174 struct option optv[N_OPTS]; 175 const char *all = "all"; 176 int anyhow = 0; 177 int status; 178 179# ifdef OS_MAC 180 InitGraf(&qd.thePort); 181# endif 182 183 argc--, argv++; 184 185 if( ( n = getoptions( argc, argv, "d:j:f:gs:t:ano:qv", optv ) ) < 0 ) 186 { 187 printf( "\nusage: jam [ options ] targets...\n\n" ); 188 189 printf( "-a Build all targets, even if they are current.\n" ); 190 printf( "-dx Display (a)actions (c)causes (d)dependencies\n" ); 191 printf( " (m)make tree (x)commands (0-9) debug levels.\n" ); 192# ifdef OPT_RULE_PROFILING_EXT 193 printf( " (p)profile rules.\n" ); 194# endif 195 printf( "-fx Read x instead of Jambase.\n" ); 196 printf( "-g Build from newest sources first.\n" ); 197 printf( "-jx Run up to x shell commands concurrently.\n" ); 198 printf( "-n Don't actually execute the updating actions.\n" ); 199 printf( "-ox Write the updating actions to file x.\n" ); 200 printf( "-q Quit quickly as soon as a target fails.\n" ); 201 printf( "-sx=y Set variable x=y, overriding environment.\n" ); 202 printf( "-tx Rebuild x, even if it is up-to-date.\n" ); 203 printf( "-v Print the version of jam and exit.\n\n" ); 204 205 exit( EXITBAD ); 206 } 207 208 argc -= n, argv += n; 209 210 /* Version info. */ 211 212 if( ( s = getoptval( optv, 'v', 0 ) ) ) 213 { 214 printf( "Jam %s. %s. ", VERSION, OSMINOR ); 215 printf( "Copyright 1993-2002 Christopher Seiwald.\n" ); 216 217 return EXITOK; 218 } 219 220 /* Pick up interesting options */ 221 222 if( ( s = getoptval( optv, 'n', 0 ) ) ) 223 globs.noexec++, DEBUG_MAKE = DEBUG_MAKEQ = DEBUG_EXEC = 1; 224 225 if( ( s = getoptval( optv, 'q', 0 ) ) ) 226 globs.quitquick = 1; 227 228 if( ( s = getoptval( optv, 'a', 0 ) ) ) 229 anyhow++; 230 231 if( ( s = getoptval( optv, 'j', 0 ) ) ) 232 { 233 globs.jobs = atoi( s ); 234 var_set( "JAMJOBS", list_new( L0, s, 0 ), VAR_SET ); 235 } 236 237 if( ( s = getoptval( optv, 'g', 0 ) ) ) 238 globs.newestfirst = 1; 239 240 /* Turn on/off debugging */ 241 242 for( n = 0; s = getoptval( optv, 'd', n ); n++ ) 243 { 244 int i = atoi( s ); 245 246 /* First -d, turn off defaults. */ 247 248 if( !n ) 249 DEBUG_MAKE = DEBUG_MAKEQ = DEBUG_EXEC = 0; 250 251 /* n turns on levels 1-n */ 252 /* +n turns on level n */ 253 /* c turns on named display c */ 254 255 if( i < 0 || i >= DEBUG_MAX ) 256 { 257 printf( "Invalid debug level '%s'.\n", s ); 258 } 259 else if( *s == '+' ) 260 { 261 globs.debug[i] = 1; 262 } 263 else if( i ) while( i ) 264 { 265 globs.debug[i--] = 1; 266 } 267 else while( *s ) switch( *s++ ) 268 { 269 case 'a': DEBUG_MAKE = DEBUG_MAKEQ = 1; break; 270 case 'c': DEBUG_CAUSES = 1; break; 271 case 'd': DEBUG_DEPENDS = 1; break; 272 case 'm': DEBUG_MAKEPROG = 1; break; 273 case 'x': DEBUG_EXEC = 1; break; 274# ifdef OPT_RULE_PROFILING_EXT 275 case 'p': DEBUG_PROFILE_RULES = 1; break; 276# endif 277 case '0': break; 278 default: printf( "Invalid debug flag '%c'.\n", s[-1] ); 279 } 280 } 281 282 /* Set JAMDATE first */ 283 284 { 285 char buf[ 128 ]; 286 time_t clock; 287 time( &clock ); 288 strcpy( buf, ctime( &clock ) ); 289 290 /* Trim newline from date */ 291 292 if( strlen( buf ) == 25 ) 293 buf[ 24 ] = 0; 294 295 var_set( "JAMDATE", list_new( L0, buf, 0 ), VAR_SET ); 296 } 297 298 /* And JAMUNAME */ 299# ifdef unix 300 { 301 struct utsname u; 302 303 if( uname( &u ) >= 0 ) 304 { 305 LIST *l = L0; 306 l = list_new( l, u.machine, 0 ); 307 l = list_new( l, u.version, 0 ); 308 l = list_new( l, u.release, 0 ); 309 l = list_new( l, u.nodename, 0 ); 310 l = list_new( l, u.sysname, 0 ); 311 var_set( "JAMUNAME", l, VAR_SET ); 312 } 313 } 314# endif /* unix */ 315 316 /* 317 * Jam defined variables OS, OSPLAT 318 */ 319 320 var_defines( othersyms ); 321 322 /* load up environment variables */ 323 324 var_defines( (const char **)use_environ ); 325 326#ifdef OPT_JAM_TARGETS_VARIABLE_EXT 327 /* define the variable JAM_TARGETS containing the targets specified on 328 the command line */ 329 { 330 LIST *l = L0; 331 int i; 332 char **targets = argv; 333 int targetCount = argc; 334 if (targetCount == 0) { 335 targets = (char**)&all; 336 targetCount = 1; 337 } 338 339 for (i = 0; i < targetCount; i++) 340 l = list_new( l, targets[i], 0 ); 341 342 var_set( "JAM_TARGETS", l, VAR_SET ); 343 } 344#endif 345 346 /* Load up variables set on command line. */ 347 348 for( n = 0; s = getoptval( optv, 's', n ); n++ ) 349 { 350 const char *symv[2]; 351 symv[0] = s; 352 symv[1] = 0; 353 var_defines( symv ); 354 } 355 356 /* Initialize built-in rules */ 357 358 load_builtins(); 359 360 /* Parse ruleset */ 361#ifdef OPT_JAMFILE_CACHE_EXT 362 jcache_init(); 363#endif 364 365 for( n = 0; s = getoptval( optv, 'f', n ); n++ ) 366 parse_file( s ); 367 368 if( !n ) 369 parse_file( "+" ); 370 371#ifdef OPT_JAMFILE_CACHE_EXT 372 jcache_done(); 373#endif 374 375 status = yyanyerrors(); 376 377 /* Manually touch -t targets */ 378 379 for( n = 0; s = getoptval( optv, 't', n ); n++ ) 380 touchtarget( s ); 381 382 /* If an output file is specified, set globs.cmdout to that */ 383 384 if( s = getoptval( optv, 'o', 0 ) ) 385 { 386 if( !( globs.cmdout = fopen( s, "w" ) ) ) 387 { 388 printf( "Failed to write to '%s'\n", s ); 389 exit( EXITBAD ); 390 } 391 globs.noexec++; 392 } 393 394#ifdef OPT_JAM_TARGETS_VARIABLE_EXT 395 /* get value of variable JAM_TARGETS and build the targets */ 396 { 397 LIST *l = var_get( "JAM_TARGETS" ); 398 int targetCount = list_length(l); 399 char **targets; 400 int i; 401 402 if (targetCount == 0) { 403 /* No targets. Nothing to do. */ 404 exit( EXITOK ); 405 } 406 407 targets = malloc(targetCount * sizeof(char*)); 408 if (!targets) { 409 printf( "Memory allocation failed!\n" ); 410 exit( EXITBAD ); 411 } 412 413 for (i = 0; i < targetCount; i++) { 414 targets[i] = (char*)l->string; 415 l = l->next; 416 } 417 418 argv = targets; 419 argc = targetCount; 420 } 421#endif 422 423 /* Now make target */ 424 425 if( !argc ) 426 status |= make( 1, &all, anyhow ); 427 else 428 status |= make( argc, (const char **)argv, anyhow ); 429 430 /* Widely scattered cleanup */ 431 432 var_done(); 433 donerules(); 434 donestamps(); 435 donestr(); 436 437 /* close cmdout */ 438 439 if( globs.cmdout ) 440 fclose( globs.cmdout ); 441 442 return status ? EXITBAD : EXITOK; 443} 444