aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/b.cxx7
-rw-r--r--build/config/operation.cxx6
-rw-r--r--build/context.cxx4
-rw-r--r--build/file.cxx114
-rw-r--r--build/name4
-rw-r--r--build/variable7
-rw-r--r--tests/amalgam/config/buildfile2
7 files changed, 105 insertions, 39 deletions
diff --git a/build/b.cxx b/build/b.cxx
index 387df1c..36d0b21 100644
--- a/build/b.cxx
+++ b/build/b.cxx
@@ -464,11 +464,8 @@ main (int argc, char* argv[])
{
for (const name& n: v.as<const list_value&> ())
{
- // Should be a list of directories.
- //
- if (!n.type.empty () || !n.value.empty () || n.dir.empty ())
- fail << "expected directory in subprojects variable "
- << "instead of " << n;
+ if (n.pair != '\0')
+ continue; // Skip project names.
if (out_base.sub (out_root / n.dir))
fail << tn << " is in a subproject of " << out_root <<
diff --git a/build/config/operation.cxx b/build/config/operation.cxx
index ea338f5..43a5718 100644
--- a/build/config/operation.cxx
+++ b/build/config/operation.cxx
@@ -176,6 +176,9 @@ namespace build
{
for (const name& n: v.as<const list_value&> ())
{
+ if (n.pair != '\0')
+ continue; // Skip project names.
+
dir_path out_nroot (out_root / n.dir);
scope& nroot (scopes.find (out_nroot));
@@ -270,6 +273,9 @@ namespace build
{
for (const name& n: v.as<const list_value&> ())
{
+ if (n.pair != '\0')
+ continue; // Skip project names.
+
// Create and bootstrap subproject's root scope.
//
dir_path out_nroot (out_root / n.dir);
diff --git a/build/context.cxx b/build/context.cxx
index dce6967..32c9e9b 100644
--- a/build/context.cxx
+++ b/build/context.cxx
@@ -38,6 +38,10 @@ namespace build
scopes.clear ();
variable_pool.clear ();
+ // Enter builtin variables.
+ //
+ variable_pool.insert (variable ("subprojects", '='));
+
// Create global scope. For Win32 we use the empty path since there
// is no "real" root path. On POSIX, however, this is a real path.
// See the comment in <build/path-map> for details.
diff --git a/build/file.cxx b/build/file.cxx
index 3c4fc1c..b58d8e8 100644
--- a/build/file.cxx
+++ b/build/file.cxx
@@ -230,6 +230,52 @@ namespace build
using subprojects = map<string, dir_path>;
+ // Extract the project name from bootstrap.build.
+ //
+ static string
+ find_project_name (const dir_path& out_root,
+ const dir_path& fallback_src_root,
+ bool* src_hint = nullptr)
+ {
+ tracer trace ("find_project_name");
+
+ // Load the project name. If this subdirectory is the subproject's
+ // src_root, then we can get directly to that. Otherwise, we first
+ // have to discover its src_root.
+ //
+ const dir_path* src_root;
+ value_ptr src_root_vp; // Need it to live until the end.
+
+ if (src_hint != nullptr ? *src_hint : is_src_root (out_root))
+ src_root = &out_root;
+ else
+ {
+ path f (out_root / src_root_file);
+
+ if (!fallback_src_root.empty () && !file_exists (f))
+ src_root = &fallback_src_root;
+ else
+ {
+ src_root_vp = extract_variable (f, "src_root");
+ value_proxy v (&src_root_vp, nullptr); // Read-only.
+ src_root = &v.as<const dir_path&> ();
+ level4 ([&]{trace << "extracted src_root " << *src_root << " for "
+ << out_root;});
+ }
+ }
+
+ string name;
+ {
+ value_ptr vp (extract_variable (*src_root / bootstrap_file, "project"));
+ value_proxy v (&vp, nullptr); // Read-only.
+ name = move (v.as<string&> ());
+ }
+
+ level4 ([&]{trace << "extracted project name " << name << " for "
+ << *src_root;});
+ return name;
+ }
+
// Scan the specified directory for any subprojects. If a subdirectory
// is a subproject, then enter it into the map, handling the duplicates.
// Otherwise, scan the subdirectory recursively.
@@ -261,30 +307,10 @@ namespace build
dir_path dir (sd.leaf (root));
level4 ([&]{trace << "subproject " << sd << " as " << dir;});
- // Load the project name. If this subdirectory is the subproject's
- // src_root, then we can get directly to that. Otherwise, we first
- // have to discover its src_root.
+ // Load its name. Note that here we don't use fallback src_root
+ // since this function is used to scan both out_root and src_root.
//
- dir_path src_sd;
- if (src)
- src_sd = move (sd);
- else
- {
- value_ptr vp (extract_variable (sd / src_root_file, "src_root"));
- value_proxy v (&vp, nullptr); // Read-only.
- src_sd = move (v.as<dir_path&> ());
- level4 ([&]{trace << "extracted src_root " << src_sd << " for "
- << sd;});
- }
-
- string name;
- {
- value_ptr vp (extract_variable (src_sd / bootstrap_file, "project"));
- value_proxy v (&vp, nullptr); // Read-only.
- name = move (v.as<string&> ());
- level4 ([&]{trace << "extracted project name " << name << " for "
- << src_sd;});
- }
+ string name (find_project_name (sd, dir_path (), &src));
// @@ Can't use move() because we may need the values in diagnostics
// below. Looks like C++17 try_emplace() is what we need.
@@ -440,7 +466,11 @@ namespace build
{
list_value_ptr vp (new list_value);
for (auto& p: sps)
+ {
+ vp->emplace_back (p.first);
+ vp->back ().pair = '=';
vp->emplace_back (move (p.second));
+ }
val = move (vp);
}
}
@@ -457,8 +487,23 @@ namespace build
//
list_value& lv (val.as<list_value&> ());
- for (name& n: lv)
+ for (auto i (lv.begin ()); i != lv.end (); ++i)
{
+ bool p (i->pair != '\0');
+
+ if (p)
+ {
+ // Project name.
+ //
+ if (!i->simple () || i->empty ())
+ fail << "expected project name instead of '" << *i << "' in "
+ << "the subprojects variable";
+
+ ++i; // Got to have the second half of the pair.
+ }
+
+ name& n (*i);
+
if (n.simple ())
{
n.dir = dir_path (move (n.value));
@@ -468,6 +513,20 @@ namespace build
if (!n.directory ())
fail << "expected directory instead of '" << n << "' in the "
<< "subprojects variable";
+
+ // Figure out the project name if the user didn't specify one.
+ //
+ if (!p)
+ {
+ // Pass fallback src_root since this is a subproject that
+ // was specified by the user so it is most likely in our
+ // src.
+ //
+ i = lv.emplace (i, find_project_name (out_root / n.dir,
+ src_root / n.dir));
+ i->pair = '=';
+ ++i;
+ }
}
}
}
@@ -529,11 +588,8 @@ namespace build
{
for (const name& n: v.as<const list_value&> ())
{
- // Should be a list of directories.
- //
- if (!n.directory ())
- fail << "expected directory in subprojects variable "
- << "instead of " << n;
+ if (n.pair != '\0')
+ continue; // Skip project names.
dir_path out_root (root.path () / n.dir);
diff --git a/build/name b/build/name
index 4a86950..fdfe083 100644
--- a/build/name
+++ b/build/name
@@ -23,8 +23,8 @@ namespace build
// without a type and directory can be used to represent any text.
// A name with directory and empty value represents a directory.
//
- // If pair is true, then this name and the next in the list form
- // a pair.
+ // If pair is not '\0', then this name and the next in the list
+ // form a pair.
//
struct name
{
diff --git a/build/variable b/build/variable
index 10e6247..2bb3393 100644
--- a/build/variable
+++ b/build/variable
@@ -35,10 +35,10 @@ namespace build
struct variable
{
explicit
- variable (std::string n): name (std::move (n)) {}
+ variable (std::string n, char p = '\0'): name (std::move (n)), pairs (p) {}
std::string name;
- char pairs = '\0';
+ char pairs;
//const value_type* type = nullptr; // If NULL, then no fixed type.
};
@@ -253,6 +253,9 @@ namespace build
//
const variable&
find (std::string name) {return *emplace (std::move (name)).first;}
+
+ const variable&
+ insert (variable v) {return *emplace (std::move (v)).first;}
};
extern variable_set variable_pool;
diff --git a/tests/amalgam/config/buildfile b/tests/amalgam/config/buildfile
index 7132877..e9fc7f4 100644
--- a/tests/amalgam/config/buildfile
+++ b/tests/amalgam/config/buildfile
@@ -1,3 +1,3 @@
-d = #1/ 2/
+d = 1/ 2/
.: $d
include $d