mirror of
https://github.com/boostorg/build.git
synced 2026-02-15 13:02:11 +00:00
Dependency scanning implementation.
* jam_src/builtins.c: New builtin SEARCH_FOR_TARGET.
* jam_src/rules.c
(bind_explicitly_located_targets): New function.
(search_for_target): New function.
* jam_src/make.c (make): Call 'bind_explicitly_located_targets()'
immediately on entering.
* jam_src/search.c (call_bind_rule): No longer 'static'.
* new/builtin.jam (c-scanner.process): Real implementation.
* test/dependency_test.py: Really test for dependencies.
[SVN r15646]
This commit is contained in:
@@ -188,6 +188,12 @@ load_builtins()
|
||||
bind_builtin( "PWD" ,
|
||||
builtin_pwd, 0, args );
|
||||
}
|
||||
|
||||
{
|
||||
char * args[] = { "target", "*", ":", "path", "*", 0 };
|
||||
bind_builtin( "SEARCH_FOR_TARGET",
|
||||
builtin_search_for_target, 0, args );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -682,6 +688,16 @@ builtin_update( PARSE *parse, FRAME *frame)
|
||||
return L0;
|
||||
}
|
||||
|
||||
LIST*
|
||||
builtin_search_for_target( PARSE *parse, FRAME *frame )
|
||||
{
|
||||
LIST* arg1 = lol_get( frame->args, 0 );
|
||||
LIST* arg2 = lol_get( frame->args, 1 );
|
||||
|
||||
TARGET* t = search_for_target( arg1->string, arg2 );
|
||||
return list_new( L0, t->name );
|
||||
}
|
||||
|
||||
static void lol_build( LOL* lol, char** elements )
|
||||
{
|
||||
LIST* l = L0;
|
||||
|
||||
@@ -30,5 +30,6 @@ LIST *builtin_caller_module( PARSE *parse, FRAME *args );
|
||||
LIST *builtin_backtrace( PARSE *parse, FRAME *args );
|
||||
LIST *builtin_pwd( PARSE *parse, FRAME *args );
|
||||
LIST *builtin_update( PARSE *parse, FRAME *args );
|
||||
LIST *builtin_search_for_target( PARSE *parse, FRAME *args );
|
||||
|
||||
#endif
|
||||
|
||||
@@ -129,6 +129,11 @@ make(
|
||||
|
||||
memset( (char *)counts, 0, sizeof( *counts ) );
|
||||
|
||||
/* First bind all targets with LOCATE_TARGET setting. This is
|
||||
needed to correctly handle dependencies to generated headers.
|
||||
*/
|
||||
bind_explicitly_located_targets();
|
||||
|
||||
for( i = 0; i < n_targets; i++ )
|
||||
{
|
||||
TARGET *t = bindtarget( targets[i] );
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
# include "newstr.h"
|
||||
# include "hash.h"
|
||||
# include "modules.h"
|
||||
# include "search.h"
|
||||
# include "lists.h"
|
||||
# include "pathsys.h"
|
||||
|
||||
/* This file is ALSO:
|
||||
* (C) Copyright David Abrahams 2001. Permission to copy, use,
|
||||
@@ -49,6 +52,15 @@ static void set_rule_actions( RULE* rule, rule_actions* actions );
|
||||
static void set_rule_body( RULE* rule, argument_list* args, PARSE* procedure );
|
||||
static struct hash *targethash = 0;
|
||||
|
||||
typedef struct _located_target LOCATED_TARGET ;
|
||||
|
||||
struct _located_target {
|
||||
char* file_name;
|
||||
TARGET* target;
|
||||
};
|
||||
static struct hash *located_targets = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
@@ -119,6 +131,118 @@ bindtarget( char *targetname )
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
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_TARGET */
|
||||
SETTINGS* s = t->settings;
|
||||
for(; s ; s = s->next)
|
||||
{
|
||||
if (strcmp(s->symbol, "LOCATE") == 0)
|
||||
{
|
||||
pushsettings(t->settings);
|
||||
t->boundname = search( t->name, &t->time );
|
||||
t->binding = t->time ? T_BIND_EXISTS : T_BIND_MISSING;
|
||||
popsettings(t->settings);
|
||||
|
||||
{
|
||||
LOCATED_TARGET lt = { t->boundname, t }, *lta = <
|
||||
if (!located_targets)
|
||||
located_targets = hashinit( sizeof(LOCATED_TARGET),
|
||||
"located targets" );
|
||||
|
||||
/* TODO: should check if we've entered the item or not. */
|
||||
hashenter(located_targets, (HASHDATA **)<a);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bind_explicitly_located_targets()
|
||||
{
|
||||
hashenumerate(targethash, bind_explicitly_located_target, (void*)0);
|
||||
}
|
||||
|
||||
/* TODO: this is probably not a good idea to use functions in other modules like
|
||||
that. */
|
||||
void call_bind_rule(char* target, char* boundname);
|
||||
|
||||
TARGET* search_for_target ( char * name, LIST* search_path )
|
||||
{
|
||||
PATHNAME f[1];
|
||||
string buf[1];
|
||||
LOCATED_TARGET lt, *lta = <
|
||||
time_t time;
|
||||
int found = 0;
|
||||
TARGET* result;
|
||||
|
||||
string_new( buf );
|
||||
|
||||
path_parse( name, f );
|
||||
|
||||
f->f_grist.ptr = 0;
|
||||
f->f_grist.len = 0;
|
||||
|
||||
while( search_path )
|
||||
{
|
||||
f->f_root.ptr = search_path->string;
|
||||
f->f_root.len = strlen( search_path->string );
|
||||
|
||||
string_truncate( buf, 0 );
|
||||
path_build( f, buf, 1 );
|
||||
|
||||
lt.file_name = buf->value ;
|
||||
|
||||
if (! located_targets )
|
||||
located_targets = hashinit( sizeof(LOCATED_TARGET),
|
||||
"located targets" );
|
||||
|
||||
|
||||
if ( hashcheck( located_targets, (HASHDATA **)<a ) )
|
||||
{
|
||||
return lta->target;
|
||||
}
|
||||
|
||||
timestamp( buf->value, &time );
|
||||
if (time)
|
||||
{
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
search_path = list_next( search_path );
|
||||
}
|
||||
|
||||
if ( ! found )
|
||||
{
|
||||
f->f_root.ptr = 0;
|
||||
f->f_root.len = 0;
|
||||
|
||||
string_truncate( buf, 0 );
|
||||
path_build( f, buf, 1 );
|
||||
|
||||
timestamp( buf->value, &time );
|
||||
}
|
||||
|
||||
result = bindtarget( name );
|
||||
result->boundname = newstr( buf->value );
|
||||
result->time = time;
|
||||
result->binding = time ? T_BIND_EXISTS : T_BIND_MISSING;
|
||||
|
||||
call_bind_rule( result->name, result->boundname );
|
||||
|
||||
string_free( buf );
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* touchtarget() - mark a target to simulate being new
|
||||
*/
|
||||
|
||||
@@ -216,6 +216,8 @@ RULE* import_rule( RULE* source, module* m, char* name );
|
||||
RULE* new_rule_body( module* m, char* rulename, argument_list* args, PARSE* procedure, int export );
|
||||
RULE* new_rule_actions( module* m, char* rulename, char* command, LIST* bindlist, int flags );
|
||||
TARGET *bindtarget( char *targetname );
|
||||
void bind_explicitly_located_targets();
|
||||
TARGET* search_for_targets ( char * name, LIST* search_path );
|
||||
void touchtarget( char *t );
|
||||
TARGETS *targetlist( TARGETS *chain, LIST *targets );
|
||||
TARGETS *targetentry( TARGETS *chain, TARGET *target );
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
# include "strings.h"
|
||||
# include <string.h>
|
||||
|
||||
static void call_bind_rule(
|
||||
void call_bind_rule(
|
||||
char* target_,
|
||||
char* boundname_ )
|
||||
{
|
||||
@@ -70,7 +70,7 @@ static void call_bind_rule(
|
||||
char *
|
||||
search(
|
||||
char *target,
|
||||
time_t *time )
|
||||
time_t *time )
|
||||
{
|
||||
PATHNAME f[1];
|
||||
LIST *varlist;
|
||||
@@ -87,7 +87,7 @@ search(
|
||||
f->f_grist.len = 0;
|
||||
|
||||
if( varlist = var_get( "LOCATE" ) )
|
||||
{
|
||||
{
|
||||
f->f_root.ptr = varlist->string;
|
||||
f->f_root.len = strlen( varlist->string );
|
||||
|
||||
|
||||
@@ -188,6 +188,12 @@ load_builtins()
|
||||
bind_builtin( "PWD" ,
|
||||
builtin_pwd, 0, args );
|
||||
}
|
||||
|
||||
{
|
||||
char * args[] = { "target", "*", ":", "path", "*", 0 };
|
||||
bind_builtin( "SEARCH_FOR_TARGET",
|
||||
builtin_search_for_target, 0, args );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -682,6 +688,16 @@ builtin_update( PARSE *parse, FRAME *frame)
|
||||
return L0;
|
||||
}
|
||||
|
||||
LIST*
|
||||
builtin_search_for_target( PARSE *parse, FRAME *frame )
|
||||
{
|
||||
LIST* arg1 = lol_get( frame->args, 0 );
|
||||
LIST* arg2 = lol_get( frame->args, 1 );
|
||||
|
||||
TARGET* t = search_for_target( arg1->string, arg2 );
|
||||
return list_new( L0, t->name );
|
||||
}
|
||||
|
||||
static void lol_build( LOL* lol, char** elements )
|
||||
{
|
||||
LIST* l = L0;
|
||||
|
||||
@@ -30,5 +30,6 @@ LIST *builtin_caller_module( PARSE *parse, FRAME *args );
|
||||
LIST *builtin_backtrace( PARSE *parse, FRAME *args );
|
||||
LIST *builtin_pwd( PARSE *parse, FRAME *args );
|
||||
LIST *builtin_update( PARSE *parse, FRAME *args );
|
||||
LIST *builtin_search_for_target( PARSE *parse, FRAME *args );
|
||||
|
||||
#endif
|
||||
|
||||
@@ -129,6 +129,11 @@ make(
|
||||
|
||||
memset( (char *)counts, 0, sizeof( *counts ) );
|
||||
|
||||
/* First bind all targets with LOCATE_TARGET setting. This is
|
||||
needed to correctly handle dependencies to generated headers.
|
||||
*/
|
||||
bind_explicitly_located_targets();
|
||||
|
||||
for( i = 0; i < n_targets; i++ )
|
||||
{
|
||||
TARGET *t = bindtarget( targets[i] );
|
||||
|
||||
124
jam_src/rules.c
124
jam_src/rules.c
@@ -12,6 +12,9 @@
|
||||
# include "newstr.h"
|
||||
# include "hash.h"
|
||||
# include "modules.h"
|
||||
# include "search.h"
|
||||
# include "lists.h"
|
||||
# include "pathsys.h"
|
||||
|
||||
/* This file is ALSO:
|
||||
* (C) Copyright David Abrahams 2001. Permission to copy, use,
|
||||
@@ -49,6 +52,15 @@ static void set_rule_actions( RULE* rule, rule_actions* actions );
|
||||
static void set_rule_body( RULE* rule, argument_list* args, PARSE* procedure );
|
||||
static struct hash *targethash = 0;
|
||||
|
||||
typedef struct _located_target LOCATED_TARGET ;
|
||||
|
||||
struct _located_target {
|
||||
char* file_name;
|
||||
TARGET* target;
|
||||
};
|
||||
static struct hash *located_targets = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
@@ -119,6 +131,118 @@ bindtarget( char *targetname )
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
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_TARGET */
|
||||
SETTINGS* s = t->settings;
|
||||
for(; s ; s = s->next)
|
||||
{
|
||||
if (strcmp(s->symbol, "LOCATE") == 0)
|
||||
{
|
||||
pushsettings(t->settings);
|
||||
t->boundname = search( t->name, &t->time );
|
||||
t->binding = t->time ? T_BIND_EXISTS : T_BIND_MISSING;
|
||||
popsettings(t->settings);
|
||||
|
||||
{
|
||||
LOCATED_TARGET lt = { t->boundname, t }, *lta = <
|
||||
if (!located_targets)
|
||||
located_targets = hashinit( sizeof(LOCATED_TARGET),
|
||||
"located targets" );
|
||||
|
||||
/* TODO: should check if we've entered the item or not. */
|
||||
hashenter(located_targets, (HASHDATA **)<a);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bind_explicitly_located_targets()
|
||||
{
|
||||
hashenumerate(targethash, bind_explicitly_located_target, (void*)0);
|
||||
}
|
||||
|
||||
/* TODO: this is probably not a good idea to use functions in other modules like
|
||||
that. */
|
||||
void call_bind_rule(char* target, char* boundname);
|
||||
|
||||
TARGET* search_for_target ( char * name, LIST* search_path )
|
||||
{
|
||||
PATHNAME f[1];
|
||||
string buf[1];
|
||||
LOCATED_TARGET lt, *lta = <
|
||||
time_t time;
|
||||
int found = 0;
|
||||
TARGET* result;
|
||||
|
||||
string_new( buf );
|
||||
|
||||
path_parse( name, f );
|
||||
|
||||
f->f_grist.ptr = 0;
|
||||
f->f_grist.len = 0;
|
||||
|
||||
while( search_path )
|
||||
{
|
||||
f->f_root.ptr = search_path->string;
|
||||
f->f_root.len = strlen( search_path->string );
|
||||
|
||||
string_truncate( buf, 0 );
|
||||
path_build( f, buf, 1 );
|
||||
|
||||
lt.file_name = buf->value ;
|
||||
|
||||
if (! located_targets )
|
||||
located_targets = hashinit( sizeof(LOCATED_TARGET),
|
||||
"located targets" );
|
||||
|
||||
|
||||
if ( hashcheck( located_targets, (HASHDATA **)<a ) )
|
||||
{
|
||||
return lta->target;
|
||||
}
|
||||
|
||||
timestamp( buf->value, &time );
|
||||
if (time)
|
||||
{
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
search_path = list_next( search_path );
|
||||
}
|
||||
|
||||
if ( ! found )
|
||||
{
|
||||
f->f_root.ptr = 0;
|
||||
f->f_root.len = 0;
|
||||
|
||||
string_truncate( buf, 0 );
|
||||
path_build( f, buf, 1 );
|
||||
|
||||
timestamp( buf->value, &time );
|
||||
}
|
||||
|
||||
result = bindtarget( name );
|
||||
result->boundname = newstr( buf->value );
|
||||
result->time = time;
|
||||
result->binding = time ? T_BIND_EXISTS : T_BIND_MISSING;
|
||||
|
||||
call_bind_rule( result->name, result->boundname );
|
||||
|
||||
string_free( buf );
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* touchtarget() - mark a target to simulate being new
|
||||
*/
|
||||
|
||||
@@ -216,6 +216,8 @@ RULE* import_rule( RULE* source, module* m, char* name );
|
||||
RULE* new_rule_body( module* m, char* rulename, argument_list* args, PARSE* procedure, int export );
|
||||
RULE* new_rule_actions( module* m, char* rulename, char* command, LIST* bindlist, int flags );
|
||||
TARGET *bindtarget( char *targetname );
|
||||
void bind_explicitly_located_targets();
|
||||
TARGET* search_for_targets ( char * name, LIST* search_path );
|
||||
void touchtarget( char *t );
|
||||
TARGETS *targetlist( TARGETS *chain, LIST *targets );
|
||||
TARGETS *targetentry( TARGETS *chain, TARGET *target );
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
# include "strings.h"
|
||||
# include <string.h>
|
||||
|
||||
static void call_bind_rule(
|
||||
void call_bind_rule(
|
||||
char* target_,
|
||||
char* boundname_ )
|
||||
{
|
||||
@@ -70,7 +70,7 @@ static void call_bind_rule(
|
||||
char *
|
||||
search(
|
||||
char *target,
|
||||
time_t *time )
|
||||
time_t *time )
|
||||
{
|
||||
PATHNAME f[1];
|
||||
LIST *varlist;
|
||||
@@ -87,7 +87,7 @@ search(
|
||||
f->f_grist.len = 0;
|
||||
|
||||
if( varlist = var_get( "LOCATE" ) )
|
||||
{
|
||||
{
|
||||
f->f_root.ptr = varlist->string;
|
||||
f->f_root.len = strlen( varlist->string );
|
||||
|
||||
|
||||
@@ -46,7 +46,60 @@ rule c-scanner ( includes * )
|
||||
|
||||
rule process ( target : matches * )
|
||||
{
|
||||
ECHO "c-scanner: processing target" $(target) with $(matches) ;
|
||||
local angle = [ regex.transform $(matches) : "<(.*)>" ] ;
|
||||
local quoted = [ regex.transform $(matches) : "\"(.*)\"" ] ;
|
||||
|
||||
# CONSIDER: the new scoping rule seem to defeat "on target" variables.
|
||||
local g = [ on $(target) return $(HDRGRIST) ] ;
|
||||
local b = [ path.native [ path.parent [ path.make
|
||||
[ virtual-target.binding $(target) ] ] ] ] ;
|
||||
|
||||
# Attach binding of including file to included targets.
|
||||
# When target is directly created from virtual target
|
||||
# this extra information is unnecessary. But in other
|
||||
# cases, it allows to distinguish between two headers of the
|
||||
# same name included from different places.
|
||||
# We don't need this extra information for angle includes,
|
||||
# since they should not depend on including file (we can't
|
||||
# get literal "." in include path).
|
||||
local g2 = $(g)"#"$(b) ;
|
||||
|
||||
angle = $(angle:G=$(g)) ;
|
||||
quoted = $(quoted:G=$(g2)) ;
|
||||
|
||||
for local i in $(angle)
|
||||
{
|
||||
local i2 = [ SEARCH_FOR_TARGET $(i) : $(self.includes:G=) ] ;
|
||||
INCLUDES $(target) : $(i2) ;
|
||||
if $(i2) = $(i)
|
||||
{
|
||||
NOCARE $(i) ;
|
||||
SEARCH on $(i) = $(self.includes:G=) ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ECHO "Binding is" [ virtual-target.binding $(target) ] ;
|
||||
for local i in $(quoted)
|
||||
{
|
||||
local path = $(b) $(self.includes:G=) ;
|
||||
local i2 = [ SEARCH_FOR_TARGET $(i) : $(path) ] ;
|
||||
INCLUDES $(target) : $(i2) ;
|
||||
if $(i2) = $(i)
|
||||
{
|
||||
NOCARE $(i) ;
|
||||
SEARCH on $(i) = $(path) ;
|
||||
}
|
||||
}
|
||||
|
||||
BINDRULE on $(angle) $(quoted) = virtual-target.remember-binding ;
|
||||
|
||||
# Just propagate current scanner to includes, in a hope
|
||||
# that includes do not change scanners.
|
||||
for local a in $(angle)
|
||||
{
|
||||
scanner.install $(__name__) : $(a) : $(target) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
0
test/dependency-test/b.h
Normal file
0
test/dependency-test/b.h
Normal file
@@ -9,4 +9,44 @@ t.run_build_system()
|
||||
# Do not bother checking for created files now.
|
||||
|
||||
|
||||
|
||||
# Check handling of first level includes.
|
||||
|
||||
# Both 'a' and 'b' include "a.h" and should be updated
|
||||
t.touch("a.h")
|
||||
t.run_build_system()
|
||||
|
||||
t.expect_touch("bin/gcc/debug/shared-false/threading-single/a")
|
||||
t.expect_touch("bin/gcc/debug/shared-false/threading-single/a.o")
|
||||
t.expect_touch("bin/gcc/debug/shared-false/threading-single/b")
|
||||
t.expect_touch("bin/gcc/debug/shared-false/threading-single/b.o")
|
||||
t.expect_nothing_more()
|
||||
|
||||
# Only 'a' include <a.h> and should be updated
|
||||
t.touch("src1/a.h")
|
||||
t.run_build_system()
|
||||
|
||||
t.expect_touch("bin/gcc/debug/shared-false/threading-single/a")
|
||||
t.expect_touch("bin/gcc/debug/shared-false/threading-single/a.o")
|
||||
t.expect_nothing_more()
|
||||
|
||||
# "src/a.h" includes "b.h" (in the same dir)
|
||||
t.touch("src1/b.h")
|
||||
t.run_build_system()
|
||||
t.expect_touch("bin/gcc/debug/shared-false/threading-single/a")
|
||||
t.expect_touch("bin/gcc/debug/shared-false/threading-single/a.o")
|
||||
t.expect_nothing_more()
|
||||
|
||||
t.touch("b.h")
|
||||
t.run_build_system()
|
||||
t.expect_nothing_more()
|
||||
|
||||
# Test dependency on generated header.
|
||||
# TODO: we have also to check that generated header is found correctly
|
||||
# if it is different for different subvariants. Lacking any toolset
|
||||
# support, this check will be implemented later.
|
||||
t.touch("x.foo")
|
||||
t.run_build_system()
|
||||
t.expect_touch("bin/gcc/debug/shared-false/threading-single/a.o")
|
||||
|
||||
t.cleanup()
|
||||
|
||||
0
v2/test/dependency-test/b.h
Normal file
0
v2/test/dependency-test/b.h
Normal file
@@ -9,4 +9,44 @@ t.run_build_system()
|
||||
# Do not bother checking for created files now.
|
||||
|
||||
|
||||
|
||||
# Check handling of first level includes.
|
||||
|
||||
# Both 'a' and 'b' include "a.h" and should be updated
|
||||
t.touch("a.h")
|
||||
t.run_build_system()
|
||||
|
||||
t.expect_touch("bin/gcc/debug/shared-false/threading-single/a")
|
||||
t.expect_touch("bin/gcc/debug/shared-false/threading-single/a.o")
|
||||
t.expect_touch("bin/gcc/debug/shared-false/threading-single/b")
|
||||
t.expect_touch("bin/gcc/debug/shared-false/threading-single/b.o")
|
||||
t.expect_nothing_more()
|
||||
|
||||
# Only 'a' include <a.h> and should be updated
|
||||
t.touch("src1/a.h")
|
||||
t.run_build_system()
|
||||
|
||||
t.expect_touch("bin/gcc/debug/shared-false/threading-single/a")
|
||||
t.expect_touch("bin/gcc/debug/shared-false/threading-single/a.o")
|
||||
t.expect_nothing_more()
|
||||
|
||||
# "src/a.h" includes "b.h" (in the same dir)
|
||||
t.touch("src1/b.h")
|
||||
t.run_build_system()
|
||||
t.expect_touch("bin/gcc/debug/shared-false/threading-single/a")
|
||||
t.expect_touch("bin/gcc/debug/shared-false/threading-single/a.o")
|
||||
t.expect_nothing_more()
|
||||
|
||||
t.touch("b.h")
|
||||
t.run_build_system()
|
||||
t.expect_nothing_more()
|
||||
|
||||
# Test dependency on generated header.
|
||||
# TODO: we have also to check that generated header is found correctly
|
||||
# if it is different for different subvariants. Lacking any toolset
|
||||
# support, this check will be implemented later.
|
||||
t.touch("x.foo")
|
||||
t.run_build_system()
|
||||
t.expect_touch("bin/gcc/debug/shared-false/threading-single/a.o")
|
||||
|
||||
t.cleanup()
|
||||
|
||||
@@ -46,7 +46,60 @@ rule c-scanner ( includes * )
|
||||
|
||||
rule process ( target : matches * )
|
||||
{
|
||||
ECHO "c-scanner: processing target" $(target) with $(matches) ;
|
||||
local angle = [ regex.transform $(matches) : "<(.*)>" ] ;
|
||||
local quoted = [ regex.transform $(matches) : "\"(.*)\"" ] ;
|
||||
|
||||
# CONSIDER: the new scoping rule seem to defeat "on target" variables.
|
||||
local g = [ on $(target) return $(HDRGRIST) ] ;
|
||||
local b = [ path.native [ path.parent [ path.make
|
||||
[ virtual-target.binding $(target) ] ] ] ] ;
|
||||
|
||||
# Attach binding of including file to included targets.
|
||||
# When target is directly created from virtual target
|
||||
# this extra information is unnecessary. But in other
|
||||
# cases, it allows to distinguish between two headers of the
|
||||
# same name included from different places.
|
||||
# We don't need this extra information for angle includes,
|
||||
# since they should not depend on including file (we can't
|
||||
# get literal "." in include path).
|
||||
local g2 = $(g)"#"$(b) ;
|
||||
|
||||
angle = $(angle:G=$(g)) ;
|
||||
quoted = $(quoted:G=$(g2)) ;
|
||||
|
||||
for local i in $(angle)
|
||||
{
|
||||
local i2 = [ SEARCH_FOR_TARGET $(i) : $(self.includes:G=) ] ;
|
||||
INCLUDES $(target) : $(i2) ;
|
||||
if $(i2) = $(i)
|
||||
{
|
||||
NOCARE $(i) ;
|
||||
SEARCH on $(i) = $(self.includes:G=) ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ECHO "Binding is" [ virtual-target.binding $(target) ] ;
|
||||
for local i in $(quoted)
|
||||
{
|
||||
local path = $(b) $(self.includes:G=) ;
|
||||
local i2 = [ SEARCH_FOR_TARGET $(i) : $(path) ] ;
|
||||
INCLUDES $(target) : $(i2) ;
|
||||
if $(i2) = $(i)
|
||||
{
|
||||
NOCARE $(i) ;
|
||||
SEARCH on $(i) = $(path) ;
|
||||
}
|
||||
}
|
||||
|
||||
BINDRULE on $(angle) $(quoted) = virtual-target.remember-binding ;
|
||||
|
||||
# Just propagate current scanner to includes, in a hope
|
||||
# that includes do not change scanners.
|
||||
for local a in $(angle)
|
||||
{
|
||||
scanner.install $(__name__) : $(a) : $(target) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user