mirror of
https://github.com/boostorg/build.git
synced 2026-02-16 01:12:13 +00:00
Speed up module imports.
* jam_src/builtins.c: New builtins IMPORT_MODULE and IMPORTED_MODULES. jam_src/rules.c: (bindrule): Refactor. (lookup_rule): New function. * kernel/modules.jam: Make use of IMPORT_MODULE. [SVN r19422]
This commit is contained in:
@@ -215,6 +215,18 @@ load_builtins()
|
||||
bind_builtin( "SEARCH_FOR_TARGET",
|
||||
builtin_search_for_target, 0, args );
|
||||
}
|
||||
|
||||
{
|
||||
char * args[] = { "modules_to_import", "+", ":", "target_module", "?", 0 };
|
||||
bind_builtin( "IMPORT_MODULE",
|
||||
builtin_import_module, 0, args );
|
||||
}
|
||||
|
||||
{
|
||||
char * args[] = { "module", "?", 0 };
|
||||
bind_builtin( "IMPORTED_MODULES",
|
||||
builtin_imported_modules, 0, args );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -846,6 +858,47 @@ builtin_search_for_target( PARSE *parse, FRAME *frame )
|
||||
return list_new( L0, t->name );
|
||||
}
|
||||
|
||||
LIST *builtin_import_module( PARSE *parse, FRAME *frame )
|
||||
{
|
||||
LIST* arg1 = lol_get( frame->args, 0 );
|
||||
LIST* arg2 = lol_get( frame->args, 1 );
|
||||
|
||||
module_t* m = arg2 ? bindmodule(arg2->string) : root_module();
|
||||
|
||||
for(;arg1; arg1 = arg1->next) {
|
||||
|
||||
char* s = arg1->string;
|
||||
char** ss = &s;
|
||||
if (!m->imported_modules)
|
||||
m->imported_modules = hashinit( sizeof(char*), "imported");
|
||||
|
||||
hashenter(m->imported_modules, (HASHDATA**)&ss);
|
||||
}
|
||||
|
||||
return L0;
|
||||
}
|
||||
|
||||
static void add_module_name( void* r_, void* result_ )
|
||||
{
|
||||
char** r = (char**)r_;
|
||||
LIST** result = (LIST**)result_;
|
||||
|
||||
*result = list_new( *result, copystr( *r ) );
|
||||
}
|
||||
|
||||
|
||||
LIST *builtin_imported_modules( PARSE *parse, FRAME *frame )
|
||||
{
|
||||
LIST *arg0 = lol_get( frame->args, 0 );
|
||||
LIST *result = L0;
|
||||
module_t* source_module = bindmodule( arg0 ? arg0->string : 0 );
|
||||
|
||||
if ( source_module->rules )
|
||||
hashenumerate( source_module->imported_modules, add_module_name, &result );
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static void lol_build( LOL* lol, char** elements )
|
||||
{
|
||||
LIST* l = L0;
|
||||
|
||||
@@ -33,6 +33,8 @@ 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 );
|
||||
LIST *builtin_import_module( PARSE *parse, FRAME *args );
|
||||
LIST *builtin_imported_modules( PARSE *parse, FRAME *frame );
|
||||
|
||||
void backtrace( FRAME *frame );
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ module_t* bindmodule( char* name )
|
||||
m->name = newstr( m->name );
|
||||
m->variables = 0;
|
||||
m->rules = 0;
|
||||
m->imported_modules = 0;
|
||||
}
|
||||
string_free( &s );
|
||||
return m;
|
||||
|
||||
@@ -11,6 +11,7 @@ struct module_t
|
||||
char* name;
|
||||
struct hash* rules;
|
||||
struct hash* variables;
|
||||
struct hash* imported_modules;
|
||||
};
|
||||
|
||||
typedef struct module_t module_t ; /* MSVC debugger gets confused unless this is provided */
|
||||
|
||||
@@ -705,15 +705,59 @@ RULE* new_rule_actions( module_t* m, char* rulename, char* command, LIST* bindli
|
||||
return local;
|
||||
}
|
||||
|
||||
RULE *bindrule( char *rulename, module_t* m )
|
||||
/* Looks for a rule in the specified module, and returns it, if found.
|
||||
First checks if the rule is present in the module's rule table.
|
||||
Second, if name of the rule is in the form name1.name2 and name1 is in
|
||||
the list of imported modules, look in module 'name1' for rule 'name2'.
|
||||
*/
|
||||
RULE *lookup_rule( char *rulename, module_t *m, int local_only )
|
||||
{
|
||||
RULE rule, *r = &rule;
|
||||
RULE rule, *r = &rule, *result = 0;
|
||||
module_t* original_module = m;
|
||||
r->name = rulename;
|
||||
|
||||
if ( m->rules && hashcheck( m->rules, (HASHDATA **)&r ) )
|
||||
return r;
|
||||
else
|
||||
return enter_rule( rulename, root_module() );
|
||||
|
||||
if (m->rules && hashcheck( m->rules, (HASHDATA **)&r ) )
|
||||
result = r;
|
||||
else if (!local_only && m->imported_modules) {
|
||||
/* Try splitting the name into module and rule. */
|
||||
char *p = strchr(r->name, '.') ;
|
||||
if (p) {
|
||||
*p = '\0';
|
||||
/* Now, r->name keeps the module name, and p+1 keeps the rule name. */
|
||||
if (hashcheck( m->imported_modules, (HASHDATA **)&r))
|
||||
{
|
||||
result = lookup_rule(p+1, bindmodule(rulename), 1);
|
||||
}
|
||||
*p = '.';
|
||||
}
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
if (local_only && !result->exported)
|
||||
result = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
RULE *bindrule( char *rulename, module_t* m)
|
||||
{
|
||||
RULE *result;
|
||||
|
||||
result = lookup_rule(rulename, m, 0);
|
||||
if (!result)
|
||||
result = lookup_rule(rulename, root_module(), 0);
|
||||
/* We've only one caller, 'evaluate_rule', which will complain about
|
||||
calling underfined rule. We could issue the error
|
||||
here, but we don't have necessary information, such as frame.
|
||||
*/
|
||||
if (!result)
|
||||
result = enter_rule( rulename, root_module() );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
RULE* import_rule( RULE* source, module_t* m, char* name )
|
||||
|
||||
@@ -215,6 +215,18 @@ load_builtins()
|
||||
bind_builtin( "SEARCH_FOR_TARGET",
|
||||
builtin_search_for_target, 0, args );
|
||||
}
|
||||
|
||||
{
|
||||
char * args[] = { "modules_to_import", "+", ":", "target_module", "?", 0 };
|
||||
bind_builtin( "IMPORT_MODULE",
|
||||
builtin_import_module, 0, args );
|
||||
}
|
||||
|
||||
{
|
||||
char * args[] = { "module", "?", 0 };
|
||||
bind_builtin( "IMPORTED_MODULES",
|
||||
builtin_imported_modules, 0, args );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -846,6 +858,47 @@ builtin_search_for_target( PARSE *parse, FRAME *frame )
|
||||
return list_new( L0, t->name );
|
||||
}
|
||||
|
||||
LIST *builtin_import_module( PARSE *parse, FRAME *frame )
|
||||
{
|
||||
LIST* arg1 = lol_get( frame->args, 0 );
|
||||
LIST* arg2 = lol_get( frame->args, 1 );
|
||||
|
||||
module_t* m = arg2 ? bindmodule(arg2->string) : root_module();
|
||||
|
||||
for(;arg1; arg1 = arg1->next) {
|
||||
|
||||
char* s = arg1->string;
|
||||
char** ss = &s;
|
||||
if (!m->imported_modules)
|
||||
m->imported_modules = hashinit( sizeof(char*), "imported");
|
||||
|
||||
hashenter(m->imported_modules, (HASHDATA**)&ss);
|
||||
}
|
||||
|
||||
return L0;
|
||||
}
|
||||
|
||||
static void add_module_name( void* r_, void* result_ )
|
||||
{
|
||||
char** r = (char**)r_;
|
||||
LIST** result = (LIST**)result_;
|
||||
|
||||
*result = list_new( *result, copystr( *r ) );
|
||||
}
|
||||
|
||||
|
||||
LIST *builtin_imported_modules( PARSE *parse, FRAME *frame )
|
||||
{
|
||||
LIST *arg0 = lol_get( frame->args, 0 );
|
||||
LIST *result = L0;
|
||||
module_t* source_module = bindmodule( arg0 ? arg0->string : 0 );
|
||||
|
||||
if ( source_module->rules )
|
||||
hashenumerate( source_module->imported_modules, add_module_name, &result );
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static void lol_build( LOL* lol, char** elements )
|
||||
{
|
||||
LIST* l = L0;
|
||||
|
||||
@@ -33,6 +33,8 @@ 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 );
|
||||
LIST *builtin_import_module( PARSE *parse, FRAME *args );
|
||||
LIST *builtin_imported_modules( PARSE *parse, FRAME *frame );
|
||||
|
||||
void backtrace( FRAME *frame );
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ module_t* bindmodule( char* name )
|
||||
m->name = newstr( m->name );
|
||||
m->variables = 0;
|
||||
m->rules = 0;
|
||||
m->imported_modules = 0;
|
||||
}
|
||||
string_free( &s );
|
||||
return m;
|
||||
|
||||
@@ -11,6 +11,7 @@ struct module_t
|
||||
char* name;
|
||||
struct hash* rules;
|
||||
struct hash* variables;
|
||||
struct hash* imported_modules;
|
||||
};
|
||||
|
||||
typedef struct module_t module_t ; /* MSVC debugger gets confused unless this is provided */
|
||||
|
||||
@@ -705,15 +705,59 @@ RULE* new_rule_actions( module_t* m, char* rulename, char* command, LIST* bindli
|
||||
return local;
|
||||
}
|
||||
|
||||
RULE *bindrule( char *rulename, module_t* m )
|
||||
/* Looks for a rule in the specified module, and returns it, if found.
|
||||
First checks if the rule is present in the module's rule table.
|
||||
Second, if name of the rule is in the form name1.name2 and name1 is in
|
||||
the list of imported modules, look in module 'name1' for rule 'name2'.
|
||||
*/
|
||||
RULE *lookup_rule( char *rulename, module_t *m, int local_only )
|
||||
{
|
||||
RULE rule, *r = &rule;
|
||||
RULE rule, *r = &rule, *result = 0;
|
||||
module_t* original_module = m;
|
||||
r->name = rulename;
|
||||
|
||||
if ( m->rules && hashcheck( m->rules, (HASHDATA **)&r ) )
|
||||
return r;
|
||||
else
|
||||
return enter_rule( rulename, root_module() );
|
||||
|
||||
if (m->rules && hashcheck( m->rules, (HASHDATA **)&r ) )
|
||||
result = r;
|
||||
else if (!local_only && m->imported_modules) {
|
||||
/* Try splitting the name into module and rule. */
|
||||
char *p = strchr(r->name, '.') ;
|
||||
if (p) {
|
||||
*p = '\0';
|
||||
/* Now, r->name keeps the module name, and p+1 keeps the rule name. */
|
||||
if (hashcheck( m->imported_modules, (HASHDATA **)&r))
|
||||
{
|
||||
result = lookup_rule(p+1, bindmodule(rulename), 1);
|
||||
}
|
||||
*p = '.';
|
||||
}
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
if (local_only && !result->exported)
|
||||
result = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
RULE *bindrule( char *rulename, module_t* m)
|
||||
{
|
||||
RULE *result;
|
||||
|
||||
result = lookup_rule(rulename, m, 0);
|
||||
if (!result)
|
||||
result = lookup_rule(rulename, root_module(), 0);
|
||||
/* We've only one caller, 'evaluate_rule', which will complain about
|
||||
calling underfined rule. We could issue the error
|
||||
here, but we don't have necessary information, such as frame.
|
||||
*/
|
||||
if (!result)
|
||||
result = enter_rule( rulename, root_module() );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
RULE* import_rule( RULE* source, module_t* m, char* name )
|
||||
|
||||
@@ -296,16 +296,14 @@ rule import ( module-names + : rules-opt * : rename-opt * )
|
||||
load $(m) : : $(search) ;
|
||||
}
|
||||
|
||||
local all-rules = [ RULENAMES $(m) ] ;
|
||||
|
||||
# import all the rules with qualification
|
||||
IMPORT $(m) : $(all-rules) : $(caller) : $(m).$(all-rules) ;
|
||||
|
||||
IMPORT_MODULE $(m) : $(caller) ;
|
||||
|
||||
if $(rules-opt)
|
||||
{
|
||||
local source-names ;
|
||||
if $(rules-opt) = *
|
||||
{
|
||||
local all-rules = [ RULENAMES $(m) ] ;
|
||||
source-names = $(all-rules) ;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -386,7 +386,7 @@ rule lib-target-class ( name : project
|
||||
basic-target.__init__ $(name) : $(project)
|
||||
: $(sources) : $(requirements) : $(default-build) : $(usage-requirements) ;
|
||||
|
||||
IMPORT builtin : generators.construct : $(__name__) : generators.construct ;
|
||||
import generators : construct : generators.construct ;
|
||||
|
||||
rule construct ( source-targets * : property-set )
|
||||
{
|
||||
|
||||
@@ -168,7 +168,7 @@ rule project-target ( name : project : requirements * : default-build * )
|
||||
import path ;
|
||||
import print ;
|
||||
import property-set ;
|
||||
IMPORT targets : set.difference : $(__name__) : set.difference ;
|
||||
import set : difference : set.difference ;
|
||||
|
||||
abstract-target.__init__ $(name) : $(project) ;
|
||||
|
||||
|
||||
65
test/core_import_module.py
Normal file
65
test/core_import_module.py
Normal file
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (C) Vladimir Prus 2003. Permission to copy, use, modify, sell and
|
||||
# distribute this software is granted provided this copyright notice appears in
|
||||
# all copies. This software is provided "as is" without express or implied
|
||||
# warranty, and with no claim as to its suitability for any purpose.
|
||||
|
||||
from BoostBuild import Tester, List
|
||||
|
||||
|
||||
t = Tester(pass_toolset=0)
|
||||
|
||||
# Test that
|
||||
|
||||
t.write("code", """
|
||||
module a {
|
||||
rule r1 ( )
|
||||
{
|
||||
ECHO R1 ;
|
||||
}
|
||||
}
|
||||
module a2 {
|
||||
rule r2 ( )
|
||||
{
|
||||
ECHO R2 ;
|
||||
}
|
||||
}
|
||||
IMPORT a2 : r2 : : a2.r2 ;
|
||||
|
||||
module b {
|
||||
IMPORT_MODULE a : b ;
|
||||
|
||||
rule test
|
||||
{
|
||||
# Call rule visible via IMPORT_MODULE
|
||||
a.r1 ;
|
||||
# Call rule in global scope
|
||||
a2.r2 ;
|
||||
}
|
||||
}
|
||||
|
||||
IMPORT b : test : : test ;
|
||||
test ;
|
||||
|
||||
module c {
|
||||
rule test
|
||||
{
|
||||
ECHO CTEST ;
|
||||
}
|
||||
}
|
||||
|
||||
IMPORT_MODULE c : ;
|
||||
c.test ;
|
||||
|
||||
actions do-nothing { }
|
||||
do-nothing all ;
|
||||
|
||||
""")
|
||||
|
||||
t.run_build_system("-fcode", stdout="""R1
|
||||
R2
|
||||
CTEST
|
||||
""")
|
||||
|
||||
t.cleanup()
|
||||
@@ -63,7 +63,7 @@ def reorder_tests(tests, first_test):
|
||||
critical_tests = ["unit_tests", "module_actions", "startup_v1", "startup_v2"]
|
||||
|
||||
critical_tests += ["core_d12", "core_typecheck", "core_delete_module",
|
||||
"core_varnames"]
|
||||
"core_varnames", "core_import_module"]
|
||||
|
||||
tests = [ "project_test1",
|
||||
"project_test3",
|
||||
|
||||
@@ -168,7 +168,7 @@ rule project-target ( name : project : requirements * : default-build * )
|
||||
import path ;
|
||||
import print ;
|
||||
import property-set ;
|
||||
IMPORT targets : set.difference : $(__name__) : set.difference ;
|
||||
import set : difference : set.difference ;
|
||||
|
||||
abstract-target.__init__ $(name) : $(project) ;
|
||||
|
||||
|
||||
@@ -296,16 +296,14 @@ rule import ( module-names + : rules-opt * : rename-opt * )
|
||||
load $(m) : : $(search) ;
|
||||
}
|
||||
|
||||
local all-rules = [ RULENAMES $(m) ] ;
|
||||
|
||||
# import all the rules with qualification
|
||||
IMPORT $(m) : $(all-rules) : $(caller) : $(m).$(all-rules) ;
|
||||
|
||||
IMPORT_MODULE $(m) : $(caller) ;
|
||||
|
||||
if $(rules-opt)
|
||||
{
|
||||
local source-names ;
|
||||
if $(rules-opt) = *
|
||||
{
|
||||
local all-rules = [ RULENAMES $(m) ] ;
|
||||
source-names = $(all-rules) ;
|
||||
}
|
||||
else
|
||||
|
||||
65
v2/test/core_import_module.py
Normal file
65
v2/test/core_import_module.py
Normal file
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (C) Vladimir Prus 2003. Permission to copy, use, modify, sell and
|
||||
# distribute this software is granted provided this copyright notice appears in
|
||||
# all copies. This software is provided "as is" without express or implied
|
||||
# warranty, and with no claim as to its suitability for any purpose.
|
||||
|
||||
from BoostBuild import Tester, List
|
||||
|
||||
|
||||
t = Tester(pass_toolset=0)
|
||||
|
||||
# Test that
|
||||
|
||||
t.write("code", """
|
||||
module a {
|
||||
rule r1 ( )
|
||||
{
|
||||
ECHO R1 ;
|
||||
}
|
||||
}
|
||||
module a2 {
|
||||
rule r2 ( )
|
||||
{
|
||||
ECHO R2 ;
|
||||
}
|
||||
}
|
||||
IMPORT a2 : r2 : : a2.r2 ;
|
||||
|
||||
module b {
|
||||
IMPORT_MODULE a : b ;
|
||||
|
||||
rule test
|
||||
{
|
||||
# Call rule visible via IMPORT_MODULE
|
||||
a.r1 ;
|
||||
# Call rule in global scope
|
||||
a2.r2 ;
|
||||
}
|
||||
}
|
||||
|
||||
IMPORT b : test : : test ;
|
||||
test ;
|
||||
|
||||
module c {
|
||||
rule test
|
||||
{
|
||||
ECHO CTEST ;
|
||||
}
|
||||
}
|
||||
|
||||
IMPORT_MODULE c : ;
|
||||
c.test ;
|
||||
|
||||
actions do-nothing { }
|
||||
do-nothing all ;
|
||||
|
||||
""")
|
||||
|
||||
t.run_build_system("-fcode", stdout="""R1
|
||||
R2
|
||||
CTEST
|
||||
""")
|
||||
|
||||
t.cleanup()
|
||||
@@ -63,7 +63,7 @@ def reorder_tests(tests, first_test):
|
||||
critical_tests = ["unit_tests", "module_actions", "startup_v1", "startup_v2"]
|
||||
|
||||
critical_tests += ["core_d12", "core_typecheck", "core_delete_module",
|
||||
"core_varnames"]
|
||||
"core_varnames", "core_import_module"]
|
||||
|
||||
tests = [ "project_test1",
|
||||
"project_test3",
|
||||
|
||||
@@ -386,7 +386,7 @@ rule lib-target-class ( name : project
|
||||
basic-target.__init__ $(name) : $(project)
|
||||
: $(sources) : $(requirements) : $(default-build) : $(usage-requirements) ;
|
||||
|
||||
IMPORT builtin : generators.construct : $(__name__) : generators.construct ;
|
||||
import generators : construct : generators.construct ;
|
||||
|
||||
rule construct ( source-targets * : property-set )
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user