aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-12-02 11:37:15 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-12-02 11:37:15 +0200
commit9891b20350021ce41a950645dd76df20a45c92cc (patch)
tree0cd27041b0c3413e17b9319ae99e87c5e745b1ff
parent74212589a797ca75e55f92a522e198915c0dbaf6 (diff)
Implement optional module loading
The syntax is: using? cli Now each module use results in two bool variables: <module>.loaded and <module>.configured. Also implement variable visibility (the above two variables are limited to project).
-rw-r--r--build/bin/module7
-rw-r--r--build/bin/module.cxx25
-rw-r--r--build/cli/module7
-rw-r--r--build/cli/module.cxx23
-rw-r--r--build/config/module6
-rw-r--r--build/config/module.cxx9
-rw-r--r--build/config/utility7
-rw-r--r--build/context.cxx22
-rw-r--r--build/cxx/module7
-rw-r--r--build/cxx/module.cxx67
-rw-r--r--build/dist/module6
-rw-r--r--build/dist/module.cxx27
-rw-r--r--build/dist/operation.cxx2
-rw-r--r--build/file.cxx5
-rw-r--r--build/install/module6
-rw-r--r--build/install/module.cxx17
-rw-r--r--build/module19
-rw-r--r--build/module.cxx37
-rw-r--r--build/parser.cxx15
-rw-r--r--build/scope21
-rw-r--r--build/scope.cxx38
-rw-r--r--build/target4
-rw-r--r--build/target.cxx15
-rw-r--r--build/target.txx2
-rw-r--r--build/test/module4
-rw-r--r--build/test/module.cxx23
-rw-r--r--build/test/rule.cxx12
-rw-r--r--build/utility3
-rw-r--r--build/variable82
-rw-r--r--build/variable.cxx2
-rw-r--r--tests/using/buildfile5
31 files changed, 332 insertions, 193 deletions
diff --git a/build/bin/module b/build/bin/module
index b87a0b0..5dd720f 100644
--- a/build/bin/module
+++ b/build/bin/module
@@ -6,14 +6,17 @@
#define BUILD_BIN_MODULE
#include <build/types>
+#include <build/utility>
+
#include <build/module>
namespace build
{
namespace bin
{
- extern "C" void
- bin_init (scope&, scope&, const location&, std::unique_ptr<module>&, bool);
+ extern "C" bool
+ bin_init (
+ scope&, scope&, const location&, unique_ptr<module>&, bool, bool);
}
}
diff --git a/build/bin/module.cxx b/build/bin/module.cxx
index 25700c6..c7da647 100644
--- a/build/bin/module.cxx
+++ b/build/bin/module.cxx
@@ -29,12 +29,13 @@ namespace build
static const strings liba_lib {"static"};
static const strings libso_lib {"shared"};
- extern "C" void
+ extern "C" bool
bin_init (scope& r,
scope& b,
const location&,
std::unique_ptr<module>&,
- bool first)
+ bool first,
+ bool)
{
tracer trace ("bin::init");
level5 ([&]{trace << "for " << b.out_path ();});
@@ -81,15 +82,15 @@ namespace build
//
if (first)
{
- variable_pool.find ("config.bin.lib", string_type);
- variable_pool.find ("config.bin.exe.lib", strings_type);
- variable_pool.find ("config.bin.liba.lib", strings_type);
- variable_pool.find ("config.bin.libso.lib", strings_type);
-
- variable_pool.find ("bin.lib", string_type);
- variable_pool.find ("bin.exe.lib", strings_type);
- variable_pool.find ("bin.liba.lib", strings_type);
- variable_pool.find ("bin.libso.lib", strings_type);
+ var_pool.find ("config.bin.lib", string_type);
+ var_pool.find ("config.bin.exe.lib", strings_type);
+ var_pool.find ("config.bin.liba.lib", strings_type);
+ var_pool.find ("config.bin.libso.lib", strings_type);
+
+ var_pool.find ("bin.lib", string_type);
+ var_pool.find ("bin.exe.lib", strings_type);
+ var_pool.find ("bin.liba.lib", strings_type);
+ var_pool.find ("bin.libso.lib", strings_type);
}
// Configure.
@@ -164,6 +165,8 @@ namespace build
install::path<liba> (b, dir_path ("lib")); // Install into install.lib.
install::mode<liba> (b, "644");
+
+ return true;
}
}
}
diff --git a/build/cli/module b/build/cli/module
index cf6258f..221e6a0 100644
--- a/build/cli/module
+++ b/build/cli/module
@@ -6,14 +6,17 @@
#define BUILD_CLI_MODULE
#include <build/types>
+#include <build/utility>
+
#include <build/module>
namespace build
{
namespace cli
{
- extern "C" void
- cli_init (scope&, scope&, const location&, std::unique_ptr<module>&, bool);
+ extern "C" bool
+ cli_init (
+ scope&, scope&, const location&, unique_ptr<module>&, bool, bool);
}
}
diff --git a/build/cli/module.cxx b/build/cli/module.cxx
index 64e95a8..081980b 100644
--- a/build/cli/module.cxx
+++ b/build/cli/module.cxx
@@ -28,12 +28,13 @@ namespace build
{
static compile compile_;
- extern "C" void
+ extern "C" bool
cli_init (scope& root,
scope& base,
- const location& l,
+ const location& loc,
std::unique_ptr<module>&,
- bool first)
+ bool first,
+ bool)
{
tracer trace ("cli::init");
level5 ([&]{trace << "for " << base.out_path ();});
@@ -44,8 +45,12 @@ namespace build
// semantics. So it is better to let the user load cxx
// explicitly.
//
- if (base.find_target_type ("cxx") == nullptr)
- fail (l) << "cxx module must be initialized before cli";
+ {
+ auto l (base["cxx.loaded"]);
+
+ if (!l || !as<bool> (*l))
+ fail (loc) << "cxx module must be loaded before cli";
+ }
// Register target types.
//
@@ -84,10 +89,10 @@ namespace build
//
if (first)
{
- variable_pool.find ("config.cli", string_type); //@@ VAR type
+ var_pool.find ("config.cli", string_type); //@@ VAR type
- variable_pool.find ("config.cli.options", strings_type);
- variable_pool.find ("cli.options", strings_type);
+ var_pool.find ("config.cli.options", strings_type);
+ var_pool.find ("cli.options", strings_type);
}
// Configure.
@@ -156,6 +161,8 @@ namespace build
//
if (const value& v = config::optional (root, "config.cli.options"))
base.assign ("cli.options") += as<strings> (v);
+
+ return true;
}
}
}
diff --git a/build/config/module b/build/config/module
index 58d9814..530fa7b 100644
--- a/build/config/module
+++ b/build/config/module
@@ -6,15 +6,17 @@
#define BUILD_CONFIG_MODULE
#include <build/types>
+#include <build/utility>
+
#include <build/module>
namespace build
{
namespace config
{
- extern "C" void
+ extern "C" bool
config_init (
- scope&, scope&, const location&, std::unique_ptr<module>&, bool);
+ scope&, scope&, const location&, unique_ptr<module>&, bool, bool);
}
}
diff --git a/build/config/module.cxx b/build/config/module.cxx
index bb787a0..b95c6c7 100644
--- a/build/config/module.cxx
+++ b/build/config/module.cxx
@@ -24,12 +24,13 @@ namespace build
//
static const path config_file ("build/config.build");
- extern "C" void
+ extern "C" bool
config_init (scope& r,
scope& b,
const location& l,
std::unique_ptr<module>&,
- bool first)
+ bool first,
+ bool)
{
tracer trace ("config::init");
@@ -39,7 +40,7 @@ namespace build
if (!first)
{
warn (l) << "multiple config module initializations";
- return;
+ return true;
}
const dir_path& out_root (r.out_path ());
@@ -65,6 +66,8 @@ namespace build
if (file_exists (f))
source (f, r, r);
+
+ return true;
}
}
}
diff --git a/build/config/utility b/build/config/utility
index 9a5dc5e..ece7a88 100644
--- a/build/config/utility
+++ b/build/config/utility
@@ -42,8 +42,7 @@ namespace build
const T& default_value,
bool override = false)
{
- return required (
- root, variable_pool.find (name), default_value, override);
+ return required (root, var_pool.find (name), default_value, override);
}
inline std::pair<std::reference_wrapper<const value>, bool>
@@ -68,7 +67,7 @@ namespace build
inline const value&
optional (scope& root, const std::string& var)
{
- return optional (root, variable_pool.find (var));
+ return optional (root, var_pool.find (var));
}
// As above but assumes the value is dir_path and makes it
@@ -81,7 +80,7 @@ namespace build
inline const value&
optional_absolute (scope& root, const std::string& var)
{
- return optional_absolute (root, variable_pool.find (var));
+ return optional_absolute (root, var_pool.find (var));
}
// Check whether there are any variables specified from the
diff --git a/build/context.cxx b/build/context.cxx
index 699cc3c..7f30c81 100644
--- a/build/context.cxx
+++ b/build/context.cxx
@@ -39,7 +39,7 @@ namespace build
targets.clear ();
scopes.clear ();
- variable_pool.clear ();
+ var_pool.clear ();
// Reset meta/operation tables. Note that the order should match
// the id constants in <build/operation>.
@@ -59,22 +59,22 @@ namespace build
// Enter builtin variables.
//
- variable_pool.find ("work", dir_path_type);
- variable_pool.find ("home", dir_path_type);
+ var_pool.find ("work", dir_path_type);
+ var_pool.find ("home", dir_path_type);
- variable_pool.find ("src_root", dir_path_type);
- variable_pool.find ("out_root", dir_path_type);
- variable_pool.find ("src_base", dir_path_type);
- variable_pool.find ("out_base", dir_path_type);
+ var_pool.find ("src_root", dir_path_type);
+ var_pool.find ("out_root", dir_path_type);
+ var_pool.find ("src_base", dir_path_type);
+ var_pool.find ("out_base", dir_path_type);
- variable_pool.find ("project", string_type);
- variable_pool.find ("amalgamation", dir_path_type);
+ var_pool.find ("project", string_type);
+ var_pool.find ("amalgamation", dir_path_type);
// Shouldn't be typed since the value requires pre-processing.
//
- variable_pool.find ("subprojects", nullptr, '=');
+ var_pool.find ("subprojects", nullptr, '=');
- variable_pool.find ("extension", string_type);
+ var_pool.find ("extension", string_type);
// Create global scope. For Win32 this is not a "real" root path.
// On POSIX, however, this is a real path. See the comment in
diff --git a/build/cxx/module b/build/cxx/module
index dcadcdd..a3bd436 100644
--- a/build/cxx/module
+++ b/build/cxx/module
@@ -6,14 +6,17 @@
#define BUILD_CXX_MODULE
#include <build/types>
+#include <build/utility>
+
#include <build/module>
namespace build
{
namespace cxx
{
- extern "C" void
- cxx_init (scope&, scope&, const location&, std::unique_ptr<module>&, bool);
+ extern "C" bool
+ cxx_init (
+ scope&, scope&, const location&, unique_ptr<module>&, bool, bool);
}
}
diff --git a/build/cxx/module.cxx b/build/cxx/module.cxx
index eda3593..4c0e493 100644
--- a/build/cxx/module.cxx
+++ b/build/cxx/module.cxx
@@ -27,12 +27,13 @@ namespace build
{
namespace cxx
{
- extern "C" void
+ extern "C" bool
cxx_init (scope& r,
scope& b,
- const location& l,
+ const location& loc,
std::unique_ptr<module>&,
- bool first)
+ bool first,
+ bool)
{
tracer trace ("cxx::init");
level5 ([&]{trace << "for " << b.out_path ();});
@@ -40,8 +41,12 @@ namespace build
// Initialize the bin module. Only do this if it hasn't already
// been loaded so that we don't overwrite user's bin.* settings.
//
- if (b.find_target_type ("obj") == nullptr)
- load_module ("bin", r, b, l);
+ {
+ auto l (b["bin.loaded"]);
+
+ if (!l || !as<bool> (*l))
+ load_module (false, "bin", r, b, loc);
+ }
// Register target types.
//
@@ -105,31 +110,31 @@ namespace build
//
if (first)
{
- variable_pool.find ("config.cxx", string_type); //@@ VAR type
-
- variable_pool.find ("config.cxx.poptions", strings_type);
- variable_pool.find ("config.cxx.coptions", strings_type);
- variable_pool.find ("config.cxx.loptions", strings_type);
- variable_pool.find ("config.cxx.libs", strings_type);
-
- variable_pool.find ("cxx.poptions", strings_type);
- variable_pool.find ("cxx.coptions", strings_type);
- variable_pool.find ("cxx.loptions", strings_type);
- variable_pool.find ("cxx.libs", strings_type);
-
- variable_pool.find ("cxx.export.poptions", strings_type);
- variable_pool.find ("cxx.export.coptions", strings_type);
- variable_pool.find ("cxx.export.loptions", strings_type);
- variable_pool.find ("cxx.export.libs", strings_type);
-
- variable_pool.find ("cxx.std", string_type);
-
- variable_pool.find ("h.ext", string_type);
- variable_pool.find ("c.ext", string_type);
- variable_pool.find ("hxx.ext", string_type);
- variable_pool.find ("ixx.ext", string_type);
- variable_pool.find ("txx.ext", string_type);
- variable_pool.find ("cxx.ext", string_type);
+ var_pool.find ("config.cxx", string_type); //@@ VAR type
+
+ var_pool.find ("config.cxx.poptions", strings_type);
+ var_pool.find ("config.cxx.coptions", strings_type);
+ var_pool.find ("config.cxx.loptions", strings_type);
+ var_pool.find ("config.cxx.libs", strings_type);
+
+ var_pool.find ("cxx.poptions", strings_type);
+ var_pool.find ("cxx.coptions", strings_type);
+ var_pool.find ("cxx.loptions", strings_type);
+ var_pool.find ("cxx.libs", strings_type);
+
+ var_pool.find ("cxx.export.poptions", strings_type);
+ var_pool.find ("cxx.export.coptions", strings_type);
+ var_pool.find ("cxx.export.loptions", strings_type);
+ var_pool.find ("cxx.export.libs", strings_type);
+
+ var_pool.find ("cxx.std", string_type);
+
+ var_pool.find ("h.ext", string_type);
+ var_pool.find ("c.ext", string_type);
+ var_pool.find ("hxx.ext", string_type);
+ var_pool.find ("ixx.ext", string_type);
+ var_pool.find ("txx.ext", string_type);
+ var_pool.find ("cxx.ext", string_type);
}
// Configure.
@@ -220,6 +225,8 @@ namespace build
path<txx> (b, dir_path ("include"));
path<h> (b, dir_path ("include"));
}
+
+ return true;
}
}
}
diff --git a/build/dist/module b/build/dist/module
index 9fad86f..20082ec 100644
--- a/build/dist/module
+++ b/build/dist/module
@@ -6,15 +6,17 @@
#define BUILD_DIST_MODULE
#include <build/types>
+#include <build/utility>
+
#include <build/module>
namespace build
{
namespace dist
{
- extern "C" void
+ extern "C" bool
dist_init (
- scope&, scope&, const location&, std::unique_ptr<module>&, bool);
+ scope&, scope&, const location&, unique_ptr<module>&, bool, bool);
}
}
diff --git a/build/dist/module.cxx b/build/dist/module.cxx
index 9bd058a..a624c20 100644
--- a/build/dist/module.cxx
+++ b/build/dist/module.cxx
@@ -22,12 +22,13 @@ namespace build
{
static rule rule_;
- extern "C" void
+ extern "C" bool
dist_init (scope& r,
scope& b,
const location& l,
- std::unique_ptr<module>&,
- bool first)
+ unique_ptr<module>&,
+ bool first,
+ bool)
{
tracer trace ("dist::init");
@@ -37,7 +38,7 @@ namespace build
if (!first)
{
warn (l) << "multiple dist module initializations";
- return;
+ return true;
}
const dir_path& out_root (r.out_path ());
@@ -58,20 +59,20 @@ namespace build
//
if (first)
{
- variable_pool.find ("dist", bool_type);
+ var_pool.find ("dist", bool_type);
- variable_pool.find ("dist.package", string_type);
+ var_pool.find ("dist.package", string_type);
- variable_pool.find ("dist.root", dir_path_type);
- variable_pool.find ("config.dist.root", dir_path_type);
+ var_pool.find ("dist.root", dir_path_type);
+ var_pool.find ("config.dist.root", dir_path_type);
//@@ VAR type
//
- variable_pool.find ("dist.cmd", string_type);
- variable_pool.find ("config.dist.cmd", string_type);
+ var_pool.find ("dist.cmd", string_type);
+ var_pool.find ("config.dist.cmd", string_type);
- variable_pool.find ("dist.archives", strings_type);
- variable_pool.find ("config.dist.archives", strings_type);
+ var_pool.find ("dist.archives", strings_type);
+ var_pool.find ("config.dist.archives", strings_type);
}
// Configuration.
@@ -127,6 +128,8 @@ namespace build
v = cv;
}
}
+
+ return true;
}
}
}
diff --git a/build/dist/operation.cxx b/build/dist/operation.cxx
index 2a84894..0069432 100644
--- a/build/dist/operation.cxx
+++ b/build/dist/operation.cxx
@@ -199,7 +199,7 @@ namespace build
// entered.
//
action_targets files;
- const variable& dist_var (variable_pool.find ("dist"));
+ const variable& dist_var (var_pool.find ("dist"));
for (const auto& pt: targets)
{
diff --git a/build/file.cxx b/build/file.cxx
index 970957b..9595d8f 100644
--- a/build/file.cxx
+++ b/build/file.cxx
@@ -528,7 +528,7 @@ namespace build
// the NULL value indicates that we found no subprojects.
//
{
- const variable& var (variable_pool.find ("subprojects"));
+ const variable& var (var_pool.find ("subprojects"));
auto rp (root.vars.assign(var)); // Set NULL by default.
value& v (rp.first);
@@ -794,8 +794,7 @@ namespace build
if (out_root.empty ())
{
const variable& var (
- variable_pool.find ("config.import." + project,
- dir_path_type));
+ var_pool.find ("config.import." + project, dir_path_type));
if (auto l = iroot[var])
{
diff --git a/build/install/module b/build/install/module
index 240d034..78004ef 100644
--- a/build/install/module
+++ b/build/install/module
@@ -6,15 +6,17 @@
#define BUILD_INSTALL_MODULE
#include <build/types>
+#include <build/utility>
+
#include <build/module>
namespace build
{
namespace install
{
- extern "C" void
+ extern "C" bool
install_init (
- scope&, scope&, const location&, std::unique_ptr<module>&, bool);
+ scope&, scope&, const location&, unique_ptr<module>&, bool, bool);
}
}
diff --git a/build/install/module.cxx b/build/install/module.cxx
index a0eed61..8711341 100644
--- a/build/install/module.cxx
+++ b/build/install/module.cxx
@@ -51,7 +51,7 @@ namespace build
vn += name;
vn += var;
const variable& vr (
- variable_pool.find (move (vn), &value_traits<T>::value_type));
+ var_pool.find (move (vn), &value_traits<T>::value_type));
cv = dv != nullptr
? &config::required (r, vr, *dv, override).first.get ()
@@ -62,7 +62,7 @@ namespace build
vn += name;
vn += var;
const variable& vr (
- variable_pool.find (move (vn), &value_traits<T>::value_type));
+ var_pool.find (move (vn), &value_traits<T>::value_type));
value& v (r.assign (vr));
@@ -99,12 +99,13 @@ namespace build
static alias_rule alias_;
static file_rule file_;
- extern "C" void
+ extern "C" bool
install_init (scope& r,
scope& b,
const location& l,
- unique_ptr<build::module>&,
- bool first)
+ unique_ptr<module>&,
+ bool first,
+ bool)
{
tracer trace ("install::init");
@@ -114,7 +115,7 @@ namespace build
if (!first)
{
warn (l) << "multiple install module initializations";
- return;
+ return true;
}
const dir_path& out_root (r.out_path ());
@@ -135,7 +136,7 @@ namespace build
//
if (first)
{
- variable_pool.find ("install", dir_path_type);
+ var_pool.find ("install", dir_path_type);
}
// Configuration.
@@ -172,6 +173,8 @@ namespace build
path<doc> (b, dir_path ("doc")); // Install into install.doc.
path<man> (b, dir_path ("man")); // Install into install.man.
path<man1> (b, dir_path ("man1")); // Install into install.man1.
+
+ return true;
}
}
}
diff --git a/build/module b/build/module
index 43ab1e0..984a50f 100644
--- a/build/module
+++ b/build/module
@@ -21,23 +21,32 @@ namespace build
~module () = default;
};
+ // Return false if the module configuration (normally based on the default
+ // values) was unsuccessful but this is not (yet) an error. One example
+ // would be the optional use of a module. Or a module might remain
+ // unconfigured for as long as it is actually not used (e.g., install,
+ // dist). The return value is used to set the <module>.configured variable.
+ //
extern "C"
using module_init_function =
- void (scope& root,
+ bool (scope& root,
scope& base,
const location&,
std::unique_ptr<module>&,
- bool first); // First time for this project.
+ bool first, // First time for this project.
+ bool optional); // Loaded with 'using?' (optional module).
using loaded_module_map =
std::map<std::string,
std::pair<module_init_function*, std::unique_ptr<module>>>;
// Load the specified module. Used by the parser but also by some
- // modules to load prerequisite modules.
+ // modules to load prerequisite modules. Return true if the module
+ // was both successfully loaded and configured.
//
- void
- load_module (const std::string& name,
+ bool
+ load_module (bool optional,
+ const std::string& name,
scope& root,
scope& base,
const location&);
diff --git a/build/module.cxx b/build/module.cxx
index 0f2b1b2..5f1aeff 100644
--- a/build/module.cxx
+++ b/build/module.cxx
@@ -7,6 +7,7 @@
#include <utility> // make_pair()
#include <build/scope>
+#include <build/variable>
#include <build/diagnostics>
using namespace std;
@@ -15,13 +16,16 @@ namespace build
{
available_module_map builtin_modules;
- void
- load_module (const string& name, scope& root, scope& base, const location& l)
+ bool
+ load_module (bool opt,
+ const string& name,
+ scope& rs,
+ scope& bs,
+ const location& loc)
{
- // First see if this modules has already been loaded for this
- // project.
+ // First see if this modules has already been loaded for this project.
//
- loaded_module_map& lm (root.modules);
+ loaded_module_map& lm (rs.modules);
auto i (lm.find (name));
bool f (i == lm.end ());
@@ -32,11 +36,26 @@ namespace build
auto j (builtin_modules.find (name));
if (j == builtin_modules.end ())
- fail (l) << "unknown module " << name;
-
- i = lm.emplace (name, make_pair (j->second, nullptr)).first;
+ {
+ if (!opt)
+ fail (loc) << "unknown module " << name;
+ }
+ else
+ i = lm.emplace (name, make_pair (j->second, nullptr)).first;
}
- i->second.first (root, base, l, i->second.second, f);
+ bool l (i != lm.end ());
+ bool c (l && i->second.first (rs, bs, loc, i->second.second, f, opt));
+
+ const variable& lv (var_pool.find (name + ".loaded",
+ variable_visibility::project,
+ bool_type));
+ const variable& cv (var_pool.find (name + ".configured",
+ variable_visibility::project,
+ bool_type));
+ bs.assign (lv) = l;
+ bs.assign (cv) = c;
+
+ return l && c;
}
}
diff --git a/build/parser.cxx b/build/parser.cxx
index 05c79db..c896c71 100644
--- a/build/parser.cxx
+++ b/build/parser.cxx
@@ -128,7 +128,8 @@ namespace build
export_ (t, tt);
continue;
}
- else if (n == "using")
+ else if (n == "using" ||
+ n == "using?")
{
using_ (t, tt);
continue;
@@ -360,7 +361,7 @@ namespace build
fail (t) << "append to target type/pattern-specific "
<< "variable " << v;
- const auto& var (variable_pool.find (move (v)));
+ const auto& var (var_pool.find (move (v)));
// Note: expand variables in the value in the context of
// the scope.
@@ -711,7 +712,7 @@ namespace build
if (at == token_type::equal || at == token_type::plus_equal)
{
- var = &variable_pool.find (t.value);
+ var = &var_pool.find (t.value);
val = at == token_type::equal
? &scope_->assign (*var)
: &scope_->append (*var);
@@ -782,6 +783,8 @@ namespace build
{
tracer trace ("parser::using", &path_);
+ bool optional (t.value.back () == '?');
+
// The rest should be a list of module names. Parse them as names
// to get variable expansion, etc.
//
@@ -798,7 +801,7 @@ namespace build
if (!n.simple ())
fail (l) << "module name expected instead of " << n;
- load_module (n.value, *root_, *scope_, l);
+ load_module (optional, n.value, *root_, *scope_, l);
}
if (tt == type::newline)
@@ -912,7 +915,7 @@ namespace build
void parser::
variable (token& t, token_type& tt, string name, token_type kind)
{
- const auto& var (variable_pool.find (move (name)));
+ const auto& var (var_pool.find (move (name)));
names_type vns (variable_value (t, tt, var));
if (kind == type::equal)
@@ -1366,7 +1369,7 @@ namespace build
// Lookup.
//
- const auto& var (variable_pool.find (move (n)));
+ const auto& var (var_pool.find (move (n)));
auto l (target_ != nullptr ? (*target_)[var] : (*scope_)[var]);
// Undefined/NULL namespace variables are not allowed.
diff --git a/build/scope b/build/scope
index 1cfbc10..e52f615 100644
--- a/build/scope
+++ b/build/scope
@@ -76,25 +76,34 @@ namespace build
// in this scope, do it on the the variables map directly.
//
build::lookup<const value>
- operator[] (const variable&) const;
+ operator[] (const variable& var) const
+ {
+ return lookup (nullptr, nullptr, var);
+ }
build::lookup<const value>
operator[] (const std::string& name) const
{
- return operator[] (variable_pool.find (name));
+ return operator[] (var_pool.find (name));
}
// As above, but includes target type/pattern-specific variables.
//
build::lookup<const value>
- lookup (const target_type&, const string& name, const variable&) const;
+ lookup (const target_key& tk, const variable& var) const
+ {
+ return lookup (tk.type, tk.name, var);
+ }
build::lookup<const value>
- lookup (const target_type& tt, const string& n, const string& var) const
+ lookup (const target_key& tk, const string& var) const
{
- return lookup (tt, n, variable_pool.find (var));
+ return lookup (tk, var_pool.find (var));
}
+ build::lookup<const value>
+ lookup (const target_type*, const string* name, const variable&) const;
+
// Return a value suitable for assignment (or append if you only
// want to append to the value from this scope). If the variable
// does not exist in this scope's map, then a new one with the
@@ -119,7 +128,7 @@ namespace build
value&
append (const std::string& name)
{
- return append (variable_pool.find (name));
+ return append (var_pool.find (name));
}
// Target type/pattern-specific variables.
diff --git a/build/scope.cxx b/build/scope.cxx
index 305950b..dfddf20 100644
--- a/build/scope.cxx
+++ b/build/scope.cxx
@@ -13,37 +13,33 @@ namespace build
// scope
//
lookup<const value> scope::
- operator[] (const variable& var) const
+ lookup (const target_type* tt, const string* name, const variable& var) const
{
using result = build::lookup<const value>;
- const value* r (nullptr);
- const scope* s (this);
-
- for (; s != nullptr; s = s->parent_scope ())
+ for (const scope* s (this); s != nullptr; )
{
- if ((r = s->vars.find (var)) != nullptr)
- break;
- }
-
- return result (r, &s->vars);
- }
-
- lookup<const value> scope::
- lookup (const target_type& tt, const string& name, const variable& var) const
- {
- using result = build::lookup<const value>;
-
- for (const scope* s (this); s != nullptr; s = s->parent_scope ())
- {
- if (!s->target_vars.empty ())
+ if (tt != nullptr && !s->target_vars.empty ())
{
- if (auto l = s->target_vars.lookup (tt, name, var))
+ if (auto l = s->target_vars.lookup (*tt, *name, var))
return l;
}
if (auto r = s->vars.find (var))
return result (r, &s->vars);
+
+ switch (var.visibility)
+ {
+ case variable_visibility::scope:
+ s = nullptr;
+ break;
+ case variable_visibility::project:
+ s = s->root () ? nullptr : s->parent_scope ();
+ break;
+ case variable_visibility::normal:
+ s = s->parent_scope ();
+ break;
+ }
}
return result ();
diff --git a/build/target b/build/target
index 66daa66..2aea7ae 100644
--- a/build/target
+++ b/build/target
@@ -283,7 +283,7 @@ namespace build
lookup<const value>
operator[] (const std::string& name) const
{
- return operator[] (variable_pool.find (name));
+ return operator[] (var_pool.find (name));
}
// Return a value suitable for assignment. See class scope for
@@ -304,7 +304,7 @@ namespace build
value&
append (const std::string& name)
{
- return append (variable_pool.find (name));
+ return append (var_pool.find (name));
}
public:
diff --git a/build/target.cxx b/build/target.cxx
index 85eec66..5c31311 100644
--- a/build/target.cxx
+++ b/build/target.cxx
@@ -133,7 +133,7 @@ namespace build
// We cannot simply delegate to scope's lookup() since we also need
// to check the group.
//
- for (const scope* s (&base_scope ()); s != nullptr; s = s->parent_scope ())
+ for (const scope* s (&base_scope ()); s != nullptr; )
{
if (!s->target_vars.empty ())
{
@@ -149,6 +149,19 @@ namespace build
if (auto r = s->vars.find (var))
return result (r, &s->vars);
+
+ switch (var.visibility)
+ {
+ case variable_visibility::scope:
+ s = nullptr;
+ break;
+ case variable_visibility::project:
+ s = s->root () ? nullptr : s->parent_scope ();
+ break;
+ case variable_visibility::normal:
+ s = s->parent_scope ();
+ break;
+ }
}
return result ();
diff --git a/build/target.txx b/build/target.txx
index 48bac21..e347f77 100644
--- a/build/target.txx
+++ b/build/target.txx
@@ -22,7 +22,7 @@ namespace build
{
// Include target type/pattern-specific variables.
//
- auto l (s.lookup (*tk.type, *tk.name, var));
+ auto l (s.lookup (tk, var));
if (!l)
{
diff --git a/build/test/module b/build/test/module
index 0b6af78..25bb2f2 100644
--- a/build/test/module
+++ b/build/test/module
@@ -12,9 +12,9 @@ namespace build
{
namespace test
{
- extern "C" void
+ extern "C" bool
test_init (
- scope&, scope&, const location&, std::unique_ptr<module>&, bool);
+ scope&, scope&, const location&, unique_ptr<module>&, bool, bool);
}
}
diff --git a/build/test/module.cxx b/build/test/module.cxx
index deda6e9..167c09b 100644
--- a/build/test/module.cxx
+++ b/build/test/module.cxx
@@ -21,12 +21,13 @@ namespace build
{
static rule rule_;
- extern "C" void
+ extern "C" bool
test_init (scope& r,
scope& b,
const location& l,
- unique_ptr<build::module>&,
- bool first)
+ unique_ptr<module>&,
+ bool first,
+ bool)
{
tracer trace ("test::init");
@@ -36,7 +37,7 @@ namespace build
if (!first)
{
warn (l) << "multiple test module initializations";
- return;
+ return true;
}
const dir_path& out_root (r.out_path ());
@@ -66,13 +67,15 @@ namespace build
// Enter module variables.
//
{
- variable_pool.find ("test", bool_type);
- variable_pool.find ("test.input", name_type);
- variable_pool.find ("test.output", name_type);
- variable_pool.find ("test.roundtrip", name_type);
- variable_pool.find ("test.options", strings_type);
- variable_pool.find ("test.arguments", strings_type);
+ var_pool.find ("test", bool_type);
+ var_pool.find ("test.input", name_type);
+ var_pool.find ("test.output", name_type);
+ var_pool.find ("test.roundtrip", name_type);
+ var_pool.find ("test.options", strings_type);
+ var_pool.find ("test.arguments", strings_type);
}
+
+ return true;
}
}
}
diff --git a/build/test/rule.cxx b/build/test/rule.cxx
index ea268a9..3a4c91d 100644
--- a/build/test/rule.cxx
+++ b/build/test/rule.cxx
@@ -72,7 +72,7 @@ namespace build
//
if (!l.defined ())
l = t.base_scope ()[
- variable_pool.find (string("test.") + t.type ().name, bool_type)];
+ var_pool.find (string("test.") + t.type ().name, bool_type)];
r = l && as<bool> (*l);
}
@@ -150,13 +150,15 @@ namespace build
string n ("test.");
n += t.type ().name;
- const variable& in (variable_pool.find (n + ".input", name_type));
- const variable& on (variable_pool.find (n + ".output", name_type));
- const variable& rn (variable_pool.find (n + ".roundtrip", name_type));
+ const variable& in (var_pool.find (n + ".input", name_type));
+ const variable& on (var_pool.find (n + ".output", name_type));
+ const variable& rn (var_pool.find (n + ".roundtrip", name_type));
// We should only keep value(s) that were specified together
// in the innermost scope.
//
+ // @@ Shouldn't we stop at project root?
+ //
for (scope* s (&bs); s != nullptr; s = s->parent_scope ())
{
ol = s->vars[on];
@@ -294,7 +296,7 @@ namespace build
var += t.type ().name;
var += '.';
var += n;
- l = t.base_scope ()[variable_pool.find (var, strings_type)];
+ l = t.base_scope ()[var_pool.find (var, strings_type)];
}
if (l)
diff --git a/build/utility b/build/utility
index 7e6b0df..404b33a 100644
--- a/build/utility
+++ b/build/utility
@@ -7,7 +7,8 @@
#include <tuple>
#include <string>
-#include <utility> // move()
+#include <utility> // move()
+#include <cassert> // assert()
#include <exception>
#include <unordered_set>
diff --git a/build/variable b/build/variable
index 7976ab9..061004c 100644
--- a/build/variable
+++ b/build/variable
@@ -7,10 +7,8 @@
#include <map>
#include <vector>
-#include <string>
#include <cstddef> // nullptr_t
-#include <utility> // move(), pair, make_pair()
-#include <cassert>
+#include <utility> // pair, make_pair()
#include <iterator>
#include <functional> // hash, reference_wrapper
#include <type_traits> // conditional, is_reference, remove_reference, etc.
@@ -19,6 +17,8 @@
#include <butl/prefix-map>
#include <build/types>
+#include <build/utility>
+
#include <build/target-type>
namespace build
@@ -37,19 +37,23 @@ namespace build
bool (*const append) (names&, names, const variable&);
};
+ enum class variable_visibility
+ {
+ scope, // This scope (no outer scopes).
+ project, // This project (no outer projects).
+ normal // All outer scopes.
+ };
+
// variable
//
// The two variables are considered the same if they have the same name.
//
struct variable
{
- explicit
- variable (std::string n, const value_type* t = nullptr, char p = '\0')
- : name (std::move (n)), pairs (p), type (t) {}
-
std::string name;
- char pairs;
- const value_type* type; // If NULL, then not (yet) typed.
+ const value_type* type; // If NULL, then not (yet) typed.
+ variable_visibility visibility;
+ char pairs; // Pair symbold or '\0' if not used.
};
inline bool
@@ -616,13 +620,40 @@ namespace build
{
// variable_pool
//
- using variable_set_base = std::unordered_set<variable>;
- struct variable_set: private variable_set_base
+ using variable_pool_base = std::unordered_set<variable>;
+ struct variable_pool: private variable_pool_base
{
const variable&
- find (std::string name, const build::value_type* t = nullptr, char p = '\0')
+ find (string name, const build::value_type* t = nullptr, char p = '\0')
{
- auto r (emplace (std::move (name), t, p));
+ return find (name, nullptr, t, p);
+ }
+
+ const variable&
+ find (string name,
+ variable_visibility v,
+ const build::value_type* t = nullptr,
+ char p = '\0')
+ {
+ return find (name, &v, t, p);
+ }
+
+ using variable_pool_base::clear;
+
+ private:
+ const variable&
+ find (string name,
+ const variable_visibility* vv,
+ const build::value_type* t,
+ char p)
+ {
+ auto r (
+ insert (
+ variable {
+ std::move (name),
+ t,
+ vv != nullptr ? *vv : variable_visibility::normal,
+ p}));
const variable& v (*r.first);
// Update type?
@@ -630,16 +661,25 @@ namespace build
if (!r.second && t != nullptr && v.type != t)
{
assert (v.type == nullptr);
- const_cast<variable&> (v).type = t; // Ok, not changing the key.
+ const_cast<variable&> (v).type = t; // Not changing the key.
+ }
+
+ // 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.
+ //
+ if (!r.second && vv != nullptr && v.visibility != *vv)
+ {
+ assert (v.visibility == variable_visibility::normal); // Default.
+ const_cast<variable&> (v).visibility = *vv; // Not changing the key.
}
return v;
}
-
- using variable_set_base::clear;
};
- extern variable_set variable_pool;
+ extern variable_pool var_pool;
// variable_map
//
@@ -696,7 +736,7 @@ namespace build
lookup<const value>
operator[] (const std::string& name) const
{
- return operator[] (variable_pool.find (name));
+ return operator[] (var_pool.find (name));
}
// Non-const lookup. Only exposed on the map directly.
@@ -710,7 +750,7 @@ namespace build
lookup<value>
operator[] (const std::string& name)
{
- return operator[] (variable_pool.find (name));
+ return operator[] (var_pool.find (name));
}
// The second member in the pair indicates whether the new
@@ -733,13 +773,13 @@ namespace build
std::pair<std::reference_wrapper<value>, bool>
assign (const std::string& name)
{
- return assign (variable_pool.find (name));
+ return assign (var_pool.find (name));
}
std::pair<const_iterator, const_iterator>
find_namespace (const std::string& ns) const
{
- auto r (m_.find_prefix (variable_pool.find (ns)));
+ auto r (m_.find_prefix (var_pool.find (ns)));
return std::make_pair (const_iterator (r.first),
const_iterator (r.second));
}
diff --git a/build/variable.cxx b/build/variable.cxx
index 753e3d3..4386c6a 100644
--- a/build/variable.cxx
+++ b/build/variable.cxx
@@ -341,7 +341,7 @@ namespace build
// variable_set
//
- variable_set variable_pool;
+ variable_pool var_pool;
// variable_type_map
//
diff --git a/tests/using/buildfile b/tests/using/buildfile
new file mode 100644
index 0000000..86baa42
--- /dev/null
+++ b/tests/using/buildfile
@@ -0,0 +1,5 @@
+using? foo
+print $foo.loaded
+print $foo.configured
+
+./: