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.
17 * See Jam.html for usage information.
19 * These comments document the code.
21 * The top half of the code is structured such:
35 * jambase parse | rules search make1
39 * builtins timestamp command execute
46 * The support routines are called by all of the above, but themselves
63 * Roughly, the modules are:
65 * builtins.c - jam's built-in rules
66 * command.c - maintain lists of commands
67 * compile.c - compile parsed jam statements
68 * execcmd.c - execute a shell script on UNIX
69 * expand.c - expand a buffer, given variable values
70 * file*.c - scan directories and archives on *
71 * hash.c - simple in-memory hashing routines
72 * headers.c - handle #includes in source files
73 * jambase.c - compilable copy of Jambase
74 * jamgram.y - jam grammar
75 * lists.c - maintain lists of strings
76 * make.c - bring a target up to date, once rules are in place
77 * make1.c - execute command to bring targets up to date
78 * newstr.c - string manipulation routines
79 * option.c - command line option processing
80 * parse.c - make and destroy parse trees as driven by the parser
81 * path*.c - manipulate file names on *
82 * hash.c - simple in-memory hashing routines
83 * hsregexp.c - Henry Spencer's regexp
84 * rules.c - access to RULEs, TARGETs, and ACTIONs
85 * scan.c - the jam yacc scanner
86 * search.c - find a target along $(SEARCH) or $(LOCATE)
87 * timestamp.c - get the timestamp of a file or archive member
88 * variable.c - handle jam multi-element variables
90 * 05/04/94 (seiwald) - async multiprocess (-j) support
91 * 02/08/95 (seiwald) - -n implies -d2.
92 * 02/22/95 (seiwald) - -v for version info.
93 * 09/11/00 (seiwald) - PATCHLEVEL folded into VERSION.
94 * 01/10/01 (seiwald) - pathsys.h split from filesys.h
95 * 01/21/02 (seiwald) - new -q to quit quickly on build failure
96 * 03/16/02 (seiwald) - support for -g (reorder builds by source time)
97 * 09/19/02 (seiwald) - new -d displays
98 * 10/22/02 (seiwald) - list_new() now does its own newstr()/copystr()
99 * 11/04/02 (seiwald) - const-ing for string literals
104 #include "patchlevel.h"
106 /* These get various function declarations. */
109 #include "variable.h"
111 #include "builtins.h"
115 #include "timestamp.h"
119 /* And UNIX for this */
121 # include <sys/utsname.h>
125 struct globs globs
= {
129 .newestfirst
= 0, /* newestfirst */
130 .debug
= { 0, 1 }, /* display actions */
131 .cmdout
= NULL
, /* output commands, not run them */
132 //#ifdef OPT_IMPROVED_PROGRESS_EXT
139 /* symbols to be defined as true for use in Jambase */
140 static const char *othersyms
[] = { OSMAJOR
, OSMINOR
, OSPLAT
, JAMVERSYM
, 0 } ;
144 * OS2 needs extern environ
147 # define use_environ environ
148 # if !defined(__WATCOM__) && !defined(OS_OS2) && !defined(OS_NT)
149 extern char **environ
;
154 static void fixJobs (void) {
155 LIST
*var
= var_get("K8JAM-JOBS"); /*FIXME: a perfectly idiotic name*/
159 int cnt
= list_length(var
);
164 int jj
= atoi(var
->string
);
166 if (jj
< 1) jj
= 1; else if (jj
> 64) jj
= 64;
171 if (globs
.jobs
< 1) globs
.jobs
= 1; else if (globs
.jobs
> 64) globs
.jobs
= 64;
172 sprintf(buf
, "%d", globs
.jobs
);
173 var
= list_new(L0
, buf
, 0);
174 var_set("K8JAM-JOBS", var
, VAR_SET
);
178 int main (int argc
, char **argv
, char **arg_environ
) {
181 struct option optv
[N_OPTS
];
182 char *targets
[N_TARGETS
];
183 const char *all
= "all";
189 if ((num_targets
= getoptions(argc
, argv
, "H:d:j:f:gs:t:ano:qvZW", optv
, targets
)) < 0) {
190 printf("usage: jam [ options ] targets...\n\n"
191 "-a Build all targets, even if they are current.\n"
192 "-dx Display (a)actions (c)causes (d)dependencies\n"
193 " (m)make tree (x)commands (0-9) debug levels.\n"
194 "-fx Read x instead of Jambase.\n"
195 "-g Build from newest sources first.\n"
196 "-jx Run up to x shell commands concurrently.\n"
197 "-n Don't actually execute the updating actions.\n"
198 "-ox Write the updating actions to file x.\n"
199 "-q Quit quickly as soon as a target fails.\n"
200 "-sx=y Set variable x=y, overriding environment.\n"
201 "-tx Rebuild x, even if it is up-to-date.\n"
202 "-v Print the version of jam and exit.\n"
203 "-Hx Show header cache statistics (a)ll, (h)its, (s)tats.\n"
204 "-Z Register old-style all-upper builtins.\n"
205 "-W Write built-in Jambase and exit.\n"
210 if ((s
= getoptval(optv
, 'v', 0))) {
211 printf("K8-Jam %s. %s. ", VERSION
, OSMINOR
);
213 "(C) 1993-2003 Christopher Seiwald, see http://www.freetype.org/jam/\n"
214 "changes by Ketmar // Vampire Avalon, psyc://ketmar.no-ip.org/~ketmar\n"
218 /* pick up interesting options */
219 if ((s
= getoptval(optv
, 'W', 0))) {
220 FILE *fl
= fopen("Jambase", "w");
223 printf("writing Jambase...\n");
225 for (int f
= 0; jambase
[f
]; ++f
) fprintf(fl
, "%s", jambase
[f
]);
230 if ((s
= getoptval(optv
, 'n', 0))) ++globs
.noexec
, DEBUG_MAKE
= DEBUG_MAKEQ
= DEBUG_EXEC
= 1;
231 if ((s
= getoptval(optv
, 'q', 0))) globs
.quitquick
= 1;
232 if ((s
= getoptval(optv
, 'a', 0))) ++anyhow
;
233 if ((s
= getoptval(optv
, 'j', 0))) globs
.jobs
= atoi(s
);
234 if ((s
= getoptval(optv
, 'g', 0))) globs
.newestfirst
= 1;
235 if ((s
= getoptval(optv
, 'Z', 0))) compat_old_builtin_names
= 1;
236 /* turn on/off debugging */
237 for (n
= 0; (s
= getoptval(optv
, 'd', n
)) != 0; ++n
) {
239 /* first -d, turn off defaults. */
240 if (!n
) DEBUG_MAKE
= DEBUG_MAKEQ
= DEBUG_EXEC
= 0;
241 /* n turns on levels 1-n */
242 /* +n turns on level n */
243 /* c turns on named display c */
244 if (i
< 0 || i
>= DEBUG_MAX
) {
245 printf( "Invalid debug level '%s'.\n", s
);
246 } else if (*s
== '+') {
249 while (i
) globs
.debug
[i
--] = 1;
253 case 'a': DEBUG_MAKE
= DEBUG_MAKEQ
= 1; break;
254 case 'c': DEBUG_CAUSES
= 1; break;
255 case 'd': DEBUG_DEPENDS
= 1; break;
256 case 'm': DEBUG_MAKEPROG
= 1; break;
257 case 'x': DEBUG_EXEC
= 1; break;
258 case 'h': DEBUG_HEADER
= 1; break;
260 default: printf("Invalid debug flag '%c'.\n", s
[-1]);
265 /* header cache statistics */
266 for (n
= 0; (s
= getoptval(optv
, 'H', n
)) != 0; ++n
) {
270 case 'a': optShowHCacheStats
= optShowHCacheInfo
= 1; break;
271 case 'h': optShowHCacheInfo
= 1; break;
272 case 's': optShowHCacheStats
= 1; break;
276 if (wasOptH
&& (optShowHCacheStats
== 0 && optShowHCacheInfo
== 0)) optShowHCacheStats
= optShowHCacheInfo
= 1;
277 /* set JAMDATE first */
283 strcpy(buf
, ctime(&clock
));
284 /* trim newline from date */
286 while (p
>= buf
&& *((unsigned char *)p
) <= ' ') --p
;
288 var_set("JAMDATE", list_new(L0
, buf
, 0), VAR_SET
);
295 if (uname(&u
) >= 0) {
297 l
= list_new(l
, u
.machine
, 0);
298 l
= list_new(l
, u
.version
, 0);
299 l
= list_new(l
, u
.release
, 0);
300 l
= list_new(l
, u
.nodename
, 0);
301 l
= list_new(l
, u
.sysname
, 0);
302 var_set("JAMUNAME", l
, VAR_SET
);
306 /* Jam defined variables OS, OSPLAT */
307 var_defines(othersyms
, 1);
308 /* load up environment variables */
309 var_defines((const char **)use_environ
, 0);
310 /* load up variables set on command line. */
311 for (n
= 0; (s
= getoptval(optv
, 's', n
)) != 0; ++n
) {
315 var_defines(symv
, 1);
319 LIST
*l0
= L0
, *l1
= L0
;
321 if (num_targets
< 1) {
322 l0
= list_new(l0
, "all", 0);
323 l1
= list_new(l1
, "all", 0);
325 for (n
= 0; n
< num_targets
; ++n
) {
326 //printf("target %i: %s\n", n, targets[n]);
327 l0
= list_new(l0
, targets
[n
], 0);
328 l1
= list_new(l1
, targets
[n
], 0);
331 var_set("JAMCMDARGS", l0
, VAR_SET
);
333 var_set("JAM_TARGETS", l1
, VAR_SET
);
335 /* initialize built-in rules */
338 for (n
= 0; (s
= getoptval(optv
, 'f', n
)) != 0; ++n
) parse_file(s
);
339 if (!n
) parse_file("::Jambase");
340 status
= yyanyerrors();
341 /* manually touch -t targets */
342 for (n
= 0; (s
= getoptval(optv
, 't', n
)) != 0; ++n
) touchtarget(s
);
343 /* if an output file is specified, set globs.cmdout to that */
344 if ((s
= getoptval(optv
, 'o', 0)) != 0) {
345 if (!(globs
.cmdout
= fopen(s
, "w"))) {
346 printf("Failed to write to '%s'\n", s
);
351 /* fix number of jobs (if necessary) */
353 #ifndef NO_OPT_JAM_TARGETS_VARIABLE_EXT
354 /* ported from Haiku */
355 /* get value of variable JAM_TARGETS and build the targets */
357 LIST
*l
= var_get("JAM_TARGETS");
358 int targetCount
= list_length(l
);
361 if (targetCount
== 0) {
362 /* no targets: nothing to do */
363 printf("No targets. Nothing to do.\n");
366 if (targetCount
>= N_TARGETS
) {
367 printf("ERROR: Too many targets!\n");
370 for (i
= 0; i
< targetCount
; ++i
) {
371 const char *s0
= l
->string
;
372 targets
[i
] = malloc((strlen(s0
)+1)*sizeof(char));
374 printf("ERROR: Out of memory!\n");
377 strcpy(targets
[i
], s0
);
380 num_targets
= targetCount
;
382 printf("new targets:\n");
383 for (i = 0; i < num_targets; i++) {
384 printf("target %i: %s\n", i, targets[i]);
389 /* now make target */
390 if (!num_targets
) status
|= make(1, &all
, anyhow
);
391 else status
|= make(num_targets
, (const char **)targets
, anyhow
);
392 /* widely scattered cleanup */
398 if (globs
.cmdout
) fclose(globs
.cmdout
);
399 return status
? EXITBAD
: EXITOK
;