Beispiel #1
0
static const char * cache_name( void )
{
    static OBJECT * name = 0;
    if ( !name )
    {
        LIST * hcachevar = var_get( root_module(), constant_HCACHEFILE );

        if ( !list_empty( hcachevar ) )
        {
            TARGET * t = bindtarget( list_front( hcachevar ) );

            pushsettings( root_module(), t->settings );
            /* Do not expect the cache file to be generated, so pass 0 as the
             * third argument to search. Expect the location to be specified via
             * LOCATE, so pass 0 as the fourth arugment.
             */
            object_free( t->boundname );
            t->boundname = search( t->name, &t->time, 0, 0 );
            popsettings( root_module(), t->settings );

            name = object_copy( t->boundname );
        }
    }
    return name ? object_str( name ) : 0;
}
Beispiel #2
0
void call_bind_rule( OBJECT * target_, OBJECT * boundname_ )
{
    LIST * const bind_rule = var_get( root_module(), constant_BINDRULE );
    if ( !list_empty( bind_rule ) )
    {
        OBJECT * target = object_copy( target_ );
        OBJECT * boundname = object_copy( boundname_ );
        if ( boundname && target )
        {
            /* Prepare the argument list. */
            FRAME frame[ 1 ];
            frame_init( frame );

            /* First argument is the target name. */
            lol_add( frame->args, list_new( target ) );

            lol_add( frame->args, list_new( boundname ) );
            if ( lol_get( frame->args, 1 ) )
            {
                OBJECT * rulename = list_front( bind_rule );
                list_free( evaluate_rule( bindrule( rulename, root_module() ), rulename, frame ) );
            }

            /* Clean up */
            frame_free( frame );
        }
        else
        {
            if ( boundname )
                object_free( boundname );
            if ( target )
                object_free( target );
        }
    }
}
Beispiel #3
0
static void call_action_rule
(
    TARGET * target,
    int status,
    timing_info const * time,
    char const * executed_command,
    char const * command_output
)
{
    LIST * action_rule;

    pushsettings( root_module(), target->settings );
    action_rule = var_get( root_module(), constant_ACTION_RULE );
    popsettings( root_module(), target->settings );

    if ( !list_empty( action_rule ) )
    {
        /* rule action-rule (
            args * :
            target :
            command status start end user system :
            output ? ) */

        /* Prepare the argument list. */
        FRAME frame[ 1 ];
        OBJECT * rulename = list_front( action_rule );
        frame_init( frame );

        /* args * :: $(__ACTION_RULE__[2-]) */
        lol_add( frame->args, list_copy_range( action_rule, list_next(
            list_begin( action_rule ) ), list_end( action_rule ) ) );

        /* target :: the name of the target */
        lol_add( frame->args, list_new( object_copy( target->name ) ) );

        /* command status start end user system :: info about the action command
         */
        lol_add( frame->args,
            list_push_back( list_push_back( list_push_back( list_push_back( list_push_back( list_new(
                object_new( executed_command ) ),
                outf_int( status ) ),
                outf_time( &time->start ) ),
                outf_time( &time->end ) ),
                outf_double( time->user ) ),
                outf_double( time->system ) ) );

        /* output ? :: the output of the action command */
        if ( command_output )
            lol_add( frame->args, list_new( object_new( command_output ) ) );
        else
            lol_add( frame->args, L0 );

        /* Call the rule. */
        evaluate_rule( bindrule( rulename, root_module() ), rulename, frame );

        /* Clean up. */
        frame_free( frame );
    }
}
Beispiel #4
0
void
headers( TARGET * t )
{
    LIST   * hdrscan;
    LIST   * hdrrule;
	#ifndef OPT_HEADER_CACHE_EXT
    LIST   * headlist = L0;
	#endif
    regexp * re[ MAXINC ];
    int rec = 0;
    LISTITER iter, end;

    hdrscan = var_get( root_module(), constant_HDRSCAN );
    if ( list_empty( hdrscan ) )
        return;

    hdrrule = var_get( root_module(), constant_HDRRULE );
    if ( list_empty( hdrrule ) )
        return;

    if ( DEBUG_HEADER )
        printf( "header scan %s\n", object_str( t->name ) );

    /* Compile all regular expressions in HDRSCAN */
    iter = list_begin( hdrscan ), end = list_end( hdrscan );
    for ( ; ( rec < MAXINC ) && iter != end; iter = list_next( iter ) )
    {
        re[ rec++ ] = regex_compile( list_item( iter ) );
    }

    /* Doctor up call to HDRRULE rule */
    /* Call headers1() to get LIST of included files. */
    {
        FRAME   frame[1];
        frame_init( frame );
        lol_add( frame->args, list_new( object_copy( t->name ) ) );
#ifdef OPT_HEADER_CACHE_EXT
        lol_add( frame->args, hcache( t, rec, re, hdrscan ) );
#else
        lol_add( frame->args, headers1( headlist, t->boundname, rec, re ) );
#endif

        if ( lol_get( frame->args, 1 ) )
        {
            /* The third argument to HDRRULE is the bound name of
             * $(<) */
            lol_add( frame->args, list_new( object_copy( t->boundname ) ) );

            list_free( evaluate_rule( list_front( hdrrule ), frame ) );
        }

        /* Clean up. */
        frame_free( frame );
    }
}
Beispiel #5
0
static void make1bind( TARGET * t )
{
    if ( t->flags & T_FLAG_NOTFILE )
        return;

    pushsettings( root_module(), t->settings );
    object_free( t->boundname );
    t->boundname = search( t->name, &t->time, 0, t->flags & T_FLAG_ISFILE );
    t->binding = timestamp_empty( &t->time ) ? T_BIND_MISSING : T_BIND_EXISTS;
    popsettings( root_module(), t->settings );
}
Beispiel #6
0
static RULE * global_rule( RULE * r )
{
    if ( r->module == root_module() )
        return r;

    {
        OBJECT * name = global_rule_name( r );
        RULE * result = define_rule( r->module, name, root_module() );
        object_free( name );
        return result;
    }
}
Beispiel #7
0
/*
 * global_rule() - given a rule, produce the corresponding entry in the global module
 */
static RULE* global_rule( RULE* r )
{
    if ( r->module == root_module() )
    {
        return r;
    }
    else
    {
        char* name = global_rule_name( r );
        RULE* result = define_rule( r->module, name, root_module() );
        freestr(name);
        return result;
    }
}
Beispiel #8
0
/*
 * swap_settings() - replace the settings from the current module and
 *                   target with those from the new module and target
 */
static void swap_settings(
    module_t** current_module
    , TARGET** current_target
    , module_t* new_module
    , TARGET* new_target)
{
    if (new_module == root_module())
        new_module = 0;
    
    if (new_target == *current_target && new_module == *current_module)
        return;

    if (*current_target)
        popsettings( (*current_target)->settings );
        
    if (new_module != *current_module)
    {
        if (*current_module)
            exit_module( *current_module );

        *current_module = new_module;
        
        if (new_module)
            enter_module( new_module );
    }

    *current_target = new_target;
    if (new_target)
        pushsettings( new_target->settings );
}
Beispiel #9
0
void frame_init( FRAME* frame )
{
    frame->prev = 0;
    lol_init(frame->args);
    frame->module = root_module();
    frame->rulename = "module scope";
    frame->procedure = 0;
}
Beispiel #10
0
RULE *bindrule( char *rulename, module* m )
{
    RULE rule, *r = &rule;
    r->name = rulename;
    
    if ( hashcheck( m->rules, (HASHDATA **)&r ) )
        return r;
    else
        return enter_rule( rulename, root_module() );
}
Beispiel #11
0
static int cache_maxage( void )
{
    int age = 100;
    LIST * var = var_get( root_module(), constant_HCACHEMAXAGE );
    if ( !list_empty( var ) )
    {
        age = atoi( object_str( list_front( var ) ) );
        if ( age < 0 )
            age = 0;
    }
    return age;
}
Beispiel #12
0
static int cache_maxage( void )
{
    int age = 100;
    LIST * var = var_get( root_module(), constant_HCACHEMAXAGE );
    if ( var )
    {
        age = atoi( object_str( var->value ) );
        if ( age < 0 )
            age = 0;
    }
    return age;
}
Beispiel #13
0
RULE * bindrule( OBJECT * rulename, module_t * m )
{
    RULE * result = lookup_rule( rulename, m, 0 );
    if ( !result )
        result = lookup_rule( rulename, root_module(), 0 );
    /* We have only one caller, 'evaluate_rule', which will complain about
     * calling an undefined rule. We could issue the error here, but we do not
     * have the necessary information, such as frame.
     */
    if ( !result )
        result = enter_rule( rulename, m );
    return result;
}
RULE* bind_builtin( char* name, LIST*(*f)(PARSE*, FRAME*), int flags, char** args )
{
    argument_list* arg_list = 0;
    
    if ( args )
    {
        arg_list = args_new();
        lol_build( arg_list->data, args );
    }

    return new_rule_body( root_module(), name, arg_list,
                          parse_make( f, P0, P0, P0, C0, C0, flags ), 1 );
}
Beispiel #15
0
static void call_timing_rule( TARGET * target, timing_info const * const time )
{
    LIST * timing_rule;

    pushsettings( root_module(), target->settings );
    timing_rule = var_get( root_module(), constant_TIMING_RULE );
    popsettings( root_module(), target->settings );

    if ( !list_empty( timing_rule ) )
    {
        /* rule timing-rule ( args * : target : start end user system ) */

        /* Prepare the argument list. */
        FRAME frame[ 1 ];
        OBJECT * rulename = list_front( timing_rule );
        frame_init( frame );

        /* args * :: $(__TIMING_RULE__[2-]) */
        lol_add( frame->args, list_copy_range( timing_rule, list_next(
            list_begin( timing_rule ) ), list_end( timing_rule ) ) );

        /* target :: the name of the target */
        lol_add( frame->args, list_new( object_copy( target->name ) ) );

        /* start end user system :: info about the action command */
        lol_add( frame->args, list_push_back( list_push_back( list_push_back( list_new(
            outf_time( &time->start ) ),
            outf_time( &time->end ) ),
            outf_double( time->user ) ),
            outf_double( time->system ) ) );

        /* Call the rule. */
        evaluate_rule( bindrule( rulename , root_module() ), rulename, frame );

        /* Clean up. */
        frame_free( frame );
    }
}
Beispiel #16
0
static void bind_explicitly_located_target( void * xtarget, void * data )
{
    TARGET * t = (TARGET *)xtarget;
    if ( !( t->flags & T_FLAG_NOTFILE ) )
    {
        /* Check if there's a setting for LOCATE */
        SETTINGS * s = t->settings;
        for ( ; s ; s = s->next )
        {
            if ( strcmp( object_str( s->symbol ), "LOCATE" ) == 0 )
            {
                pushsettings( root_module(), t->settings );
                /* We are binding a target with explicit LOCATE. So third
                 * argument is of no use: nothing will be returned through it.
                 */
                object_free( t->boundname );
                t->boundname = search( t->name, &t->time, 0, 0 );
                popsettings( root_module(), t->settings );
                break;
            }
        }
    }
}
Beispiel #17
0
/*
 * global_name() - given a rule, return the name for a corresponding rule in the global module
 */
static char* global_rule_name( RULE* r )
{
    if ( r->module == root_module() )
    {
        return r->name;
    }
    else
    {
        char name[4096] = "";
        strncat(name, r->module->name, sizeof(name) - 1);
        strncat(name, r->name, sizeof(name) - 1 );
        return newstr(name);
    }
}
Beispiel #18
0
static OBJECT * global_rule_name( RULE * r )
{
    if ( r->module == root_module() )
        return object_copy( r->name );

    {
        char name[4096] = "";
        if ( r->module->name )
        {
            strncat( name, object_str( r->module->name ), sizeof( name ) - 1 );
            strncat( name, ".", sizeof( name ) - 1 );
        }
        strncat( name, object_str( r->name ), sizeof( name ) - 1 );
        return object_new( name );
    }
}
Beispiel #19
0
static LIST* evaluate_in_module ( char* module_name, PARSE * p, FRAME* frame)
{
    LIST* result;

    module_t* outer_module = frame->module;
    frame->module = module_name ? bindmodule( module_name ) : root_module();

    if ( outer_module != frame->module )
    {
        exit_module( outer_module );
        enter_module( frame->module );
    }

    result = parse_evaluate( p, frame );

    if ( outer_module != frame->module )
    {
        exit_module( frame->module );
        enter_module( outer_module );
        frame->module = outer_module;
    }

    return result;
}
RULE* duplicate_rule( char* name, RULE* other )
{
    return import_rule( other, root_module(), name );
}
Beispiel #21
0
LIST * var_get( struct module_t * module, OBJECT * symbol )
{
    LIST * result = L0;
#ifdef OPT_AT_FILES
    /* Some "fixed" variables... */
    if ( object_equal( symbol, constant_TMPDIR ) )
    {
        list_free( saved_var );
        result = saved_var = list_new( object_new( path_tmpdir()->value ) );
    }
    else if ( object_equal( symbol, constant_TMPNAME ) )
    {
        list_free( saved_var );
        result = saved_var = list_new( path_tmpnam() );
    }
    else if ( object_equal( symbol, constant_TMPFILE ) )
    {
        list_free( saved_var );
        result = saved_var = list_new( path_tmpfile() );
    }
    else if ( object_equal( symbol, constant_STDOUT ) )
    {
        list_free( saved_var );
        result = saved_var = list_new( object_copy( constant_STDOUT ) );
    }
    else if ( object_equal( symbol, constant_STDERR ) )
    {
        list_free( saved_var );
        result = saved_var = list_new( object_copy( constant_STDERR ) );
    }
    else
#endif
    {
        VARIABLE * v;
        int n;

        if ( ( n = module_get_fixed_var( module, symbol ) ) != -1 )
        {
            if ( DEBUG_VARGET )
                var_dump( symbol, module->fixed_variables[ n ], "get" );
            result = module->fixed_variables[ n ];
        }
        else if ( module->variables && ( v = (VARIABLE *)hash_find(
            module->variables, symbol ) ) )
        {
            if ( DEBUG_VARGET )
                var_dump( v->symbol, v->value, "get" );
            result = v->value;
        }

#ifdef OS_VMS
        else if ( ( module->name && object_equal( module->name, constant_ENVIRON ) )
                  || root_module() == module )
        {
            /* On VMS, when a variable from root or ENVIRON module is not found,
             * explicitly request it from the process.
             * By design, process variables (and logicals) are not made available
             * to C main(), and thus will not get loaded in bulk to root/ENVRON.
             * So we get around it by getting any such variable on first request.
             */
            const char * val = getenv( object_str( symbol ) );

            if ( val )
            {
                struct module_t * environ_module = module;
                char * environ[ 2 ] = { 0 }; /* NULL-terminated */
                string buf[ 1 ];

                if ( root_module() == module )
                {
                    environ_module = bindmodule( constant_ENVIRON );
                }

                string_copy( buf, object_str( symbol ) );
                string_append( buf, "=" );
                string_append( buf, val );

                environ[ 0 ] = buf->value;

                /* Load variable to global module, with splitting, for backward
                 * compatibility. Then to .ENVIRON, without splitting.
                 */
                var_defines( root_module(), environ, 1 );
                var_defines( environ_module, environ, 0 );
                string_free( buf );

                if ( module->variables && ( v = (VARIABLE *)hash_find(
                    module->variables, symbol ) ) )
                {
                    if ( DEBUG_VARGET )
                        var_dump( v->symbol, v->value, "get" );
                    result = v->value;
                }
            }
        }
#endif
    }
    return result;
}
Beispiel #22
0
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;
}
Beispiel #23
0
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( &current );
            var_set( root_module(), constant_JAMDATE, list_new( outf_time(
                &current ) ), 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;
}
Beispiel #24
0
static void make1c( state const * const pState )
{
    TARGET * const t = pState->t;
    CMD * const cmd = (CMD *)t->cmds;

    if ( cmd && t->status == EXEC_CMD_OK )
    {
        /* Pop state first in case something below (e.g. exec_cmd(), exec_wait()
         * or make1c_closure()) pushes a new state. Note that we must not access
         * the popped state data after this as the same stack node might have
         * been reused internally for some newly pushed state.
         */
        pop_state( &state_stack );

        /* Increment the jobs running counter. */
        ++cmdsrunning;

        /* Execute the actual build command or fake it if no-op. */
        if ( globs.noexec || cmd->noop )
        {
            timing_info time_info = { 0 };
            timestamp_current( &time_info.start );
            timestamp_copy( &time_info.end, &time_info.start );
            make1c_closure( t, EXEC_CMD_OK, &time_info, "", "", EXIT_OK );
        }
        else
        {
            exec_cmd( cmd->buf, make1c_closure, t, cmd->shell );

            /* Wait until under the concurrent command count limit. */
            /* FIXME: This wait could be skipped here and moved to just before
             * trying to execute a command that would cross the command count
             * limit. Note though that this might affect the order in which
             * unrelated targets get built and would thus require that all
             * affected Boost Build tests be updated.
             */
            assert( 0 < globs.jobs );
            assert( globs.jobs <= MAXJOBS );
            while ( cmdsrunning >= globs.jobs )
                exec_wait();
        }
    }
    else
    {
        ACTIONS * actions;

        /* Collect status from actions, and distribute it as well. */
        for ( actions = t->actions; actions; actions = actions->next )
            if ( actions->action->status > t->status )
                t->status = actions->action->status;
        for ( actions = t->actions; actions; actions = actions->next )
            if ( t->status > actions->action->status )
                actions->action->status = t->status;

        /* Tally success/failure for those we tried to update. */
        if ( t->progress == T_MAKE_RUNNING )
            switch ( t->status )
            {
                case EXEC_CMD_OK: ++counts->made; break;
                case EXEC_CMD_FAIL: ++counts->failed; break;
            }

        /* Tell parents their dependency has been built. */
        {
            TARGETS * c;
            stack temp_stack = { NULL };
            TARGET * additional_includes = NULL;

            t->progress = globs.noexec ? T_MAKE_NOEXEC_DONE : T_MAKE_DONE;

            /* Target has been updated so rescan it for dependencies. */
            if ( t->fate >= T_FATE_MISSING && t->status == EXEC_CMD_OK &&
                !( t->flags & T_FLAG_INTERNAL ) )
            {
                TARGET * saved_includes;
                SETTINGS * s;

                t->rescanned = 1;

                /* Clean current includes. */
                saved_includes = t->includes;
                t->includes = 0;

                s = copysettings( t->settings );
                pushsettings( root_module(), s );
                headers( t );
                popsettings( root_module(), s );
                freesettings( s );

                if ( t->includes )
                {
                    /* Tricky. The parents have already been processed, but they
                     * have not seen the internal node, because it was just
                     * created. We need to:
                     *  - push MAKE1A states that would have been pushed by the
                     *    parents here
                     *  - make sure all unprocessed parents will pick up the
                     *    new includes
                     *  - make sure processing the additional MAKE1A states is
                     *    done before processing the MAKE1B state for our
                     *    current target (which would mean this target has
                     *    already been built), otherwise the parent would be
                     *    considered built before the additional MAKE1A state
                     *    processing even got a chance to start.
                     */
                    make0( t->includes, t->parents->target, 0, 0, 0, t->includes
                        );
                    /* Link the old includes on to make sure that it gets
                     * cleaned up correctly.
                     */
                    t->includes->includes = saved_includes;
                    for ( c = t->dependants; c; c = c->next )
                        c->target->depends = targetentry( c->target->depends,
                            t->includes );
                    /* Will be processed below. */
                    additional_includes = t->includes;
                }
                else
                {
                    t->includes = saved_includes;
                }
            }

            if ( additional_includes )
                for ( c = t->parents; c; c = c->next )
                    push_state( &temp_stack, additional_includes, c->target,
                        T_STATE_MAKE1A );

            if ( t->scc_root )
            {
                TARGET * const scc_root = target_scc( t );
                assert( scc_root->progress < T_MAKE_DONE );
                for ( c = t->parents; c; c = c->next )
                {
                    if ( target_scc( c->target ) == scc_root )
                        push_state( &temp_stack, c->target, NULL, T_STATE_MAKE1B
                            );
                    else
                        scc_root->parents = targetentry( scc_root->parents,
                            c->target );
                }
            }
            else
            {
                for ( c = t->parents; c; c = c->next )
                    push_state( &temp_stack, c->target, NULL, T_STATE_MAKE1B );
            }

#ifdef OPT_SEMAPHORE
            /* If there is a semaphore, it is now free. */
            if ( t->semaphore )
            {
                assert( t->semaphore->asynccnt == 1 );
                --t->semaphore->asynccnt;

                if ( DEBUG_EXECCMD )
                    printf( "SEM: %s is now free\n", object_str(
                        t->semaphore->name ) );

                /* If anything is waiting, notify the next target. There is no
                 * point in notifying all waiting targets, since they will be
                 * notified again.
                 */
                if ( t->semaphore->parents )
                {
                    TARGETS * first = t->semaphore->parents;
                    t->semaphore->parents = first->next;
                    if ( first->next )
                        first->next->tail = first->tail;

                    if ( DEBUG_EXECCMD )
                        printf( "SEM: placing %s on stack\n", object_str(
                            first->target->name ) );
                    push_state( &temp_stack, first->target, NULL, T_STATE_MAKE1B
                        );
                    BJAM_FREE( first );
                }
            }
#endif

            /* Must pop state before pushing any more. */
            pop_state( &state_stack );

            /* Using stacks reverses the order of execution. Reverse it back. */
            push_stack_on_stack( &state_stack, &temp_stack );
        }
    }
}
Beispiel #25
0
OBJECT * search( OBJECT * target, timestamp * const time,
    OBJECT * * another_target, int const file )
{
    PATHNAME f[ 1 ];
    LIST * varlist;
    string buf[ 1 ];
    int found = 0;
    OBJECT * boundname = 0;

    if ( another_target )
        *another_target = 0;

    if ( !explicit_bindings )
        explicit_bindings = hashinit( sizeof( BINDING ), "explicitly specified "
            "locations" );

    string_new( buf );

    /* Parse the filename. */
    path_parse( object_str( target ), f );

    f->f_grist.ptr = 0;
    f->f_grist.len = 0;

    varlist = var_get( root_module(), constant_LOCATE );
    if ( !list_empty( varlist ) )
    {
        OBJECT * key;
        f->f_root.ptr = object_str( list_front( varlist ) );
        f->f_root.len = strlen( object_str( list_front( varlist ) ) );

        path_build( f, buf );

        if ( DEBUG_SEARCH )
            printf( "locate %s: %s\n", object_str( target ), buf->value );

        key = object_new( buf->value );
        timestamp_from_path( time, key );
        object_free( key );
        found = 1;
    }
    else if ( varlist = var_get( root_module(), constant_SEARCH ),
        !list_empty( varlist ) )
    {
        LISTITER iter = list_begin( varlist );
        LISTITER const end = list_end( varlist );
        for ( ; iter != end; iter = list_next( iter ) )
        {
            BINDING * ba;
            file_info_t * ff;
            OBJECT * key;
            OBJECT * test_path;

            f->f_root.ptr = object_str( list_item( iter ) );
            f->f_root.len = strlen( object_str( list_item( iter ) ) );

            string_truncate( buf, 0 );
            path_build( f, buf );

            if ( DEBUG_SEARCH )
                printf( "search %s: %s\n", object_str( target ), buf->value );

            test_path = object_new( buf->value );
            key = path_as_key( test_path );
            object_free( test_path );
            ff = file_query( key );
            timestamp_from_path( time, key );

            if ( ( ba = (BINDING *)hash_find( explicit_bindings, key ) ) )
            {
                if ( DEBUG_SEARCH )
                    printf(" search %s: found explicitly located target %s\n",
                        object_str( target ), object_str( ba->target ) );
                if ( another_target )
                    *another_target = ba->target;
                found = 1;
                object_free( key );
                break;
            }
            else if ( ff )
            {
                if ( !file || ff->is_file )
                {
                    found = 1;
                    object_free( key );
                    break;
                }
            }
            object_free( key );
        }
    }

    if ( !found )
    {
        /* Look for the obvious. */
        /* This is a questionable move. Should we look in the obvious place if
         * SEARCH is set?
         */
        OBJECT * key;

        f->f_root.ptr = 0;
        f->f_root.len = 0;

        string_truncate( buf, 0 );
        path_build( f, buf );

        if ( DEBUG_SEARCH )
            printf( "search %s: %s\n", object_str( target ), buf->value );

        key = object_new( buf->value );
        timestamp_from_path( time, key );
        object_free( key );
    }

    boundname = object_new( buf->value );
    string_free( buf );

    /* Prepare a call to BINDRULE if the variable is set. */
    call_bind_rule( target, boundname );

    return boundname;
}
Beispiel #26
0
OBJECT *
search(
    OBJECT * target,
    time_t *time,
    OBJECT * * another_target,
    int file
)
{
    PATHNAME f[1];
    LIST   * varlist;
    string   buf[1];
    int      found = 0;
    /* Will be set to 1 if target location is specified via LOCATE. */
    int      explicitly_located = 0;
    OBJECT * boundname = 0;

    if ( another_target )
        *another_target = 0;

    if (! explicit_bindings )
        explicit_bindings = hashinit( sizeof(BINDING),
                                     "explicitly specified locations");

    string_new( buf );
    /* Parse the filename */

    path_parse( object_str( target ), f );

    f->f_grist.ptr = 0;
    f->f_grist.len = 0;

    varlist = var_get( root_module(), constant_LOCATE );
    if ( !list_empty( varlist ) )
    {
        OBJECT * key;
        f->f_root.ptr = object_str( list_front( varlist ) );
        f->f_root.len = strlen( object_str( list_front( varlist ) ) );

        path_build( f, buf, 1 );

        if ( DEBUG_SEARCH )
            printf( "locate %s: %s\n", object_str( target ), buf->value );

        explicitly_located = 1;

        key = object_new( buf->value );
        timestamp( key, time );
        object_free( key );
        found = 1;
    }
    else if ( varlist = var_get( root_module(), constant_SEARCH ), !list_empty( varlist ) )
    {
        LISTITER iter = list_begin( varlist ), end = list_end( varlist );
        for ( ; iter != end; iter = list_next( iter ) )
        {
            BINDING * ba;
            file_info_t *ff;
            OBJECT * key;
            OBJECT * test_path;

            f->f_root.ptr = object_str( list_item( iter ) );
            f->f_root.len = strlen( object_str( list_item( iter ) ) );

            string_truncate( buf, 0 );
            path_build( f, buf, 1 );

            if ( DEBUG_SEARCH )
                printf( "search %s: %s\n", object_str( target ), buf->value );

            test_path = object_new( buf->value );
            key = path_as_key( test_path );
            object_free( test_path );
            ff = file_query( key );
            timestamp( key, time );

            if ( ( ba = (BINDING *)hash_find( explicit_bindings, key ) ) )
            {
                if ( DEBUG_SEARCH )
                    printf(" search %s: found explicitly located target %s\n",
                           object_str( target ), object_str( ba->target ) );
                if ( another_target )
                    *another_target = ba->target;
                found = 1;
                object_free( key );
                break;
            }
            else if ( ff && ff->time )
            {
                if ( !file || ff->is_file )
                {
                    found = 1;
                    object_free( key );
                    break;
                }
            }
            object_free( key );
        }
    }

    if ( !found )
    {
        /* Look for the obvious */
        /* This is a questionable move.  Should we look in the */
        /* obvious place if SEARCH is set? */
        OBJECT * key;

        f->f_root.ptr = 0;
        f->f_root.len = 0;

        string_truncate( buf, 0 );
        path_build( f, buf, 1 );

        if ( DEBUG_SEARCH )
            printf( "search %s: %s\n", object_str( target ), buf->value );

        key = object_new( buf->value );
        timestamp( key, time );
        object_free( key );
    }

    boundname = object_new( buf->value );
    string_free( buf );

    if ( explicitly_located )
    {
        int found;
        BINDING * ba;
        OBJECT * key = path_as_key( boundname );
        /* CONSIDER: we probably should issue a warning is another file
           is explicitly bound to the same location. This might break
           compatibility, though. */
        ba = (BINDING *)hash_insert( explicit_bindings, key, &found );
        if ( !found )
        {
            ba->binding = key;
            ba->target = target;
        }
        else
        {
            object_free( key );
        }
    }

    /* prepare a call to BINDRULE if the variable is set */
    call_bind_rule( target, boundname );

    return boundname;
}
Beispiel #27
0
void make0
(
    TARGET * t,
    TARGET * p,       /* parent */
    int      depth,   /* for display purposes */
    COUNTS * counts,  /* for reporting */
    int      anyhow,
    TARGET * rescanning
)  /* forcibly touch all (real) targets */
{
    TARGETS    * c;
    TARGET     * ptime = t;
    TARGET     * located_target = 0;
    timestamp    last;
    timestamp    leaf;
    timestamp    hlast;
    int          fate;
    char const * flag = "";
    SETTINGS   * s;

#ifdef OPT_GRAPH_DEBUG_EXT
    int savedFate;
    int oldTimeStamp;
#endif

    if ( DEBUG_MAKEPROG )
        out_printf( "make\t--\t%s%s\n", spaces( depth ), object_str( t->name ) );

    /*
     * Step 1: Initialize.
     */

    if ( DEBUG_MAKEPROG )
        out_printf( "make\t--\t%s%s\n", spaces( depth ), object_str( t->name ) );

    t->fate = T_FATE_MAKING;
    t->depth = depth;

    /*
     * Step 2: Under the influence of "on target" variables, bind the target and
     * search for headers.
     */

    /* Step 2a: Set "on target" variables. */
    s = copysettings( t->settings );
    pushsettings( root_module(), s );

    /* Step 2b: Find and timestamp the target file (if it is a file). */
    if ( ( t->binding == T_BIND_UNBOUND ) && !( t->flags & T_FLAG_NOTFILE ) )
    {
        OBJECT * another_target;
        object_free( t->boundname );
        t->boundname = search( t->name, &t->time, &another_target,
            t->flags & T_FLAG_ISFILE );
        /* If it was detected that this target refers to an already existing and
         * bound target, we add a dependency so that every target depending on
         * us will depend on that other target as well.
         */
        if ( another_target )
            located_target = bindtarget( another_target );

        t->binding = timestamp_empty( &t->time )
            ? T_BIND_MISSING
            : T_BIND_EXISTS;
    }

    /* INTERNAL, NOTFILE header nodes have the time of their parents. */
    if ( p && ( t->flags & T_FLAG_INTERNAL ) )
        ptime = p;

    /* If temp file does not exist but parent does, use parent. */
    if ( p && ( t->flags & T_FLAG_TEMP ) &&
        ( t->binding == T_BIND_MISSING ) &&
        ( p->binding != T_BIND_MISSING ) )
    {
        t->binding = T_BIND_PARENTS;
        ptime = p;
    }

#ifdef OPT_SEMAPHORE
    {
        LIST * var = var_get( root_module(), constant_JAM_SEMAPHORE );
        if ( !list_empty( var ) )
        {
            TARGET * const semaphore = bindtarget( list_front( var ) );
            semaphore->progress = T_MAKE_SEMAPHORE;
            t->semaphore = semaphore;
        }
    }
#endif

    /* Step 2c: If its a file, search for headers. */
    if ( t->binding == T_BIND_EXISTS )
        headers( t );

    /* Step 2d: reset "on target" variables. */
    popsettings( root_module(), s );
    freesettings( s );

    /*
     * Pause for a little progress reporting.
     */

    if ( DEBUG_BIND )
    {
        if ( !object_equal( t->name, t->boundname ) )
            out_printf( "bind\t--\t%s%s: %s\n", spaces( depth ),
                object_str( t->name ), object_str( t->boundname ) );

        switch ( t->binding )
        {
        case T_BIND_UNBOUND:
        case T_BIND_MISSING:
        case T_BIND_PARENTS:
            out_printf( "time\t--\t%s%s: %s\n", spaces( depth ),
                object_str( t->name ), target_bind[ (int)t->binding ] );
            break;

        case T_BIND_EXISTS:
            out_printf( "time\t--\t%s%s: %s\n", spaces( depth ),
                object_str( t->name ), timestamp_str( &t->time ) );
            break;
        }
    }

    /*
     * Step 3: Recursively make0() dependencies & headers.
     */

    /* Step 3a: Recursively make0() dependencies. */
    for ( c = t->depends; c; c = c->next )
    {
        int const internal = t->flags & T_FLAG_INTERNAL;

        /* Warn about circular deps, except for includes, which include each
         * other alot.
         */
        if ( c->target->fate == T_FATE_INIT )
            make0( c->target, ptime, depth + 1, counts, anyhow, rescanning );
        else if ( c->target->fate == T_FATE_MAKING && !internal )
            out_printf( "warning: %s depends on itself\n", object_str(
                c->target->name ) );
        else if ( c->target->fate != T_FATE_MAKING && rescanning )
            make0rescan( c->target, rescanning );
        if ( rescanning && c->target->includes && c->target->includes->fate !=
            T_FATE_MAKING )
            make0rescan( target_scc( c->target->includes ), rescanning );
    }

    if ( located_target )
    {
        if ( located_target->fate == T_FATE_INIT )
            make0( located_target, ptime, depth + 1, counts, anyhow, rescanning
                );
        else if ( located_target->fate != T_FATE_MAKING && rescanning )
            make0rescan( located_target, rescanning );
    }

    /* Step 3b: Recursively make0() internal includes node. */
    if ( t->includes )
        make0( t->includes, p, depth + 1, counts, anyhow, rescanning );

    /* Step 3c: Add dependencies' includes to our direct dependencies. */
    {
        TARGETS * incs = 0;
        for ( c = t->depends; c; c = c->next )
            if ( c->target->includes )
                incs = targetentry( incs, c->target->includes );
        t->depends = targetchain( t->depends, incs );
    }

    if ( located_target )
        t->depends = targetentry( t->depends, located_target );

    /* Step 3d: Detect cycles. */
    {
        int cycle_depth = depth;
        for ( c = t->depends; c; c = c->next )
        {
            TARGET * scc_root = target_scc( c->target );
            if ( scc_root->fate == T_FATE_MAKING &&
                ( !scc_root->includes ||
                  scc_root->includes->fate != T_FATE_MAKING ) )
            {
                if ( scc_root->depth < cycle_depth )
                {
                    cycle_depth = scc_root->depth;
                    t->scc_root = scc_root;
                }
            }
        }
    }

    /*
     * Step 4: Compute time & fate.
     */

    /* Step 4a: Pick up dependencies' time and fate. */
    timestamp_clear( &last );
    timestamp_clear( &leaf );
    fate = T_FATE_STABLE;
    for ( c = t->depends; c; c = c->next )
    {
        /* If we are in a different strongly connected component, pull
         * timestamps from the root.
         */
        if ( c->target->scc_root )
        {
            TARGET * const scc_root = target_scc( c->target );
            if ( scc_root != t->scc_root )
            {
                timestamp_max( &c->target->leaf, &c->target->leaf,
                    &scc_root->leaf );
                timestamp_max( &c->target->time, &c->target->time,
                    &scc_root->time );
                c->target->fate = max( c->target->fate, scc_root->fate );
            }
        }

        /* If LEAVES has been applied, we only heed the timestamps of the leaf
         * source nodes.
         */
        timestamp_max( &leaf, &leaf, &c->target->leaf );
        if ( t->flags & T_FLAG_LEAVES )
        {
            timestamp_copy( &last, &leaf );
            continue;
        }
        timestamp_max( &last, &last, &c->target->time );
        fate = max( fate, c->target->fate );

#ifdef OPT_GRAPH_DEBUG_EXT
        if ( DEBUG_FATE )
            if ( fate < c->target->fate )
                out_printf( "fate change %s from %s to %s by dependency %s\n",
                    object_str( t->name ), target_fate[ (int)fate ],
                    target_fate[ (int)c->target->fate ], object_str(
                    c->target->name ) );
#endif
    }

    /* Step 4b: Pick up included headers time. */

    /*
     * If a header is newer than a temp source that includes it, the temp source
     * will need building.
     */
    if ( t->includes )
        timestamp_copy( &hlast, &t->includes->time );
    else
        timestamp_clear( &hlast );

    /* Step 4c: handle NOUPDATE oddity.
     *
     * If a NOUPDATE file exists, mark it as having eternally old dependencies.
     * Do not inherit our fate from our dependencies. Decide fate based only on
     * other flags and our binding (done later).
     */
    if ( t->flags & T_FLAG_NOUPDATE )
    {
#ifdef OPT_GRAPH_DEBUG_EXT
        if ( DEBUG_FATE )
            if ( fate != T_FATE_STABLE )
                out_printf( "fate change  %s back to stable, NOUPDATE.\n",
                    object_str( t->name ) );
#endif

        timestamp_clear( &last );
        timestamp_clear( &t->time );

        /* Do not inherit our fate from our dependencies. Decide fate based only
         * upon other flags and our binding (done later).
         */
        fate = T_FATE_STABLE;
    }

    /* Step 4d: Determine fate: rebuild target or what? */

    /*
        In English:
        If can not find or make child, can not make target.
        If children changed, make target.
        If target missing, make it.
        If children newer, make target.
        If temp's children newer than parent, make temp.
        If temp's headers newer than parent, make temp.
        If deliberately touched, make it.
        If up-to-date temp file present, use it.
        If target newer than non-notfile parent, mark target newer.
        Otherwise, stable!

        Note this block runs from least to most stable: as we make it further
        down the list, the target's fate gets more stable.
    */

#ifdef OPT_GRAPH_DEBUG_EXT
    savedFate = fate;
    oldTimeStamp = 0;
#endif

    if ( fate >= T_FATE_BROKEN )
    {
        fate = T_FATE_CANTMAKE;
    }
    else if ( fate >= T_FATE_SPOIL )
    {
        fate = T_FATE_UPDATE;
    }
    else if ( t->binding == T_BIND_MISSING )
    {
        fate = T_FATE_MISSING;
    }
    else if ( t->binding == T_BIND_EXISTS && timestamp_cmp( &last, &t->time ) >
        0 )
    {
#ifdef OPT_GRAPH_DEBUG_EXT
        oldTimeStamp = 1;
#endif
        fate = T_FATE_OUTDATED;
    }
    else if ( t->binding == T_BIND_PARENTS && timestamp_cmp( &last, &p->time ) >
        0 )
    {
#ifdef OPT_GRAPH_DEBUG_EXT
        oldTimeStamp = 1;
#endif
        fate = T_FATE_NEEDTMP;
    }
    else if ( t->binding == T_BIND_PARENTS && timestamp_cmp( &hlast, &p->time )
        > 0 )
    {
        fate = T_FATE_NEEDTMP;
    }
    else if ( t->flags & T_FLAG_TOUCHED )
    {
        fate = T_FATE_TOUCHED;
    }
    else if ( anyhow && !( t->flags & T_FLAG_NOUPDATE ) )
    {
        fate = T_FATE_TOUCHED;
    }
    else if ( t->binding == T_BIND_EXISTS && ( t->flags & T_FLAG_TEMP ) )
    {
        fate = T_FATE_ISTMP;
    }
    else if ( t->binding == T_BIND_EXISTS && p && p->binding != T_BIND_UNBOUND
        && timestamp_cmp( &t->time, &p->time ) > 0 )
    {
#ifdef OPT_GRAPH_DEBUG_EXT
        oldTimeStamp = 1;
#endif
        fate = T_FATE_NEWER;
    }
    else
    {
        fate = T_FATE_STABLE;
    }
#ifdef OPT_GRAPH_DEBUG_EXT
    if ( DEBUG_FATE && ( fate != savedFate ) )
	{
        if ( savedFate == T_FATE_STABLE )
            out_printf( "fate change  %s set to %s%s\n", object_str( t->name ),
                target_fate[ fate ], oldTimeStamp ? " (by timestamp)" : "" );
        else
            out_printf( "fate change  %s from %s to %s%s\n", object_str( t->name ),
                target_fate[ savedFate ], target_fate[ fate ], oldTimeStamp ?
                " (by timestamp)" : "" );
	}
#endif

    /* Step 4e: Handle missing files. */
    /* If it is missing and there are no actions to create it, boom. */
    /* If we can not make a target we do not care about it, okay. */
    /* We could insist that there are updating actions for all missing */
    /* files, but if they have dependencies we just pretend it is a NOTFILE. */

    if ( ( fate == T_FATE_MISSING ) && !t->actions && !t->depends )
    {
        if ( t->flags & T_FLAG_NOCARE )
        {
#ifdef OPT_GRAPH_DEBUG_EXT
            if ( DEBUG_FATE )
                out_printf( "fate change %s to STABLE from %s, "
                    "no actions, no dependencies and do not care\n",
                    object_str( t->name ), target_fate[ fate ] );
#endif
            fate = T_FATE_STABLE;
        }
        else
        {
            out_printf( "don't know how to make %s\n", object_str( t->name ) );
            fate = T_FATE_CANTFIND;
        }
    }

    /* Step 4f: Propagate dependencies' time & fate. */
    /* Set leaf time to be our time only if this is a leaf. */

    timestamp_max( &t->time, &t->time, &last );
    timestamp_copy( &t->leaf, timestamp_empty( &leaf ) ? &t->time : &leaf );
    /* This target's fate may have been updated by virtue of following some
     * target's rebuilds list, so only allow it to be increased to the fate we
     * have calculated. Otherwise, grab its new fate.
     */
    if ( fate > t->fate )
        t->fate = fate;
    else
        fate = t->fate;

    /*
     * Step 4g: If this target needs to be built, make0 all targets
     * that are updated by the same actions used to update this target.
     * These have already been marked as REBUILDS, and make1 has
     * special handling for them.  We just need to make sure that
     * they get make0ed.
     */
    if ( ( fate >= T_FATE_BUILD ) && ( fate < T_FATE_BROKEN ) )
    {
        ACTIONS * a;
        TARGETS * c;
        for ( a = t->actions; a; a = a->next )
        {
            for ( c = a->action->targets; c; c = c->next )
            {
                if ( c->target->fate == T_FATE_INIT )
                {
                    make0( c->target, ptime, depth + 1, counts, anyhow, rescanning );
                }
            }
        }
    }

    /* Step 4h: If this target needs to be built, force rebuild everything in
     * its rebuilds list.
     */
    if ( ( fate >= T_FATE_BUILD ) && ( fate < T_FATE_BROKEN ) )
        force_rebuilds( t );

    /*
     * Step 5: Sort dependencies by their update time.
     */

    if ( globs.newestfirst )
        t->depends = make0sort( t->depends );

    /*
     * Step 6: A little harmless tabulating for tracing purposes.
     */

    /* Do not count or report interal includes nodes. */
    if ( t->flags & T_FLAG_INTERNAL )
        return;

    if ( counts )
    {
#ifdef OPT_IMPROVED_PATIENCE_EXT
        ++counts->targets;
#else
        if ( !( ++counts->targets % 1000 ) && DEBUG_MAKE )
        {
            out_printf( "...patience...\n" );
            out_flush();
        }
#endif

        if ( fate == T_FATE_ISTMP )
            ++counts->temp;
        else if ( fate == T_FATE_CANTFIND )
            ++counts->cantfind;
        else if ( ( fate == T_FATE_CANTMAKE ) && t->actions )
            ++counts->cantmake;
        else if ( ( fate >= T_FATE_BUILD ) && ( fate < T_FATE_BROKEN ) &&
            t->actions )
            ++counts->updating;
    }

    if ( !( t->flags & T_FLAG_NOTFILE ) && ( fate >= T_FATE_SPOIL ) )
        flag = "+";
    else if ( t->binding == T_BIND_EXISTS && p && timestamp_cmp( &t->time,
        &p->time ) > 0 )
        flag = "*";

    if ( DEBUG_MAKEPROG )
        out_printf( "made%s\t%s\t%s%s\n", flag, target_fate[ (int)t->fate ],
            spaces( depth ), object_str( t->name ) );
}
Beispiel #28
0
static LIST*
call_python_function(RULE* r, FRAME* frame)
{
    LIST* result = 0;
    PyObject* arguments = PyTuple_New(frame->args->count);
    int i ;
    PyObject* py_result;

    for(i = 0; i < frame->args->count; ++i)
    {
        PyObject* arg = PyList_New(0);
        LIST* l = lol_get( frame->args, i);

        for(; l; l = l->next)
        {
            PyObject* v = PyString_FromString(l->string);
            /* Steals reference to 'v' */
            PyList_Append(arg, v);            
        }
        /* Steals reference to 'arg' */
        PyTuple_SetItem(arguments, i, arg);
    }

    py_result = PyObject_CallObject(r->python_function, arguments);
    Py_DECREF(arguments);
    if (py_result != NULL) {
        
        if (PyList_Check(py_result)) {
            int size = PyList_Size(py_result);
            int i;
            for(i = 0; i < size; ++i)
            {
                PyObject* item = PyList_GetItem(py_result, i);
                if (PyString_Check(item))
                {
                    result = list_new(result, 
                                      newstr(PyString_AsString(item)));
                }
                else
                {
                    fprintf(stderr, "Non-string object returned by Python call\n");
                }
            }
        }
        else if (PyInstance_Check(py_result))
        {
            static char instance_name[1000];
            static char imported_method_name[1000];
            module_t* m;
            PyObject* method;
            PyObject* method_name = PyString_FromString("foo");
            RULE* r;

            fprintf(stderr, "Got instance!\n");

            snprintf(instance_name, 1000,
                     "pyinstance%d", python_instance_number);
            snprintf(imported_method_name, 1000,
                     "pyinstance%d.foo", python_instance_number);
            ++python_instance_number;
            
            m = bindmodule(instance_name);

            /* This is expected to get bound method. */
            method = PyObject_GetAttr(py_result, method_name);
            
            r = bindrule( imported_method_name, root_module() );

            r->python_function = method;

            result = list_new(0, newstr(instance_name));    

            Py_DECREF(method_name);
        }
        else if (py_result == Py_None)
        {
            result = L0;
        }
        else
        {
            fprintf(stderr, "Non-list object returned by Python call\n");
        }

        Py_DECREF(py_result);
    }
    else {
        PyErr_Print();
        fprintf(stderr,"Call failed\n");
    }
    
    return result;
}