Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/tools/jam/src/jam.c @ 29

Last change on this file since 29 was 29, checked in by landauf, 17 years ago

updated boost from 1_33_1 to 1_34_1

File size: 13.5 KB
Line 
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/*  This file is ALSO:
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 http://www.boost.org/LICENSE_1_0.txt)
19 */
20
21/*
22 * jam.c - make redux
23 *
24 * See Jam.html for usage information.
25 *
26 * These comments document the code.
27 *
28 * The top half of the code is structured such:
29 *
30 *                       jam
31 *                      / | \
32 *                 +---+  |  \
33 *                /       |   \
34 *         jamgram     option  \
35 *        /  |   \              \
36 *       /   |    \              \
37 *      /    |     \             |
38 *  scan     |     compile      make
39 *   |       |    /  | \       / |  \
40 *   |       |   /   |  \     /  |   \
41 *   |       |  /    |   \   /   |    \
42 * jambase parse     |   rules  search make1
43 *                   |           |      |   \
44 *                   |           |      |    \
45 *                   |           |      |     \
46 *               builtins    timestamp command execute
47 *                               |
48 *                               |
49 *                               |
50 *                             filesys
51 *
52 *
53 * The support routines are called by all of the above, but themselves
54 * are layered thus:
55 *
56 *                     variable|expand
57 *                      /  |   |   |
58 *                     /   |   |   |
59 *                    /    |   |   |
60 *                 lists   |   |   pathsys
61 *                    \    |   |
62 *                     \   |   |
63 *                      \  |   |
64 *                     newstr  |
65 *                        \    |
66 *                         \   |
67 *                          \  |
68 *                          hash
69 *
70 * Roughly, the modules are:
71 *
72 *      builtins.c - jam's built-in rules
73 *      command.c - maintain lists of commands
74 *      compile.c - compile parsed jam statements
75 *      execunix.c - execute a shell script on UNIX
76 *      execvms.c - execute a shell script, ala VMS
77 *      expand.c - expand a buffer, given variable values
78 *      file*.c - scan directories and archives on *
79 *      hash.c - simple in-memory hashing routines
80 *  hdrmacro.c - handle header file parsing for filename macro definitions
81 *      headers.c - handle #includes in source files
82 *      jambase.c - compilable copy of Jambase
83 *      jamgram.y - jam grammar
84 *      lists.c - maintain lists of strings
85 *      make.c - bring a target up to date, once rules are in place
86 *      make1.c - execute command to bring targets up to date
87 *      newstr.c - string manipulation routines
88 *      option.c - command line option processing
89 *      parse.c - make and destroy parse trees as driven by the parser
90 *      path*.c - manipulate file names on *
91 *      hash.c - simple in-memory hashing routines
92 *      regexp.c - Henry Spencer's regexp
93 *      rules.c - access to RULEs, TARGETs, and ACTIONs
94 *      scan.c - the jam yacc scanner
95 *      search.c - find a target along $(SEARCH) or $(LOCATE)
96 *      timestamp.c - get the timestamp of a file or archive member
97 *      variable.c - handle jam multi-element variables
98 *
99 * 05/04/94 (seiwald) - async multiprocess (-j) support
100 * 02/08/95 (seiwald) - -n implies -d2.
101 * 02/22/95 (seiwald) - -v for version info.
102 * 09/11/00 (seiwald) - PATCHLEVEL folded into VERSION.
103 * 01/10/01 (seiwald) - pathsys.h split from filesys.h
104 */
105
106# include "jam.h"
107# include "option.h"
108# include "patchlevel.h"
109
110/* These get various function declarations. */
111
112# include "lists.h"
113# include "parse.h"
114# include "variable.h"
115# include "compile.h"
116# include "builtins.h"
117# include "rules.h"
118# include "newstr.h"
119# include "scan.h"
120# include "timestamp.h"
121# include "make.h"
122# include "strings.h"
123# include "expand.h"
124# include "debug.h"
125# include "filesys.h"
126
127/* Macintosh is "special" */
128
129# ifdef OS_MAC
130# include <QuickDraw.h>
131# endif
132
133/* And UNIX for this */
134
135# ifdef unix
136# include <sys/utsname.h>
137# endif
138
139struct globs globs = {
140        0,                      /* noexec */
141        1,                      /* jobs */
142        0,                      /* quitquick */
143        0,                      /* newestfirst */
144# ifdef OS_MAC
145        { 0, 0 },               /* debug - suppress tracing output */
146# else
147        { 0, 1 },               /* debug ... */
148# endif
149        0,                      /* output commands, not run them */
150    0 /* action timeout */
151} ;
152
153/* Symbols to be defined as true for use in Jambase */
154
155static char *othersyms[] = { OSMAJOR, OSMINOR, OSPLAT, JAMVERSYM, 0 } ;
156
157/* Known for sure:
158 *      mac needs arg_enviro
159 *      OS2 needs extern environ
160 */
161
162# ifdef OS_MAC
163# define use_environ arg_environ
164# ifdef MPW
165QDGlobals qd;
166# endif
167# endif
168
169/* on Win32-LCC */
170# if defined( OS_NT ) && defined( __LCC__ )
171#   define  use_environ _environ
172# endif
173
174# if defined( __MWERKS__)
175# define use_environ _environ
176extern char **_environ;
177#endif
178
179# ifndef use_environ
180# define use_environ environ
181# if !defined( __WATCOM__ ) && !defined( OS_OS2 ) && !defined( OS_NT )
182extern char **environ;
183# endif
184# endif
185
186# if YYDEBUG != 0
187extern int yydebug;
188# endif
189
190#ifndef NDEBUG
191static void run_unit_tests()
192{
193# if defined( USE_EXECNT )
194    extern void execnt_unit_test();
195    execnt_unit_test();
196# endif
197    string_unit_test();
198    var_expand_unit_test();
199}
200#endif
201
202#ifdef HAVE_PYTHON
203    extern PyObject*
204    bjam_call(PyObject *self, PyObject *args);
205 
206    extern PyObject*
207    bjam_import_rule(PyObject* self, PyObject* args);
208#endif
209
210int  main( int argc, char **argv, char **arg_environ )
211{
212    int         n;
213    char                *s;
214    struct option       optv[N_OPTS];
215    const char  *all = "all";
216    int         anyhow = 0;
217    int         status;
218    int arg_c = argc;
219    char ** arg_v = argv;
220    const char *progname = argv[0];
221
222# ifdef OS_MAC
223    InitGraf(&qd.thePort);
224# endif
225
226    argc--, argv++;
227
228        if( getoptions( argc, argv, "-:l:d:j:f:gs:t:ano:qv", optv ) < 0 )
229    {
230        printf( "\nusage: %s [ options ] targets...\n\n", progname );
231
232        printf( "-a      Build all targets, even if they are current.\n" );
233        printf( "-dx     Set the debug level to x (0-9).\n" );
234        printf( "-fx     Read x instead of Jambase.\n" );
235            /* printf( "-g      Build from newest sources first.\n" ); */
236        printf( "-jx     Run up to x shell commands concurrently.\n" );
237        printf( "-lx     Limit actions to x number of seconds after which they are stopped.\n" );
238        printf( "-n      Don't actually execute the updating actions.\n" );
239        printf( "-ox     Write the updating actions to file x.\n" );
240                printf( "-q      Quit quickly as soon as a target fails.\n" );
241        printf( "-sx=y   Set variable x=y, overriding environment.\n" );
242        printf( "-tx     Rebuild x, even if it is up-to-date.\n" );
243        printf( "-v      Print the version of jam and exit.\n" );
244        printf( "--x     Option is ignored.\n\n" );
245
246        exit( EXITBAD );
247    }
248
249    /* Version info. */
250
251    if( ( s = getoptval( optv, 'v', 0 ) ) )
252    {
253        printf( "Boost.Jam  " );
254        printf( "Version %s. %s.\n", VERSION, OSMINOR );
255           printf( "   Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.  \n" );
256        printf( "   Copyright 2001 David Turner.\n" );
257        printf( "   Copyright 2001-2004 David Abrahams.\n" );
258        printf( "   Copyright 2002-2005 Rene Rivera.\n" );
259        printf( "   Copyright 2003-2005 Vladimir Prus.\n" );
260
261        return EXITOK;
262    }
263
264    /* Pick up interesting options */
265
266    if( ( s = getoptval( optv, 'n', 0 ) ) )
267        globs.noexec++, globs.debug[2] = 1;
268
269        if( ( s = getoptval( optv, 'q', 0 ) ) )
270            globs.quitquick = 1;
271    if( ( s = getoptval( optv, 'a', 0 ) ) )
272        anyhow++;
273
274    if( ( s = getoptval( optv, 'j', 0 ) ) )
275        globs.jobs = atoi( s );
276
277        if( ( s = getoptval( optv, 'g', 0 ) ) )
278            globs.newestfirst = 1;
279
280    if( ( s = getoptval( optv, 'l', 0 ) ) )
281        globs.timeout = atoi( s );
282
283    /* Turn on/off debugging */
284
285    for( n = 0; s = getoptval( optv, 'd', n ); n++ )
286    {
287        int i;
288
289        /* First -d, turn off defaults. */
290
291        if( !n )
292            for( i = 0; i < DEBUG_MAX; i++ )
293                globs.debug[i] = 0;
294
295        i = atoi( s );
296
297        if( i < 0 || i >= DEBUG_MAX )
298        {
299            printf( "Invalid debug level '%s'.\n", s );
300            continue;
301        }
302
303        /* n turns on levels 1-n */
304        /* +n turns on level n */
305
306        if( *s == '+' )
307            globs.debug[i] = 1;
308        else while( i )
309            globs.debug[i--] = 1;
310    }
311
312    { PROFILE_ENTER(MAIN);
313
314    #ifdef HAVE_PYTHON
315    {
316        PROFILE_ENTER(MAIN_PYTHON);
317        Py_Initialize();
318   
319        {
320            static PyMethodDef BjamMethods[] = {
321                {"call", bjam_call, METH_VARARGS,
322                 "Call the specified bjam rule."},
323                {"import_rule", bjam_import_rule, METH_VARARGS,
324                 "Imports Python callable to bjam."},
325                {NULL, NULL, 0, NULL}
326            };
327   
328            Py_InitModule("bjam", BjamMethods);
329        }
330        PROFILE_EXIT(MAIN_PYTHON);
331    }
332    #endif
333   
334#ifndef NDEBUG
335    run_unit_tests();
336#endif
337#if YYDEBUG != 0
338    if ( DEBUG_PARSE )
339        yydebug = 1;
340#endif
341
342    /* Set JAMDATE first */
343
344    {
345        char *date;
346        time_t clock;
347        time( &clock );
348        date = newstr( ctime( &clock ) );
349
350        /* Trim newline from date */
351
352        if( strlen( date ) == 25 )
353            date[ 24 ] = 0;
354
355        var_set( "JAMDATE", list_new( L0, newstr( date ) ), VAR_SET );
356    }
357
358 
359    var_set( "JAM_VERSION",
360             list_new( list_new( list_new( L0, newstr( VERSION_MAJOR_SYM ) ), 
361                                 newstr( VERSION_MINOR_SYM ) ), 
362                       newstr( VERSION_PATCH_SYM ) ),
363             VAR_SET );
364
365    /* And JAMUNAME */
366# ifdef unix
367    {
368        struct utsname u;
369
370        if( uname( &u ) >= 0 )
371        {
372            var_set( "JAMUNAME", 
373                     list_new( 
374                         list_new(
375                             list_new(
376                                 list_new(
377                                     list_new( L0, 
378                                               newstr( u.sysname ) ),
379                                     newstr( u.nodename ) ),
380                                 newstr( u.release ) ),
381                             newstr( u.version ) ),
382                         newstr( u.machine ) ), VAR_SET );
383        }
384    }
385# endif /* unix */
386
387    /* load up environment variables */
388
389    /* first into global module, with splitting, for backward compatibility */
390    var_defines( use_environ, 1 );
391   
392    /* then into .ENVIRON, without splitting */
393    enter_module( bindmodule(".ENVIRON") );
394    var_defines( use_environ, 0 );
395    exit_module( bindmodule(".ENVIRON") );
396
397        /*
398         * Jam defined variables OS, OSPLAT
399     * We load them after environment, so that
400     * setting OS in environment does not
401     * change Jam notion of the current platform.
402         */
403
404    var_defines( othersyms, 1 );
405
406
407    /* Load up variables set on command line. */
408
409    for( n = 0; s = getoptval( optv, 's', n ); n++ )
410    {
411        char *symv[2];
412        symv[0] = s;
413        symv[1] = 0;
414        var_defines( symv, 1 );
415    }
416
417    /* Set the ARGV to reflect the complete list of arguments of invocation. */
418
419    for ( n = 0; n < arg_c; ++n )
420    {
421        var_set( "ARGV", list_new( L0, newstr( arg_v[n] ) ), VAR_APPEND );
422    }
423
424        /* Initialize built-in rules */
425
426        load_builtins();
427
428    /* Add the targets in the command line to update list */
429
430    for ( n = 1; n < arg_c; ++n )
431    {
432        if ( arg_v[n][0] == '-' )
433        {
434            char *f = "-:l:d:j:f:gs:t:ano:qv";
435            for( ; *f; f++ ) if( *f == arg_v[n][1] ) break;
436            if ( f[1] == ':' && arg_v[n][2] == '\0' ) { ++n; }
437        }
438        else
439        {
440            mark_target_for_updating(arg_v[n]);
441        }
442    }
443
444    /* Parse ruleset */
445
446    {
447        FRAME frame[1];
448        frame_init( frame );
449        for( n = 0; s = getoptval( optv, 'f', n ); n++ )
450            parse_file( s, frame );
451
452        if( !n )
453            parse_file( "+", frame );
454    }
455
456    status = yyanyerrors();
457
458    /* Manually touch -t targets */
459
460    for( n = 0; s = getoptval( optv, 't', n ); n++ )
461        touchtarget( s );
462
463    /* If an output file is specified, set globs.cmdout to that */
464
465    if( s = getoptval( optv, 'o', 0 ) )
466    {
467        if( !( globs.cmdout = fopen( s, "w" ) ) )
468        {
469            printf( "Failed to write to '%s'\n", s );
470            exit( EXITBAD );
471        }
472        globs.noexec++;
473    }
474
475    /* Now make target */
476
477    {
478        PROFILE_ENTER(MAIN_MAKE);
479       
480        LIST* targets = targets_to_update();
481        if ( !targets )
482        {
483            status |= make( 1, &all, anyhow );
484        }
485        else 
486        {
487            int targets_count = list_length(targets);
488            const char **targets2 = (const char **)malloc(targets_count * sizeof(char *));
489            int n = 0;
490            if ( DEBUG_PROFILE )
491                profile_memory( targets_count * sizeof(char *) );
492            for ( ; targets; targets = list_next(targets) )
493            {
494                targets2[n++] = targets->string;
495            }
496            status |= make( targets_count, targets2, anyhow );       
497            free(targets);
498        }
499       
500        PROFILE_EXIT(MAIN_MAKE);
501    }
502
503
504    PROFILE_EXIT(MAIN); }
505   
506    if ( DEBUG_PROFILE )
507        profile_dump();
508
509    /* Widely scattered cleanup */
510
511    var_done();
512    file_done();
513    donerules();
514    donestamps();
515    donestr();
516
517    /* close cmdout */
518
519    if( globs.cmdout )
520        fclose( globs.cmdout );
521
522#ifdef HAVE_PYTHON
523    Py_Finalize();
524#endif
525
526
527    return status ? EXITBAD : EXITOK;
528}
Note: See TracBrowser for help on using the repository browser.