diff --git a/historic/jam/src/builtins.c b/historic/jam/src/builtins.c index fbe72df50..10929c073 100644 --- a/historic/jam/src/builtins.c +++ b/historic/jam/src/builtins.c @@ -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; diff --git a/historic/jam/src/builtins.h b/historic/jam/src/builtins.h index c405797f1..7dbaad35d 100644 --- a/historic/jam/src/builtins.h +++ b/historic/jam/src/builtins.h @@ -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 ); diff --git a/historic/jam/src/modules.c b/historic/jam/src/modules.c index 4d9985c1c..7f47421fc 100644 --- a/historic/jam/src/modules.c +++ b/historic/jam/src/modules.c @@ -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; diff --git a/historic/jam/src/modules.h b/historic/jam/src/modules.h index 944b0be5f..f52b23e4f 100644 --- a/historic/jam/src/modules.h +++ b/historic/jam/src/modules.h @@ -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 */ diff --git a/historic/jam/src/rules.c b/historic/jam/src/rules.c index fac0894e8..1ce112c39 100644 --- a/historic/jam/src/rules.c +++ b/historic/jam/src/rules.c @@ -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 ) diff --git a/jam_src/builtins.c b/jam_src/builtins.c index fbe72df50..10929c073 100644 --- a/jam_src/builtins.c +++ b/jam_src/builtins.c @@ -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; diff --git a/jam_src/builtins.h b/jam_src/builtins.h index c405797f1..7dbaad35d 100644 --- a/jam_src/builtins.h +++ b/jam_src/builtins.h @@ -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 ); diff --git a/jam_src/modules.c b/jam_src/modules.c index 4d9985c1c..7f47421fc 100644 --- a/jam_src/modules.c +++ b/jam_src/modules.c @@ -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; diff --git a/jam_src/modules.h b/jam_src/modules.h index 944b0be5f..f52b23e4f 100644 --- a/jam_src/modules.h +++ b/jam_src/modules.h @@ -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 */ diff --git a/jam_src/rules.c b/jam_src/rules.c index fac0894e8..1ce112c39 100644 --- a/jam_src/rules.c +++ b/jam_src/rules.c @@ -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 ) diff --git a/kernel/modules.jam b/kernel/modules.jam index bc769aa41..5ccf2fb56 100755 --- a/kernel/modules.jam +++ b/kernel/modules.jam @@ -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 diff --git a/new/builtin.jam b/new/builtin.jam index d6b5675e0..7ff244e4b 100644 --- a/new/builtin.jam +++ b/new/builtin.jam @@ -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 ) { diff --git a/new/targets.jam b/new/targets.jam index 775710432..ec681f0a2 100644 --- a/new/targets.jam +++ b/new/targets.jam @@ -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) ; diff --git a/test/core_import_module.py b/test/core_import_module.py new file mode 100644 index 000000000..d4a1d5426 --- /dev/null +++ b/test/core_import_module.py @@ -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() diff --git a/test/test_all.py b/test/test_all.py index 9e61a78f9..3644c010b 100644 --- a/test/test_all.py +++ b/test/test_all.py @@ -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", diff --git a/v2/build/targets.jam b/v2/build/targets.jam index 775710432..ec681f0a2 100644 --- a/v2/build/targets.jam +++ b/v2/build/targets.jam @@ -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) ; diff --git a/v2/kernel/modules.jam b/v2/kernel/modules.jam index bc769aa41..5ccf2fb56 100755 --- a/v2/kernel/modules.jam +++ b/v2/kernel/modules.jam @@ -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 diff --git a/v2/test/core_import_module.py b/v2/test/core_import_module.py new file mode 100644 index 000000000..d4a1d5426 --- /dev/null +++ b/v2/test/core_import_module.py @@ -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() diff --git a/v2/test/test_all.py b/v2/test/test_all.py index 9e61a78f9..3644c010b 100644 --- a/v2/test/test_all.py +++ b/v2/test/test_all.py @@ -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", diff --git a/v2/tools/builtin.jam b/v2/tools/builtin.jam index d6b5675e0..7ff244e4b 100644 --- a/v2/tools/builtin.jam +++ b/v2/tools/builtin.jam @@ -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 ) {