aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-07-08 14:40:15 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-07-08 14:40:15 +0200
commit650d61845b3f61e9596a8a2dc97458998ba26013 (patch)
treeb0ce0b66bfd053ffb38849589404957cde0f12dc
parent402bb6e6b297614226c4f848ebdb13fd49a95d76 (diff)
Implement automatic amalgamation discovery
-rw-r--r--build/b.cxx38
-rw-r--r--build/bin/module.cxx8
-rw-r--r--build/config/operation.cxx23
-rw-r--r--build/file17
-rw-r--r--build/file.cxx121
-rw-r--r--build/scope10
-rw-r--r--build/target10
-rw-r--r--build/variable15
-rw-r--r--build/variable.ixx5
-rw-r--r--tests/amalgam/config/build/bootstrap.build1
-rw-r--r--tests/amalgam/config/buildfile2
-rw-r--r--tests/amalgam/simple/build/bootstrap.build1
12 files changed, 167 insertions, 84 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);
diff --git a/build/file b/build/file
index 7ac4d4d..8e96f4a 100644
--- a/build/file
+++ b/build/file
@@ -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
{
diff --git a/tests/amalgam/config/build/bootstrap.build b/tests/amalgam/config/build/bootstrap.build
index 5951f06..5a01046 100644
--- a/tests/amalgam/config/build/bootstrap.build
+++ b/tests/amalgam/config/build/bootstrap.build
@@ -1,3 +1,4 @@
project = amalgam-config
+amalgamation = # Shall not be amalgamated.
subprojects = 1/ 2/
using config
diff --git a/tests/amalgam/config/buildfile b/tests/amalgam/config/buildfile
index e9fc7f4..7132877 100644
--- a/tests/amalgam/config/buildfile
+++ b/tests/amalgam/config/buildfile
@@ -1,3 +1,3 @@
-d = 1/ 2/
+d = #1/ 2/
.: $d
include $d
diff --git a/tests/amalgam/simple/build/bootstrap.build b/tests/amalgam/simple/build/bootstrap.build
index 8da7272..698a248 100644
--- a/tests/amalgam/simple/build/bootstrap.build
+++ b/tests/amalgam/simple/build/bootstrap.build
@@ -1,3 +1,2 @@
project = amalgam-simple
-amalgamation = ../
using config