diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2015-07-08 14:40:15 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2015-07-08 14:40:15 +0200 |
commit | 650d61845b3f61e9596a8a2dc97458998ba26013 (patch) | |
tree | b0ce0b66bfd053ffb38849589404957cde0f12dc /build | |
parent | 402bb6e6b297614226c4f848ebdb13fd49a95d76 (diff) |
Implement automatic amalgamation discovery
Diffstat (limited to 'build')
-rw-r--r-- | build/b.cxx | 38 | ||||
-rw-r--r-- | build/bin/module.cxx | 8 | ||||
-rw-r--r-- | build/config/operation.cxx | 23 | ||||
-rw-r--r-- | build/file | 17 | ||||
-rw-r--r-- | build/file.cxx | 121 | ||||
-rw-r--r-- | build/scope | 10 | ||||
-rw-r--r-- | build/target | 10 | ||||
-rw-r--r-- | build/variable | 15 | ||||
-rw-r--r-- | build/variable.ixx | 5 |
9 files changed, 165 insertions, 82 deletions
diff --git a/build/b.cxx b/build/b.cxx index 0291729..1650a73 100644 --- a/build/b.cxx +++ b/build/b.cxx @@ -40,42 +40,6 @@ using namespace std; -namespace build -{ - // Given an src_base directory, look for the project's src_root - // based on the presence of known special files. Return empty - // path if not found. - // - dir_path - find_src_root (const dir_path& b) - { - for (dir_path d (b); !d.root () && d != home; d = d.directory ()) - { - if (is_src_root (d)) - return d; - } - - return dir_path (); - } - - // The same but for out. Note that we also check whether a - // directory happens to be src_root, in case this is an in- - // tree build. - // - dir_path - find_out_root (const dir_path& b, bool& src) - { - for (dir_path d (b); !d.root () && d != home; d = d.directory ()) - { - if ((src = is_src_root (d)) || is_out_root (d)) - return d; - } - - src = false; - return dir_path (); - } -} - #include <build/config/module> #include <build/bin/module> #include <build/cxx/module> @@ -359,7 +323,7 @@ main (int argc, char* argv[]) // If no src_base was explicitly specified, search for out_root. // bool src; - out_root = find_out_root (out_base, src); + out_root = find_out_root (out_base, &src); // If not found (i.e., we have no idea where the roots are), // then this can mean two things: an in-tree build of a diff --git a/build/bin/module.cxx b/build/bin/module.cxx index b2374ff..ab1c1f5 100644 --- a/build/bin/module.cxx +++ b/build/bin/module.cxx @@ -82,7 +82,7 @@ namespace build // config.bin.lib // { - auto v (base.vars.assign ("bin.lib")); + auto v (base.assign ("bin.lib")); if (!v) v = required (root, "config.bin.lib", "shared").first; } @@ -90,7 +90,7 @@ namespace build // config.bin.exe.lib // { - auto v (base.vars.assign ("bin.exe.lib")); + auto v (base.assign ("bin.exe.lib")); if (!v) v = required (root, "config.bin.exe.lib", exe_lib).first; } @@ -98,7 +98,7 @@ namespace build // config.bin.liba.lib // { - auto v (base.vars.assign ("bin.liba.lib")); + auto v (base.assign ("bin.liba.lib")); if (!v) v = required (root, "config.bin.liba.lib", liba_lib).first; } @@ -106,7 +106,7 @@ namespace build // config.bin.libso.lib // { - auto v (base.vars.assign ("bin.libso.lib")); + auto v (base.assign ("bin.libso.lib")); if (!v) v = required (root, "config.bin.libso.lib", libso_lib).first; } diff --git a/build/config/operation.cxx b/build/config/operation.cxx index e6c258c..300dd22 100644 --- a/build/config/operation.cxx +++ b/build/config/operation.cxx @@ -85,9 +85,10 @@ namespace build << "# feel free to edit." << endl << "#" << endl; - if (auto v = root.vars["amalgamation"]) + auto av = root.vars["amalgamation"]; + if (av && !av.empty ()) { - const dir_path& d (v.as<const dir_path&> ()); + const dir_path& d (av.as<const dir_path&> ()); ofs << "# Base configuration inherited from " << d << endl << "#" << endl; @@ -276,20 +277,20 @@ namespace build // Create and bootstrap subproject's root scope. // dir_path out_nroot (out_root / n.dir); - dir_path src_nroot (src_root / n.dir); - scope& nroot (create_root (out_nroot, src_nroot)); + // The same logic to src_root as in create_bootstrap_inner(). + // + scope& nroot (create_root (out_nroot, dir_path ())); bootstrap_out (nroot); - // Check if the bootstrap process changed src_root. - // - const dir_path& p (nroot.vars["src_root"].as<const dir_path&> ()); + auto val (nroot.assign ("src_root")); - if (src_nroot != p) - fail << "bootstrapped src_root " << p << " does not match " - << "subproject " << src_nroot; + if (!val) + val = is_src_root (out_nroot) + ? out_nroot + : (src_root / n.dir); - nroot.src_path_ = &p; + nroot.src_path_ = &val.as<const dir_path&> (); bootstrap_src (nroot); @@ -19,6 +19,21 @@ namespace build bool is_out_root (const dir_path&); + // Given an src_base directory, look for a project's src_root + // based on the presence of known special files. Return empty + // path if not found. + // + dir_path + find_src_root (const dir_path&); + + // The same as above but for project's out. Note that we also + // check whether a directory happens to be src_root, in case + // this is an in-tree build. The second argument is the out + // flag that is set to true if this is src_root. + // + dir_path + find_out_root (const dir_path&, bool* src = nullptr); + void source (const path& buildfile, scope& root, scope& base); @@ -45,7 +60,7 @@ namespace build bootstrap_out (scope& root); // Bootstrap the project's root scope, the src part. Return true if - // we loaded anything. + // we loaded anything (which confirms the src_root is not bogus). // bool bootstrap_src (scope& root); diff --git a/build/file.cxx b/build/file.cxx index 948b6ce..e65d775 100644 --- a/build/file.cxx +++ b/build/file.cxx @@ -31,6 +31,36 @@ namespace build return file_exists (d / path ("build/bootstrap/src-root.build")); } + dir_path + find_src_root (const dir_path& b) + { + for (dir_path d (b); !d.root () && d != home; d = d.directory ()) + { + if (is_src_root (d)) + return d; + } + + return dir_path (); + } + + dir_path + find_out_root (const dir_path& b, bool* src) + { + for (dir_path d (b); !d.root () && d != home; d = d.directory ()) + { + bool s (false); + if ((s = is_src_root (d)) || is_out_root (d)) // Order is important! + { + if (src != nullptr) + *src = s; + + return d; + } + } + + return dir_path (); + } + void source (const path& bf, scope& root, scope& base) { @@ -147,18 +177,91 @@ namespace build { tracer trace ("bootstrap_src"); + bool r (false); + path bf (root.src_path () / path ("build/bootstrap.build")); - if (!file_exists (bf)) - return false; + if (file_exists (bf)) + { + // We assume that bootstrap out cannot load this file explicitly. It + // feels wrong to allow this since that makes the whole bootstrap + // process hard to reason about. But we may try to bootstrap the + // same root scope multiple time. + // + source_once (bf, root, root); + r = true; + } - // We assume that bootstrap out cannot load this file explicitly. It - // feels wrong to allow this since that makes the whole bootstrap - // process hard to reason about. But we may try to bootstrap the - // same root scope multiple time. + // See if we are a part of an amalgamation. There are two key + // players: the outer root scope which may already be present + // (i.e., we were loaded as part of an amalgamation) and the + // amalgamation variable that may or may not be set by the + // user (in bootstrap.build) or by an earlier call to this + // function for the same scope. When set by the user, the + // empty special value means that the project shall not be + // amalgamated. When calculated, the NULL value indicates + // that we are not amalgamated. // - source_once (bf, root, root); - return true; + { + auto rp (root.vars.assign("amalgamation")); // Set NULL by default. + auto& val (rp.first); + const dir_path& d (root.path ()); + + if (scope* aroot = root.parent_scope ()->root_scope ()) + { + const dir_path& ad (aroot->path ()); + dir_path rd (ad.relative (d)); + + // If we already have the amalgamation variable set, verify + // that aroot matches its value. + // + if (!rp.second) + { + if (val.null () || val.empty ()) + { + fail << d << " cannot be amalgamated" << + info << "amalgamated by " << ad; + } + else + { + const dir_path& vd (val.as<const dir_path&> ()); + + if (vd != rd) + { + fail << "inconsistent amalgamation of " << d << + info << "specified: " << vd << + info << "actual: " << rd << " by " << ad; + } + } + } + else + { + // Otherwise, use the outer root as our amalgamation. + // + level4 ([&]{trace << d << " amalgamated as " << rd;}); + val = move (rd); + } + } + else if (rp.second) + { + // If there is no outer root and the amalgamation variable + // hasn't been set, then we need to check if any of the + // outer directories is a project's out_root. If so, then + // that's our amalgamation. + // + const dir_path& d (root.path ()); + const dir_path& ad (find_out_root (d.directory ())); + + if (!ad.empty ()) + { + dir_path rd (ad.relative (d)); + level4 ([&]{trace << d << " amalgamated as " << rd;}); + val = move (rd); + } + } + } + + return r; } void @@ -166,7 +269,7 @@ namespace build { auto v (root.vars["amalgamation"]); - if (!v) + if (!v || v.empty ()) return; const dir_path& d (v.as<const dir_path&> ()); diff --git a/build/scope b/build/scope index d1cd941..817ee95 100644 --- a/build/scope +++ b/build/scope @@ -70,16 +70,10 @@ namespace build // returned. // value_proxy - assign (const variable& var) - { - return vars.assign (var); - } + assign (const variable& var) {return vars.assign (var).first;} value_proxy - assign (const std::string& name) - { - return assign (variable_pool.find (name)); - } + assign (const std::string& name) {return vars.assign (name).first;} // Return a value_proxy suitable for appending. If the variable // does not exist in this scope's map, then outer scopes are diff --git a/build/target b/build/target index 954604c..ba51f5e 100644 --- a/build/target +++ b/build/target @@ -254,16 +254,10 @@ namespace build // for details. // value_proxy - assign (const variable& var) - { - return vars.assign (var); - } + assign (const variable& var) {return vars.assign (var).first;} value_proxy - assign (const std::string& name) - { - return assign (variable_pool.find (name)); - } + assign (const std::string& name) {return vars.assign (name).first;} // Return a value_proxy suitable for appending. See class scope // for details. diff --git a/build/variable b/build/variable index 2164f92..064a10a 100644 --- a/build/variable +++ b/build/variable @@ -8,7 +8,7 @@ #include <string> #include <memory> // unique_ptr #include <cstddef> // nullptr_t -#include <utility> // move() +#include <utility> // move(), pair, make_pair() #include <cassert> #include <functional> // hash #include <typeindex> @@ -104,6 +104,9 @@ namespace build bool null () const {return *p == nullptr;} + bool + empty () const; + explicit operator bool () const {return defined () && !null ();} explicit operator value_ptr& () const {return *p;} @@ -267,13 +270,17 @@ namespace build return operator[] (variable_pool.find (name)); } - value_proxy + // The second member in the pair indicates whether new (NULL) + // value was set. + // + std::pair<value_proxy, bool> assign (const variable& var) { - return value_proxy (&variable_map_base::operator[] (var), this); + auto r (emplace (var, value_ptr ())); + return std::make_pair (value_proxy (&r.first->second, this), r.second); } - value_proxy + std::pair<value_proxy, bool> assign (const std::string& name) { return assign (variable_pool.find (name)); diff --git a/build/variable.ixx b/build/variable.ixx index b0ff021..b97815e 100644 --- a/build/variable.ixx +++ b/build/variable.ixx @@ -4,6 +4,11 @@ namespace build { + // value_proxy + // + inline bool value_proxy:: + empty () const {return as<const list_value&> ().empty ();} + inline const value_proxy& value_proxy:: operator= (value_ptr v) const { |