From dfb51bc816cde2cb345f8a0300205e6ac95a2065 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 30 Mar 2020 15:30:08 +0200 Subject: Switch to project variable visibility by default --- build2/b.cxx | 4 +- build2/cli/init.cxx | 10 +- libbuild2/bin/init.cxx | 57 +++++------ libbuild2/c/init.cxx | 24 +++-- libbuild2/cc/init.cxx | 24 ++--- libbuild2/cc/module.cxx | 9 +- libbuild2/config/init.cxx | 6 +- libbuild2/context.cxx | 180 +++++++++++++++++++--------------- libbuild2/cxx/init.cxx | 41 ++++---- libbuild2/dist/init.cxx | 15 ++- libbuild2/functions-builtin.cxx | 2 +- libbuild2/install/init.cxx | 18 ++-- libbuild2/module.cxx | 2 +- libbuild2/parser.cxx | 5 +- libbuild2/scope.cxx | 4 +- libbuild2/scope.hxx | 20 +++- libbuild2/test/init.cxx | 24 +++-- libbuild2/test/script/parser.test.cxx | 3 +- libbuild2/variable.cxx | 43 ++++++-- libbuild2/variable.hxx | 48 +++++---- libbuild2/version/init.cxx | 12 +-- 21 files changed, 295 insertions(+), 256 deletions(-) diff --git a/build2/b.cxx b/build2/b.cxx index eafa1dc..b74433d 100644 --- a/build2/b.cxx +++ b/build2/b.cxx @@ -1422,7 +1422,7 @@ main (int argc, char* argv[]) for (const variable_override& o: ctx->var_overrides) { - if (o.ovr.visibility != variable_visibility::normal) + if (o.ovr.visibility != variable_visibility::global) continue; // If we have a directory, enter the scope, similar to how we do @@ -1445,7 +1445,7 @@ main (int argc, char* argv[]) { // Ours is either project (%foo) or scope (/foo). // - if (o.ovr.visibility == variable_visibility::normal) + if (o.ovr.visibility == variable_visibility::global) continue; scope& s (o.dir diff --git a/build2/cli/init.cxx b/build2/cli/init.cxx index b0ff4f9..c68a62f 100644 --- a/build2/cli/init.cxx +++ b/build2/cli/init.cxx @@ -41,13 +41,11 @@ namespace build2 { auto& vp (rs.var_pool ()); - // Note: some overridable, some not. + // The special config.cli=false value is recognized as an explicit + // request to leave the module unconfigured. // - // The config.cli=false is recognized as an explicit request to leave - // the module unconfigured. - // - vp.insert ("config.cli", true); - vp.insert ("config.cli.options", true); + vp.insert ("config.cli"); + vp.insert ("config.cli.options"); //@@ TODO: split version into componets (it is stdver). // diff --git a/libbuild2/bin/init.cxx b/libbuild2/bin/init.cxx index 25d5c39..c97cadf 100644 --- a/libbuild2/bin/init.cxx +++ b/libbuild2/bin/init.cxx @@ -50,45 +50,42 @@ namespace build2 assert (first); - // Enter variables. Note: some overridable, some not. + // Enter variables. // // Target is a string and not target_triplet because it can be // specified by the user. // auto& vp (rs.var_pool ()); - const auto vis_tgt (variable_visibility::target); - const auto vis_prj (variable_visibility::project); - - vp.insert ("config.bin.target", true); - vp.insert ("config.bin.pattern", true); + vp.insert ("config.bin.target"); + vp.insert ("config.bin.pattern"); // Library types to build. // - vp.insert ("config.bin.lib", true); + vp.insert ("config.bin.lib"); // Library types to use (in priority order). // - vp.insert ("config.bin.exe.lib", true); - vp.insert ("config.bin.liba.lib", true); - vp.insert ("config.bin.libs.lib", true); + vp.insert ("config.bin.exe.lib"); + vp.insert ("config.bin.liba.lib"); + vp.insert ("config.bin.libs.lib"); // The rpath[_link].auto flag controls automatic rpath behavior, for // example, addition of rpaths for prerequisite libraries (see the cc // module for an example). Default is true. // - vp.insert ("config.bin.rpath", true); - vp.insert ("config.bin.rpath.auto", true); + vp.insert ("config.bin.rpath"); + vp.insert ("config.bin.rpath.auto"); - vp.insert ("config.bin.rpath_link", true); - vp.insert ("config.bin.rpath_link.auto", true); + vp.insert ("config.bin.rpath_link"); + vp.insert ("config.bin.rpath_link.auto"); - vp.insert ("config.bin.prefix", true); - vp.insert ("config.bin.suffix", true); - vp.insert ("config.bin.lib.prefix", true); - vp.insert ("config.bin.lib.suffix", true); - vp.insert ("config.bin.exe.prefix", true); - vp.insert ("config.bin.exe.suffix", true); + vp.insert ("config.bin.prefix"); + vp.insert ("config.bin.suffix"); + vp.insert ("config.bin.lib.prefix"); + vp.insert ("config.bin.lib.suffix"); + vp.insert ("config.bin.exe.prefix"); + vp.insert ("config.bin.exe.suffix"); vp.insert ("bin.lib"); @@ -102,7 +99,7 @@ namespace build2 vp.insert ("bin.rpath_link"); vp.insert ("bin.rpath_link.auto"); - // Link whole archive. Note: non-overridable with target visibility. + // Link whole archive. Note: with target visibility. // // The lookup semantics is as follows: we first look for a prerequisite- // specific value, then for a target-specific value in the library being @@ -118,7 +115,7 @@ namespace build2 // // If unspecified, defaults to false for liba{} and to true for libu*{}. // - vp.insert ("bin.whole", vis_tgt); + vp.insert ("bin.whole", variable_visibility::target); vp.insert ("bin.exe.prefix"); vp.insert ("bin.exe.suffix"); @@ -131,11 +128,11 @@ namespace build2 // only used for platform-independent versions (for platforms-specific // versions we can always derive the pattern automatically). // - vp.insert ("bin.lib.load_suffix", vis_prj); - vp.insert ("bin.lib.load_suffix_pattern", vis_prj); + vp.insert ("bin.lib.load_suffix"); + vp.insert ("bin.lib.load_suffix_pattern"); - vp.insert> ("bin.lib.version", vis_prj); - vp.insert ("bin.lib.version_pattern", vis_prj); + vp.insert> ("bin.lib.version"); + vp.insert ("bin.lib.version_pattern"); return true; } @@ -580,8 +577,8 @@ namespace build2 vp.insert ("bin.ar.path"); vp.insert ("bin.ranlib.path"); - vp.insert ("config.bin.ar", true); - vp.insert ("config.bin.ranlib", true); + vp.insert ("config.bin.ar"); + vp.insert ("config.bin.ranlib"); } // Configuration. @@ -745,7 +742,7 @@ namespace build2 auto& vp (rs.var_pool ()); vp.insert ("bin.ld.path"); - vp.insert ("config.bin.ld", true); + vp.insert ("config.bin.ld"); } // Configuration. @@ -881,7 +878,7 @@ namespace build2 auto& vp (rs.var_pool ()); vp.insert ("bin.rc.path"); - vp.insert ("config.bin.rc", true); + vp.insert ("config.bin.rc"); } // Configuration. diff --git a/libbuild2/c/init.cxx b/libbuild2/c/init.cxx index ffea0ca..e6e28aa 100644 --- a/libbuild2/c/init.cxx +++ b/libbuild2/c/init.cxx @@ -163,20 +163,18 @@ namespace build2 hinters, - // Note: some overridable, some not. - // // NOTE: remember to update documentation if changing anything here. // - vp.insert ("config.c", true), - vp.insert ("config.c.id", true), - vp.insert ("config.c.version", true), - vp.insert ("config.c.target", true), - vp.insert ("config.c.std", true), - vp.insert ("config.c.poptions", true), - vp.insert ("config.c.coptions", true), - vp.insert ("config.c.loptions", true), - vp.insert ("config.c.aoptions", true), - vp.insert ("config.c.libs", true), + vp.insert ("config.c"), + vp.insert ("config.c.id"), + vp.insert ("config.c.version"), + vp.insert ("config.c.target"), + vp.insert ("config.c.std"), + vp.insert ("config.c.poptions"), + vp.insert ("config.c.coptions"), + vp.insert ("config.c.loptions"), + vp.insert ("config.c.aoptions"), + vp.insert ("config.c.libs"), nullptr /* config.c.translatable_headers */, vp.insert ("c.path"), @@ -184,7 +182,7 @@ namespace build2 vp.insert ("c.sys_lib_dirs"), vp.insert ("c.sys_inc_dirs"), - vp.insert ("c.std", variable_visibility::project), + vp.insert ("c.std"), vp.insert ("c.poptions"), vp.insert ("c.coptions"), diff --git a/libbuild2/cc/init.cxx b/libbuild2/cc/init.cxx index 723b678..8d66376 100644 --- a/libbuild2/cc/init.cxx +++ b/libbuild2/cc/init.cxx @@ -74,7 +74,7 @@ namespace build2 // load_module (rs, rs, "bin.vars", loc); - // Enter variables. Note: some overridable, some not. + // Enter variables. // auto& vp (rs.var_pool ()); @@ -82,11 +82,11 @@ namespace build2 // NOTE: remember to update documentation if changing anything here. // - vp.insert ("config.cc.poptions", true); - vp.insert ("config.cc.coptions", true); - vp.insert ("config.cc.loptions", true); - vp.insert ("config.cc.aoptions", true); - vp.insert ("config.cc.libs", true); + vp.insert ("config.cc.poptions"); + vp.insert ("config.cc.coptions"); + vp.insert ("config.cc.loptions"); + vp.insert ("config.cc.aoptions"); + vp.insert ("config.cc.libs"); vp.insert ("cc.poptions"); vp.insert ("cc.coptions"); @@ -101,11 +101,11 @@ namespace build2 // Hint variables (not overridable). // - vp.insert ("config.cc.id"); - vp.insert ("config.cc.hinter"); // Hinting module. - vp.insert ("config.cc.pattern"); - vp.insert ("config.cc.mode"); - vp.insert ("config.cc.target"); + vp.insert ("config.cc.id", false); + vp.insert ("config.cc.hinter", false); // Hinting module. + vp.insert ("config.cc.pattern", false); + vp.insert ("config.cc.mode", false); + vp.insert ("config.cc.target", false); // Compiler runtime and C standard library. // @@ -137,7 +137,7 @@ namespace build2 // Ability to disable using preprocessed output for compilation. // - vp.insert ("config.cc.reprocess", true); + vp.insert ("config.cc.reprocess"); vp.insert ("cc.reprocess"); // Register scope operation callback. diff --git a/libbuild2/cc/module.cxx b/libbuild2/cc/module.cxx index d6c337d..2b2604b 100644 --- a/libbuild2/cc/module.cxx +++ b/libbuild2/cc/module.cxx @@ -78,7 +78,7 @@ namespace build2 // Must be the same as in module's init(). // - const variable& v (vp.insert ("config." + m, true)); + const variable& v (vp.insert ("config." + m)); if (rs[v].defined ()) { @@ -358,8 +358,11 @@ namespace build2 // @@ There are actually two cases to this issue: // // 1. The module is loaded in the outer project (e.g., tests inside a - // project). It feels like this should be handled with project- - // specific variable visibility. + // project). It feels like this should be handled with project + // variable visibility. And now it is with the project being the + // default. Note that this is the reason we don't need any of this + // for the project configuration: there the config.* variables are + // always set on the project root. // // 2. The module is loaded in the outer scope within the same // project. We are currently thinking whether we should even diff --git a/libbuild2/config/init.cxx b/libbuild2/config/init.cxx index f15bfc5..75193bb 100644 --- a/libbuild2/config/init.cxx +++ b/libbuild2/config/init.cxx @@ -44,12 +44,12 @@ namespace build2 // reserved to not be valid module names (`build`). We also currently // treat `import` as special. // + auto& vp (rs.var_pool ()); + // NOTE: all config.** variables are by default made (via a pattern) to // be overridable with global visibility. So we must override this if a // different semantics is required. // - auto& vp (rs.var_pool ()); - const auto v_p (variable_visibility::project); // While config.config.load (see below) could theoretically be specified @@ -166,6 +166,8 @@ namespace build2 auto& vp (rs.var_pool ()); + // Note: config.* is pattern-typed to global visibility. + // const auto v_p (variable_visibility::project); auto& c_l (vp.insert ("config.config.load", true /* ovr */)); diff --git a/libbuild2/context.cxx b/libbuild2/context.cxx index 724a16e..3838451 100644 --- a/libbuild2/context.cxx +++ b/libbuild2/context.cxx @@ -124,45 +124,50 @@ namespace build2 // may reference these things. // scope& gs (global_scope.rw ()); + { + const auto v_g (variable_visibility::global); - gs.assign ("build.work") = work; - gs.assign ("build.home") = home; + // Any variable assigned on the global scope should natually have the + // global visibility. + // + auto set = [&gs, &vp] (const char* var, auto val) + { + using T = decltype (val); + value& v (gs.assign (vp.insert (var, variable_visibility::global))); + v = move (val); + }; - // Build system driver process path. - // - gs.assign ("build.path") = - process_path (nullptr, // Will be filled by value assignment. - path (argv0.recall_string ()), - path (argv0.effect)); + set ("build.work", work); + set ("build.home", home); - // Build system import path for modules. We only set it for the - // development build. - // - var_import_build2 = &vp.insert ("import.build2"); + // Build system driver process path. + // + set ("build.path", + process_path (nullptr, // Will be filled by value assignment. + path (argv0.recall_string ()), + path (argv0.effect))); - if (!build_installed) - { + // Build system import path for modules. We only set it for the + // development build. + // + var_import_build2 = &vp.insert ("import.build2", v_g); + + if (!build_installed) + { #ifdef BUILD2_IMPORT_PATH - gs.assign (var_import_build2) = abs_dir_path (BUILD2_IMPORT_PATH); + gs.assign (var_import_build2) = abs_dir_path (BUILD2_IMPORT_PATH); #endif - } + } - // Build system verbosity level. - // - gs.assign ("build.verbosity") = verb; + // Build system verbosity level. + // + set ("build.verbosity", uint64_t (verb)); - // Build system version (similar to what we do in the version module - // except here we don't include package epoch/revision). - // - { + // Build system version (similar to what we do in the version module + // except here we don't include package epoch/revision). + // const standard_version& v (build_version); - auto set = [&gs, &vp] (const char* var, auto val) - { - using T = decltype (val); - gs.assign (vp.insert (var)) = move (val); - }; - // Note: here we assume epoch will always be 1 and therefore omit the // project_ prefix in a few places. // @@ -201,16 +206,15 @@ namespace build2 // not re-package things during the queued-to-public transition. // set ("build.version.stage", LIBBUILD2_STAGE); - } - // Enter the host information. Rather than jumping through hoops like - // config.guess, for now we are just going to use the compiler target we - // were built with. While it is not as precise (for example, a binary - // built for i686 might be running on x86_64), it is good enough of an - // approximation/fallback since most of the time we are interested in just - // the target class (e.g., linux, windows, macos). - // - { + // Enter the host information. Rather than jumping through hoops like + // config.guess, for now we are just going to use the compiler target we + // were built with. While it is not as precise (for example, a binary + // built for i686 might be running on x86_64), it is good enough of an + // approximation/fallback since most of the time we are interested in + // just the target class (e.g., linux, windows, macos). + // + // Did the user ask us to use config.guess? // string orig (config_guess @@ -231,19 +235,22 @@ namespace build2 // Also enter as build.host.{cpu,vendor,system,version,class} for // convenience of access. // - gs.assign ("build.host.cpu") = t.cpu; - gs.assign ("build.host.vendor") = t.vendor; - gs.assign ("build.host.system") = t.system; - gs.assign ("build.host.version") = t.version; - gs.assign ("build.host.class") = t.class_; + set ("build.host.cpu", t.cpu); + set ("build.host.vendor", t.vendor); + set ("build.host.system", t.system); + set ("build.host.version", t.version); + set ("build.host.class", t.class_); - gs.assign ("build.host") = move (t); + set ("build.host", move (t)); } catch (const invalid_argument& e) { fail << "unable to parse build host '" << orig << "': " << e << info << "consider using the --config-guess option"; } + + var_build_meta_operation = + &vp.insert ("build.meta_operation", v_g); } // Register builtin target types. @@ -271,6 +278,39 @@ namespace build2 } } + // Enter builtin variable patterns. + // + // Note that we must do this prior to entering overrides below. + // + { + const auto v_g (variable_visibility::global); + const auto v_p (variable_visibility::project); + + // All config.** variables are overridable with global visibility. + // + // For the config.**.configured semantics, see config::unconfigured(). + // + // Note that some config.config.* variables have project visibility thus + // the match argument is false. + // + vp.insert_pattern ("config.**", nullopt, true, v_g, true, false); + vp.insert_pattern ("config.**.configured", false, v_p); + + // file.cxx:import() (note: order is important; see insert_pattern()). + // + vp.insert_pattern ("config.import.*", true, v_g, true); + vp.insert_pattern ("config.import.**", true, v_g, true); + + // module.cxx:boot/init_module(). + // + // Note that we also have the config..configured variable (see + // above). + // + vp.insert_pattern ("**.booted", false /* overridable */, v_p); + vp.insert_pattern ("**.loaded", false, v_p); + vp.insert_pattern ("**.configured", false, v_p); + } + // Parse and enter the command line variables. We do it before entering // any other variables so that all the variables that are overriden are // marked as such first. Then, as we enter variables, we can verify that @@ -400,14 +440,18 @@ namespace build2 if (c == '!' && dir) fail << "scope-qualified global override of variable " << n; - variable& var (const_cast ( - vp.insert (n, true /* overridable */))); + // Pre-enter the main variable. Note that we rely on all the overridable + // variables with global visibility to be known (either entered or + // handled via a pettern) at this stage. + // + variable& var ( + const_cast (vp.insert (n, true /* overridable */))); const variable* o; { variable_visibility v (c == '/' ? variable_visibility::scope : c == '%' ? variable_visibility::project : - variable_visibility::normal); + variable_visibility::global); const char* k (tt == token_type::assign ? "__override" : tt == token_type::append ? "__suffix" : "__prefix"); @@ -474,52 +518,28 @@ namespace build2 data_->global_var_overrides.push_back (s); } - // Enter builtin variables and patterns. + // Enter builtin variables. // - const auto v_g (variable_visibility::normal); // Global. - const auto v_p (variable_visibility::project); const auto v_t (variable_visibility::target); const auto v_q (variable_visibility::prereq); - // All config.** variables are by default overridable with global - // visibility. - // - // For the config.**.configured semantics, see config::unconfigured(). - // - vp.insert_pattern ("config.**", nullopt, true, v_g, true, false); - vp.insert_pattern ("config.**.configured", false, v_p); - - // file.cxx:import() (note that order is important; see insert_pattern()). - // - vp.insert_pattern ("config.import.*", true, v_g, true); - vp.insert_pattern ("config.import.**", true, v_g, true); - - // module.cxx:boot/init_module(). - // - // Note that we also have the config..configured variable (see - // above). - // - vp.insert_pattern ("**.booted", false /* overridable */, v_p); - vp.insert_pattern ("**.loaded", false, v_p); - vp.insert_pattern ("**.configured", false, v_p); - var_src_root = &vp.insert ("src_root"); var_out_root = &vp.insert ("out_root"); var_src_base = &vp.insert ("src_base"); var_out_base = &vp.insert ("out_base"); - var_forwarded = &vp.insert ("forwarded", v_p); + var_forwarded = &vp.insert ("forwarded"); // Note that subprojects is not typed since the value requires // pre-processing (see file.cxx). // - var_project = &vp.insert ("project", v_p); - var_amalgamation = &vp.insert ("amalgamation", v_p); - var_subprojects = &vp.insert ("subprojects", v_p); - var_version = &vp.insert ("version", v_p); + var_project = &vp.insert ("project"); + var_amalgamation = &vp.insert ("amalgamation"); + var_subprojects = &vp.insert ("subprojects"); + var_version = &vp.insert ("version"); - var_project_url = &vp.insert ("project.url", v_p); - var_project_summary = &vp.insert ("project.summary", v_p); + var_project_url = &vp.insert ("project.url"); + var_project_summary = &vp.insert ("project.summary"); var_import_target = &vp.insert ("import.target"); @@ -533,8 +553,6 @@ namespace build2 gs.target_vars[exe::static_type]["*"].assign (var_backlink) = "true"; gs.target_vars[doc::static_type]["*"].assign (var_backlink) = "true"; - var_build_meta_operation = &vp.insert ("build.meta_operation"); - // Register builtin rules. // { diff --git a/libbuild2/cxx/init.cxx b/libbuild2/cxx/init.cxx index 4c4f6ad..1d8421c 100644 --- a/libbuild2/cxx/init.cxx +++ b/libbuild2/cxx/init.cxx @@ -91,13 +91,13 @@ namespace build2 // Feature flags. // - auto enter = [&rs] (const char* v) -> const variable& - { - return rs.var_pool ().insert (v, variable_visibility::project); - }; + auto& vp (rs.var_pool ()); - //bool concepts (false); auto& v_c (enter ("cxx.features.concepts")); - bool modules (false); auto& v_m (enter ("cxx.features.modules")); + //bool concepts (false); + //auto& v_c (vp.insert ("cxx.features.concepts")); + + bool modules (false); + auto& v_m (vp.insert ("cxx.features.modules")); // NOTE: see also module sidebuild subproject if changing anything about // modules here. @@ -403,20 +403,18 @@ namespace build2 hinters, - // Note: some overridable, some not. - // // NOTE: remember to update documentation if changing anything here. // - vp.insert ("config.cxx", true), - vp.insert ("config.cxx.id", true), - vp.insert ("config.cxx.version", true), - vp.insert ("config.cxx.target", true), - vp.insert ("config.cxx.std", true), - vp.insert ("config.cxx.poptions", true), - vp.insert ("config.cxx.coptions", true), - vp.insert ("config.cxx.loptions", true), - vp.insert ("config.cxx.aoptions", true), - vp.insert ("config.cxx.libs", true), + vp.insert ("config.cxx"), + vp.insert ("config.cxx.id"), + vp.insert ("config.cxx.version"), + vp.insert ("config.cxx.target"), + vp.insert ("config.cxx.std"), + vp.insert ("config.cxx.poptions"), + vp.insert ("config.cxx.coptions"), + vp.insert ("config.cxx.loptions"), + vp.insert ("config.cxx.aoptions"), + vp.insert ("config.cxx.libs"), // List of translatable headers. Inclusions of such headers are // translated to the corresponding header unit imports. @@ -427,14 +425,14 @@ namespace build2 // opposed to -I) header search paths. Note also that all entries must // be specified before loading the cxx module. // - &vp.insert ("config.cxx.translatable_headers", true), + &vp.insert ("config.cxx.translatable_headers"), vp.insert ("cxx.path"), vp.insert ("cxx.mode"), vp.insert ("cxx.sys_lib_dirs"), vp.insert ("cxx.sys_inc_dirs"), - vp.insert ("cxx.std", variable_visibility::project), + vp.insert ("cxx.std"), vp.insert ("cxx.poptions"), vp.insert ("cxx.coptions"), @@ -602,8 +600,7 @@ namespace build2 bool symexport (false); if (modules) { - auto& var (vp.insert ("cxx.features.symexport", - variable_visibility::project)); + auto& var (vp.insert ("cxx.features.symexport")); symexport = cast_false (rs[var]); cm.x_symexport = &var; } diff --git a/libbuild2/dist/init.cxx b/libbuild2/dist/init.cxx index 8eaafa2..a95f768 100644 --- a/libbuild2/dist/init.cxx +++ b/libbuild2/dist/init.cxx @@ -38,8 +38,6 @@ namespace build2 // auto& vp (rs.var_pool ()); - // Note: some overridable, some not. - // // config.dist.archives is a list of archive extensions (e.g., zip, // tar.gz) that can be optionally prefixed with a directory. If it is // relative, then it is prefixed with config.dist.root. Otherwise, the @@ -51,15 +49,15 @@ namespace build2 // absent, then the checksum file is written into the same directory as // the corresponding archive. // - vp.insert ("config.dist.root", true); - vp.insert ("config.dist.archives", true); - vp.insert ("config.dist.checksums", true); - vp.insert ("config.dist.cmd", true); + vp.insert ("config.dist.root"); + vp.insert ("config.dist.archives"); + vp.insert ("config.dist.checksums"); + vp.insert ("config.dist.cmd"); // Allow distribution of uncommitted projects. This is enforced by the // version module. // - vp.insert ("config.dist.uncommitted", true); + vp.insert ("config.dist.uncommitted"); vp.insert ("dist.root"); vp.insert ("dist.cmd"); @@ -71,8 +69,7 @@ namespace build2 // Project's package name. // - auto& v_d_p ( - vp.insert ("dist.package", variable_visibility::project)); + auto& v_d_p (vp.insert ("dist.package")); // Create the module. // diff --git a/libbuild2/functions-builtin.cxx b/libbuild2/functions-builtin.cxx index 4e28741..afafe66 100644 --- a/libbuild2/functions-builtin.cxx +++ b/libbuild2/functions-builtin.cxx @@ -27,7 +27,7 @@ namespace build2 return (*s)[convert (move (name))].defined (); }; - // Return variable visibility if it exists and NULL otherwise. + // Return variable visibility if it has been entered and NULL otherwise. // f["visibility"] = [](const scope* s, names name) { diff --git a/libbuild2/install/init.cxx b/libbuild2/install/init.cxx index 06e5d3a..d0fb4bc 100644 --- a/libbuild2/install/init.cxx +++ b/libbuild2/install/init.cxx @@ -52,8 +52,6 @@ namespace build2 if (spec) { - // Note: overridable. - // vn = "config.install"; if (!global) { @@ -61,7 +59,7 @@ namespace build2 vn += name; } vn += var; - const variable& vr (rs.var_pool ().insert (move (vn), true)); + const variable& vr (rs.var_pool ().insert (move (vn))); using config::lookup_config; @@ -75,8 +73,6 @@ namespace build2 if (global) return; - // Note: not overridable. - // vn = "install."; vn += name; vn += var; @@ -196,18 +192,16 @@ namespace build2 // Note that the set_dir() calls below enter some more. // { - // Note: not overridable. - // // The install variable is a path, not dir_path, since it can be used // to both specify the target directory (to install with the same file // name) or target file (to install with a different name). And the // way we distinguish between the two is via the presence/absence of // the trailing directory separator. // - vp.insert ("install", variable_visibility::target); - vp.insert ("for_install", variable_visibility::prereq); - vp.insert ("install.mode", variable_visibility::project); - vp.insert ("install.subdirs", variable_visibility::project); + vp.insert ("install", variable_visibility::target); + vp.insert ("for_install", variable_visibility::prereq); + vp.insert ("install.mode"); + vp.insert ("install.subdirs"); } // Register our rules. @@ -278,7 +272,7 @@ namespace build2 // { auto& var (vp.insert ( "install.chroot")); - auto& cvar (vp.insert ("config.install.chroot", true)); + auto& cvar (vp.insert ("config.install.chroot")); value& v (rs.assign (var)); diff --git a/libbuild2/module.cxx b/libbuild2/module.cxx index 777f177..28d2468 100644 --- a/libbuild2/module.cxx +++ b/libbuild2/module.cxx @@ -571,7 +571,7 @@ namespace build2 } } - // Note: pattern-typed in context ctor as project-visibility variables of + // Note: pattern-typed in context ctor as project visibility variables of // type bool. // // We call the variable 'loaded' rather than 'inited' because it is diff --git a/libbuild2/parser.cxx b/libbuild2/parser.cxx index 68e7ed9..532b357 100644 --- a/libbuild2/parser.cxx +++ b/libbuild2/parser.cxx @@ -1823,7 +1823,7 @@ namespace build2 // Note that even though we are relying on the config.** variable // pattern to set global visibility, let's make sure as a sanity check. // - if (var.visibility != variable_visibility::normal) + if (var.visibility != variable_visibility::global) { fail (t) << "configuration variable " << var << " has " << var.visibility << " visibility"; @@ -3224,7 +3224,8 @@ namespace build2 << var.type->name << " to " << type->name; } - //@@ TODO: the same for vis and ovr. + //@@ TODO: the same checks for vis and ovr (when we have the corresponding + // attributes). if (type || vis || ovr) ctx.var_pool.update (const_cast (var), diff --git a/libbuild2/scope.cxx b/libbuild2/scope.cxx index d18c4eb..842b839 100644 --- a/libbuild2/scope.cxx +++ b/libbuild2/scope.cxx @@ -164,7 +164,7 @@ namespace build2 case variable_visibility::project: s = s->root () ? nullptr : s->parent_scope (); break; - case variable_visibility::normal: + case variable_visibility::global: s = s->parent_scope (); break; case variable_visibility::prereq: @@ -259,7 +259,7 @@ namespace build2 break; } - case variable_visibility::normal: + case variable_visibility::global: break; case variable_visibility::target: case variable_visibility::prereq: diff --git a/libbuild2/scope.hxx b/libbuild2/scope.hxx index cb20f79..39be143 100644 --- a/libbuild2/scope.hxx +++ b/libbuild2/scope.hxx @@ -187,13 +187,15 @@ namespace build2 value& assign (const variable* var) {return vars.assign (var);} // For cached. + // Assign an untyped non-overridable variable with project visibility. + // value& assign (string name) { return assign (var_pool ().insert (move (name))); } - // Assign a typed non-overridable variable with normal visibility. + // As above, but assign a typed variable. // template value& @@ -210,6 +212,22 @@ namespace build2 return v.as (); } + template + T& + assign (const variable& var, T&& val) + { + value& v (assign (var) = forward (val)); + return v.as (); + } + + template + T& + assign (const variable* var, T&& val) + { + value& v (assign (var) = forward (val)); + return v.as (); + } + // Return a value suitable for appending. If the variable does not // exist in this scope's map, then outer scopes are searched for // the same variable. If found then a new variable with the found diff --git a/libbuild2/test/init.cxx b/libbuild2/test/init.cxx index a21e8f2..16891c6 100644 --- a/libbuild2/test/init.cxx +++ b/libbuild2/test/init.cxx @@ -46,25 +46,23 @@ namespace build2 // // Specified as @ pairs with both sides being // optional. The variable is untyped (we want a list of name-pairs), - // overridable, and inheritable. The target is relative (in essence a - // prerequisite) which is resolved from the (root) scope where the - // config.test value is defined. + // overridable, and with global visibiility. The target is relative + // (in essence a prerequisite) which is resolved from the (root) scope + // where the config.test value is defined. // - vp.insert ("config.test", true), + vp.insert ("config.test"), // Test working directory before/after cleanup (see Testscript spec // for semantics). // - vp.insert ("config.test.output", true), + vp.insert ("config.test.output"), // The test variable is a name which can be a path (with the // true/false special values) or a target name. // - // Note: none are overridable. - // - vp.insert ("test", variable_visibility::target), - vp.insert ("test.options", variable_visibility::project), - vp.insert ("test.arguments", variable_visibility::project), + vp.insert ("test", variable_visibility::target), + vp.insert ("test.options"), + vp.insert ("test.arguments"), // Prerequisite-specific. // @@ -93,7 +91,7 @@ namespace build2 // Test target platform. // - vp.insert ("test.target", variable_visibility::project) + vp.insert ("test.target") }; // This one is used by other modules/rules. @@ -102,8 +100,8 @@ namespace build2 // These are only used in testscript. // - vp.insert ("test.redirects", variable_visibility::project); - vp.insert ("test.cleanups", variable_visibility::project); + vp.insert ("test.redirects"); + vp.insert ("test.cleanups"); // Unless already set, default test.target to build.host. Note that it // can still be overriden by the user, e.g., in root.build. diff --git a/libbuild2/test/script/parser.test.cxx b/libbuild2/test/script/parser.test.cxx index 44be998..a12fda4 100644 --- a/libbuild2/test/script/parser.test.cxx +++ b/libbuild2/test/script/parser.test.cxx @@ -206,8 +206,7 @@ namespace build2 value& v ( tt.assign ( - ctx.var_pool.rw ().insert ( - "test.target", variable_visibility::project))); + ctx.var_pool.rw ().insert ("test.target"))); v = cast (ctx.global_scope["build.host"]); diff --git a/libbuild2/variable.cxx b/libbuild2/variable.cxx index 48fcf40..d16fcb4 100644 --- a/libbuild2/variable.cxx +++ b/libbuild2/variable.cxx @@ -22,7 +22,7 @@ namespace build2 switch (v) { - case variable_visibility::normal: r = "normal"; break; + case variable_visibility::global: r = "global"; break; case variable_visibility::project: r = "project"; break; case variable_visibility::scope: r = "scope"; break; case variable_visibility::target: r = "target"; break; @@ -1161,14 +1161,34 @@ namespace build2 var.type = t; } - // Change visibility? While this might at first seem like a bad idea, - // it can happen that the variable lookup happens before any values - // were set, in which case the variable will be entered with the - // default visibility. + // Change visibility? While this might at first seem like a bad idea, it + // can happen that the variable lookup happens before any values were set + // in which case the variable will be entered with the default (project) + // visibility. + // + // For example, a buildfile, for some reason, could reference a target- + // specific variable (say, test) before loading a module (say, test) that + // sets this visibility. While strictly speaking we could have potentially + // already made a lookup using the wrong visibility, presumably this + // should be harmless. + // + // @@ But consider a situation where this test is set on scope prior to + // loading the module: now this value will effectively be unreachable + // without any diagnostics. So maybe we should try to clean this up. + // But we will need proper diagnostics instead of assert (which means + // we would probably need to track the location where the variable + // was first entered). + // + // Note also that this won't work well for global visibility since we only + // allow restrictions. The thinking is that global visibility is special + // and requiring special arrangements (like variable patterns, similar to + // how we've done it for config.*) is reasonable. In fact, it feels like + // only the build system core should be allowed to use global visibility + // (see the context ctor for details). // if (uv) { - assert (var.visibility == variable_visibility::normal); // Default. + assert (*v > var.visibility); var.visibility = *v; } } @@ -1219,7 +1239,14 @@ namespace build2 if (v == nullptr) v = &*p.visibility; else if (p.match) - assert (*v == *p.visibility); + { + // Allow the pattern to restrict but not relax. + // + if (*p.visibility > *v) + v = &*p.visibility; + else + assert (*v == *p.visibility); + } } if (p.overridable) @@ -1277,7 +1304,7 @@ namespace build2 nullptr, pt, nullptr, - pv != nullptr ? *pv : variable_visibility::normal})); + pv != nullptr ? *pv : variable_visibility::project})); variable& var (r.first->second); diff --git a/libbuild2/variable.hxx b/libbuild2/variable.hxx index bf0aa00..0eaf170 100644 --- a/libbuild2/variable.hxx +++ b/libbuild2/variable.hxx @@ -98,10 +98,10 @@ namespace build2 // enum class variable_visibility: uint8_t { - // Note that the search for target type/pattern-specific terminates at - // the project boundary. + // Note that the search for target type/pattern-specific variables always + // terminates at the project boundary but includes the global scope. // - normal, // All outer scopes. + global, // All outer scopes. project, // This project (no outer projects). scope, // This scope (no outer scopes). target, // Target and target type/pattern-specific. @@ -192,8 +192,8 @@ namespace build2 // context ctor before any other variables. Project wide overrides are // entered in main(). Overriding happens in scope::find_override(). // - // NULL type and normal visibility are the defaults and can be overridden by - // "tighter" values. + // Untyped (NULL type) and project visibility are the defaults but can be + // overridden by "tighter" values. // struct variable { @@ -1068,8 +1068,10 @@ namespace build2 // Find existing or insert new variable. // // Unless specified explicitly, the variable is untyped, non-overridable, - // and with normal visibility but these may be overridden by a pattern. - // Note also that a pattern may restrict (but not relax) overridability. + // and with project visibility but these may be overridden by a pattern. + // + // Note also that a pattern and later insertions may restrict (but not + // relax) visibility and overridability. const variable& insert (string name) @@ -1077,18 +1079,12 @@ namespace build2 return insert (move (name), nullptr, nullptr, nullptr); } - // Insert or override (type/visibility). Note that by default the - // variable is not overridable. - // const variable& insert (string name, variable_visibility v) { return insert (move (name), nullptr, &v, nullptr); } - // Note that overridability can still be restricted (but not relaxed) by - // another call to insert or via patterns (see below). - // const variable& insert (string name, bool overridable) { @@ -1149,19 +1145,19 @@ namespace build2 LIBBUILD2_SYMEXPORT const variable& insert_alias (const variable& var, string name); - // Insert a variable pattern. Any variable that matches this pattern - // will have the specified type, visibility, and overridability. If - // match is true, then individual insertions of the matching variable - // must match the specified type/visibility/overridability. Otherwise, - // individual insertions can provide alternative values and the pattern - // values are a fallback (if you specify false you better be very clear - // about what you are trying to achieve). - // - // The pattern must be in the form [.](*|**)[.] where - // '*' matches single component stems (i.e., 'foo' but not 'foo.bar') - // and '**' matches single and multi-component stems. Note that only - // multi-component variables are considered for pattern matching (so - // just '*' won't match anything). + // Insert a variable pattern. Any variable that matches this pattern will + // have the specified type, visibility, and overridability. If match is + // true, then individual insertions of the matching variable must match + // the specified type/visibility/overridability. Otherwise, individual + // insertions can provide alternative values and the pattern values are a + // fallback (if you specify false you better be very clear about what you + // are trying to achieve). + // + // The pattern must be in the form [.](*|**)[.] where '*' + // matches single component stems (i.e., 'foo' but not 'foo.bar') and '**' + // matches single and multi-component stems. Note that only multi- + // component variables are considered for pattern matching (so just '*' + // won't match anything). // // The patterns are matched in the more-specific-first order where the // pattern is considered more specific if it has a greater sum of its diff --git a/libbuild2/version/init.cxx b/libbuild2/version/init.cxx index 135f2db..d30dc24 100644 --- a/libbuild2/version/init.cxx +++ b/libbuild2/version/init.cxx @@ -226,17 +226,13 @@ namespace build2 // Note also that we have "gifted" the config.version variable name to // the config module. // - auto& vp (rs.var_pool ()); - - auto set = [&vp, &rs] (const char* var, auto val) + auto set = [&rs] (auto var, auto val) { - using T = decltype (val); - auto& v (vp.insert (var, variable_visibility::project)); - rs.assign (v) = move (val); + rs.assign (var, move (val)); }; - if (!sum.empty ()) rs.assign (ctx.var_project_summary) = move (sum); - if (!url.empty ()) rs.assign (ctx.var_project_url) = move (url); + if (!sum.empty ()) set (ctx.var_project_summary, move (sum)); + if (!url.empty ()) set (ctx.var_project_url, move (url)); set ("version", v.string ()); // Project version (var_version). -- cgit v1.1