diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2015-07-13 10:01:36 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2015-07-13 10:01:36 +0200 |
commit | bef7c36a3479b9b83eaf4be9ef090b21d6468f12 (patch) | |
tree | 15a827bd6175a558dc0924b933cf3a6f9f0f9d88 | |
parent | 4208f2d755f2bd2215051390f6500ccf54f1858f (diff) |
Make subprojects list of name=subdir pairs
-rw-r--r-- | build/b.cxx | 7 | ||||
-rw-r--r-- | build/config/operation.cxx | 6 | ||||
-rw-r--r-- | build/context.cxx | 4 | ||||
-rw-r--r-- | build/file.cxx | 114 | ||||
-rw-r--r-- | build/name | 4 | ||||
-rw-r--r-- | build/variable | 7 | ||||
-rw-r--r-- | tests/amalgam/config/buildfile | 2 |
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); @@ -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 |