aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2016-08-30 09:51:03 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2016-08-30 10:00:35 +0200
commitf89d2c16c1dad9b8d2f3b0e402a47e30521f5a69 (patch)
tree10fe158dd8ca79c89ede9d21bdbfc57104c65d57
parent83d5e6063f670134303a3396219f63eaac0aedff (diff)
Add support for config.build file versioning
-rw-r--r--build2/b.cxx16
-rw-r--r--build2/config/init.cxx43
-rw-r--r--build2/config/module2
-rw-r--r--build2/config/operation.cxx10
-rw-r--r--build2/context25
-rw-r--r--build2/context.cxx5
-rw-r--r--build2/dist/operation.cxx14
-rw-r--r--build2/file8
-rw-r--r--build2/file.cxx31
9 files changed, 116 insertions, 38 deletions
diff --git a/build2/b.cxx b/build2/b.cxx
index bb4f0fe..6d6723a 100644
--- a/build2/b.cxx
+++ b/build2/b.cxx
@@ -297,6 +297,7 @@ main (int argc, char* argv[])
{
vector_view<opspec> opspecs;
const string& mname (lifted == nullptr ? mit->name : lifted->name);
+ current_mname = &mname;
if (lifted == nullptr)
{
@@ -345,6 +346,7 @@ main (int argc, char* argv[])
// A lifted meta-operation will always have default operation.
//
const string& oname (lifted == nullptr ? os.name : string ());
+ current_oname = &oname;
if (lifted != nullptr)
lifted = nullptr; // Clear for the next iteration.
@@ -719,7 +721,7 @@ main (int argc, char* argv[])
if (mif->meta_operation_pre != nullptr)
mif->meta_operation_pre ();
- current_mif = mif;
+ set_current_mif (*mif);
dirty = true;
}
//
@@ -973,9 +975,7 @@ main (int argc, char* argv[])
if (mif->operation_pre != nullptr)
mif->operation_pre (pre_oid); // Cannot be translated.
- current_inner_oif = pre_oif;
- current_outer_oif = oif;
- current_mode = pre_oif->mode;
+ set_current_oif (*pre_oif, oif);
dependency_count = 0;
action a (mid, pre_oid, oid);
@@ -990,9 +990,7 @@ main (int argc, char* argv[])
<< ", id " << static_cast<uint16_t> (pre_oid);});
}
- current_inner_oif = oif;
- current_outer_oif = nullptr;
- current_mode = oif->mode;
+ set_current_oif (*oif);
dependency_count = 0;
action a (mid, oid, 0);
@@ -1008,9 +1006,7 @@ main (int argc, char* argv[])
if (mif->operation_pre != nullptr)
mif->operation_pre (post_oid); // Cannot be translated.
- current_inner_oif = post_oif;
- current_outer_oif = oif;
- current_mode = post_oif->mode;
+ set_current_oif (*post_oif, oif);
dependency_count = 0;
action a (mid, post_oid, oid);
diff --git a/build2/config/init.cxx b/build2/config/init.cxx
index 6c713df..368b9d0 100644
--- a/build2/config/init.cxx
+++ b/build2/config/init.cxx
@@ -23,9 +23,10 @@ namespace build2
namespace config
{
const string module::name ("config");
+ const uint64_t module::version;
void
- boot (scope& rs, const location&, unique_ptr<module_base>&)
+ boot (scope& rs, const location& loc, unique_ptr<module_base>&)
{
tracer trace ("config::boot");
@@ -44,10 +45,44 @@ namespace build2
// possible that some module which needs the configuration will get
// called first.
//
- path f (out_root / config_file);
+ const variable& c_v (var_pool.insert<uint64_t> ("config.version"));
- if (file_exists (f))
- source (f, rs, rs);
+ // Don't load it if we are disfiguring. This is a bit tricky since the
+ // build2 core may not yet know it is disfiguring. But we know.
+ //
+ if (*current_mname != disfigure.name &&
+ (!current_mname->empty () || *current_oname != disfigure.name))
+ {
+ path f (out_root / config_file);
+
+ if (file_exists (f))
+ {
+ // Check the config version. We assume that old versions cannot
+ // understand new configs and new versions are incompatible with old
+ // configs.
+ //
+ // We extract the value manually instead of loading and then
+ // checking in order to be able to fixup/migrate the file which we
+ // may want to do in the future.
+ //
+ {
+ // Assume missing version is 0.
+ //
+ auto p (extract_variable (f, c_v.name.c_str ()));
+ uint64_t v (p.second ? cast<uint64_t> (p.first) : 0);
+
+ if (v != module::version)
+ fail (loc) << "incompatible config file " << f <<
+ info << "config file version " << v
+ << (p.second ? "" : " (missing)") <<
+ info << "config module version " << module::version <<
+ info << "consider reconfiguring " << project (rs) << '@'
+ << out_root;
+ }
+
+ source (f, rs, rs);
+ }
+ }
}
bool
diff --git a/build2/config/module b/build2/config/module
index e6fb197..8f9a9b9 100644
--- a/build2/config/module
+++ b/build2/config/module
@@ -78,7 +78,9 @@ namespace build2
struct module: module_base
{
config::saved_modules saved_modules;
+
static const string name; // init.cxx
+ static constexpr const uint64_t version = 1;
};
}
}
diff --git a/build2/config/operation.cxx b/build2/config/operation.cxx
index 90c2bbb..e6ab14a 100644
--- a/build2/config/operation.cxx
+++ b/build2/config/operation.cxx
@@ -80,6 +80,8 @@ namespace build2
"free to edit." << endl
<< "#" << endl;
+ ofs << "config.version = " << module::version << endl;
+
if (auto l = root.vars["amalgamation"])
{
const dir_path& d (cast<dir_path> (l));
@@ -371,13 +373,11 @@ namespace build2
id < rs->operations.size ();
++id)
{
- const operation_info* oi (rs->operations[id]);
- if (oi == nullptr)
+ const operation_info* oif (rs->operations[id]);
+ if (oif == nullptr)
continue;
- current_inner_oif = oi;
- current_outer_oif = nullptr;
- current_mode = oi->mode;
+ set_current_oif (*oif);
dependency_count = 0;
match (action (configure_id, id), t);
diff --git a/build2/context b/build2/context
index e7b8c7d..257e96b 100644
--- a/build2/context
+++ b/build2/context
@@ -26,12 +26,35 @@ namespace build2
// Current action (meta/operation).
//
+ // The names unlike info are available during boot but may not yet be
+ // lifted. The name is always for an outer operation (or meta operation
+ // that hasn't been recognized as such yet).
+ //
+ extern const string* current_mname;
+ extern const string* current_oname;
+
extern const meta_operation_info* current_mif;
extern const operation_info* current_inner_oif;
extern const operation_info* current_outer_oif;
-
extern execution_mode current_mode;
+ inline void
+ set_current_mif (const meta_operation_info& mif)
+ {
+ current_mif = &mif;
+ current_mname = &mif.name;
+ }
+
+ inline void
+ set_current_oif (const operation_info& inner_oif,
+ const operation_info* outer_oif = nullptr)
+ {
+ current_inner_oif = &inner_oif;
+ current_outer_oif = outer_oif;
+ current_oname = &(outer_oif == nullptr ? inner_oif : *outer_oif).name;
+ current_mode = inner_oif.mode;
+ }
+
// Total number of dependency relationships in the current action.
// Together with the target::dependents count it is incremented
// during the rule search & match phase and is decremented during
diff --git a/build2/context.cxx b/build2/context.cxx
index ac972ac..0e05926 100644
--- a/build2/context.cxx
+++ b/build2/context.cxx
@@ -32,10 +32,15 @@ namespace build2
string_pool extension_pool;
string_pool project_name_pool;
+ const string* current_mname;
+ const string* current_oname;
+
const meta_operation_info* current_mif;
const operation_info* current_inner_oif;
const operation_info* current_outer_oif;
+
execution_mode current_mode;
+
uint64_t dependency_count;
variable_overrides
diff --git a/build2/dist/operation.cxx b/build2/dist/operation.cxx
index d03fe28..12bcc61 100644
--- a/build2/dist/operation.cxx
+++ b/build2/dist/operation.cxx
@@ -101,17 +101,15 @@ namespace build2
id < rs->operations.size ();
++id)
{
- const operation_info* oi (rs->operations[id]);
- if (oi == nullptr)
+ const operation_info* oif (rs->operations[id]);
+ if (oif == nullptr)
continue;
// Note that we are not calling operation_pre/post() callbacks
// here since the meta operation is dist and we know what we
// are doing.
//
- current_inner_oif = oi;
- current_outer_oif = nullptr;
- current_mode = oi->mode;
+ set_current_oif (*oif);
dependency_count = 0;
action a (dist_id, id);
@@ -237,14 +235,12 @@ namespace build2
if (perform.meta_operation_pre != nullptr)
perform.meta_operation_pre ();
- current_mif = &perform;
+ set_current_mif (perform);
if (perform.operation_pre != nullptr)
perform.operation_pre (update_id);
- current_inner_oif = &update;
- current_outer_oif = nullptr;
- current_mode = update.mode;
+ set_current_oif (update);
dependency_count = 0;
action a (perform_id, update_id);
diff --git a/build2/file b/build2/file
index f5dac83..1502d73 100644
--- a/build2/file
+++ b/build2/file
@@ -129,6 +129,14 @@ namespace build2
void
load_root_pre (scope& root);
+ // Extract the specified variable value from a buildfile. It is expected to
+ // be the first non-comment line and not to rely on any variable expansion
+ // other than those from the global scope or any variable overrides. Return
+ // an indication of whether the variable was found.
+ //
+ pair<value, bool>
+ extract_variable (const path&, const char* var);
+
// Import has two phases: the first is triggered by the import
// directive in the buildfile. It will try to find and load the
// project. Failed that, it will return the project-qualified
diff --git a/build2/file.cxx b/build2/file.cxx
index d267fec..46362e1 100644
--- a/build2/file.cxx
+++ b/build2/file.cxx
@@ -272,7 +272,7 @@ namespace build2
// be the first non-comment line and not to rely on any variable expansion
// other than those from the global scope or any variable overrides.
//
- static value
+ pair<value, bool>
extract_variable (const path& bf, const char* name)
{
try
@@ -288,8 +288,7 @@ namespace build2
tt != token_type::prepend &&
tt != token_type::append))
{
- error << "variable '" << name << "' expected as first line in " << bf;
- throw failed (); // Suppress "used uninitialized" warning.
+ return make_pair (value (), false);
}
const variable& var (var_pool.find (move (t.value)));
@@ -300,14 +299,18 @@ namespace build2
value* v (tmp.vars.find (var));
assert (v != nullptr);
- return move (*v); // Steal the value, the scope is going away.
+
+ // Steal the value, the scope is going away.
+ //
+ return make_pair (move (*v), true);
}
catch (const ifdstream::failure& e)
{
- fail << "unable to read buildfile " << bf << ": " << e.what ();
+ error << "unable to read buildfile " << bf << ": " << e.what ();
+ throw failed ();
}
- return value (); // Never reaches.
+ // Never reached.
}
// Extract the project name from bootstrap.build.
@@ -336,7 +339,12 @@ namespace build2
src_root = &fallback_src_root;
else
{
- src_root_v = extract_variable (f, "src_root");
+ auto p (extract_variable (f, "src_root"));
+
+ if (!p.second)
+ error << "variable 'src_root' expected as first line in " << f;
+
+ src_root_v = move (p.first);
src_root = &cast<dir_path> (src_root_v);
l5 ([&]{trace << "extracted src_root " << *src_root << " for "
<< out_root;});
@@ -345,8 +353,13 @@ namespace build2
string name;
{
- value v (extract_variable (*src_root / bootstrap_file, "project"));
- name = cast<string> (move (v));
+ path f (*src_root / bootstrap_file);
+ auto p (extract_variable (f, "project"));
+
+ if (!p.second)
+ error << "variable 'project' expected as first line in " << f;
+
+ name = cast<string> (move (p.first));
}
l5 ([&]{trace << "extracted project name '" << name << "' for "