aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2020-06-03 08:42:26 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2020-06-03 08:42:26 +0200
commit1cc657a1ae2d496c0467a7c33257aa3cd2bfc3a8 (patch)
tree062e0eada1230ef19b0f51b2e77c00f2dd49a266
parentbc3c8492f129d9295c9ef6c325bf2c99e88ca73e (diff)
Add versioning for ad hoc C++ recipes
This will allow us to deal with backward-incompatible changes to cxx_rule interface and semantics.
-rw-r--r--libbuild2/parser.cxx23
-rw-r--r--libbuild2/rule.cxx35
-rw-r--r--libbuild2/rule.hxx19
-rw-r--r--tests/dependency/recipe/testscript4
4 files changed, 60 insertions, 21 deletions
diff --git a/libbuild2/parser.cxx b/libbuild2/parser.cxx
index 65a42fe..dada34d 100644
--- a/libbuild2/parser.cxx
+++ b/libbuild2/parser.cxx
@@ -1048,7 +1048,7 @@ namespace build2
//
// % [<attrs>]
// [if|switch ...]
- // {{ [<lang>]
+ // {{ [<lang> ...]
// ...
// }}
//
@@ -1130,7 +1130,26 @@ namespace build2
{
// C++
//
- ar.reset (new adhoc_cxx_rule (loc, st.value.size ()));
+
+ // Parse recipe version.
+ //
+ if (tt == type::newline || tt == type::eos)
+ fail (t) << "expected c++ recipe version instead of " << t;
+
+ location nloc (get_location (t));
+ names ns (parse_names (t, tt, pattern_mode::ignore));
+
+ uint64_t v;
+ try
+ {
+ v = convert<uint64_t> (move (ns));
+ }
+ catch (const invalid_argument& e)
+ {
+ fail (nloc) << "invalid c++ recipe version value: " << e;
+ }
+
+ ar.reset (new adhoc_cxx_rule (loc, st.value.size (), v));
}
else
fail (lloc) << "unknown recipe language '" << *lang << "'";
diff --git a/libbuild2/rule.cxx b/libbuild2/rule.cxx
index 7f9c357..9e2ef95 100644
--- a/libbuild2/rule.cxx
+++ b/libbuild2/rule.cxx
@@ -759,9 +759,9 @@ namespace build2
return target_state::changed;
}
- // cxx_rule
+ // cxx_rule_v1
//
- bool cxx_rule::
+ bool cxx_rule_v1::
match (action, target&, const string&) const
{
return true;
@@ -770,6 +770,21 @@ namespace build2
// adhoc_cxx_rule
//
adhoc_cxx_rule::
+ adhoc_cxx_rule (const location& l, size_t b, uint64_t v)
+ : adhoc_rule (l, b), version (v), impl (nullptr)
+ {
+ if (v != 1)
+ fail (l) << "unsupported c++ recipe version " << v;
+ }
+
+ bool adhoc_cxx_rule::
+ recipe_text (context&, string&& t, attributes&)
+ {
+ code = move (t);
+ return true;
+ }
+
+ adhoc_cxx_rule::
~adhoc_cxx_rule ()
{
delete impl.load (memory_order_relaxed); // Serial execution.
@@ -781,7 +796,7 @@ namespace build2
// @@ TODO: indentation is multi-line recipes is off (would need to insert
// indentation after every newline).
//
- os << ind << string (braces, '{') << " c++" << endl
+ os << ind << string (braces, '{') << " c++ " << version << endl
<< ind << code
<< ind << string (braces, '}');
}
@@ -829,7 +844,7 @@ namespace build2
if ((impl = this->impl.load (memory_order_relaxed)) != nullptr)
break;
- using create_function = cxx_rule* (const location&, target_state);
+ using create_function = cxx_rule_v1* (const location&, target_state);
using load_function = create_function* ();
// The only way to guarantee that the name of our module matches its
@@ -945,7 +960,7 @@ namespace build2
? loc.file.path.string ()
: loc.file.name ? *loc.file.name : string ());
- const string psig ("# c++ 1");
+ const string psig ("# c++ " + to_string (version));
const string lsig ("// " + lf + ':' + to_string (loc.line));
// Check whether we need to (re)create the project.
@@ -994,6 +1009,8 @@ namespace build2
// Include every header that can plausibly be needed by a rule.
//
+ // @@ TMP: any new headers to add? [Keep this note for review.]
+ //
ofs << "#include <libbuild2/types.hxx>" << '\n'
<< "#include <libbuild2/forward.hxx>" << '\n'
<< "#include <libbuild2/utility.hxx>" << '\n'
@@ -1033,7 +1050,7 @@ namespace build2
//
ofs << "namespace" << '\n'
<< "{" << '\n'
- << "class rule: public cxx_rule" << '\n'
+ << "class rule: public cxx_rule_v1" << '\n'
<< "{" << '\n'
<< "public:" << '\n'
<< '\n';
@@ -1041,7 +1058,7 @@ namespace build2
// Inherit base constructor. This way the user may provide their own
// but don't have to.
//
- ofs << " using cxx_rule::cxx_rule;" << '\n'
+ ofs << " using cxx_rule_v1::cxx_rule_v1;" << '\n'
<< '\n';
// An extern "C" function cannot throw which can happen in case of a
@@ -1049,7 +1066,7 @@ namespace build2
// We incorporate id to make sure it doesn't conflict with anything
// user-defined.
//
- ofs << " static cxx_rule*" << '\n'
+ ofs << " static cxx_rule_v1*" << '\n'
<< " create_" << id << " (const location& l, target_state s)" << '\n'
<< " {" << '\n'
<< " return new rule (l, s);" << '\n'
@@ -1082,7 +1099,7 @@ namespace build2
<< "#ifdef _WIN32" << '\n'
<< "__declspec(dllexport)" << '\n'
<< "#endif" << '\n'
- << "cxx_rule* (*" << sym << " ()) (const location&, target_state)" << '\n'
+ << "cxx_rule_v1* (*" << sym << " ()) (const location&, target_state)" << '\n'
<< "{" << '\n'
<< " return &rule_" << id << "::create_" << id << ";" << '\n'
<< "}" << '\n'
diff --git a/libbuild2/rule.hxx b/libbuild2/rule.hxx
index 05be9eb..76ab306 100644
--- a/libbuild2/rule.hxx
+++ b/libbuild2/rule.hxx
@@ -209,6 +209,13 @@ namespace build2
//
class LIBBUILD2_SYMEXPORT cxx_rule: public rule
{
+ // For now this class is provided purely as an alias for rule in case the
+ // implementation (which is also called rule) needs to refer to something
+ // in its base.
+ };
+
+ class LIBBUILD2_SYMEXPORT cxx_rule_v1: public cxx_rule
+ {
public:
// A robust recipe may want to incorporate the recipe_state into its
// up-to-date decision as if the recipe library was a prerequisite (it
@@ -218,7 +225,7 @@ namespace build2
const location recipe_loc; // Buildfile location of the recipe.
const target_state recipe_state; // State of recipe library target.
- cxx_rule (const location& l, target_state s)
+ cxx_rule_v1 (const location& l, target_state s)
: recipe_loc (l), recipe_state (s) {}
// Return true by default.
@@ -241,15 +248,10 @@ namespace build2
virtual void
dump (ostream&, string&) const override;
- adhoc_cxx_rule (const location& l, size_t b)
- : adhoc_rule (l, b), impl (nullptr) {}
+ adhoc_cxx_rule (const location&, size_t, uint64_t version);
virtual bool
- recipe_text (context&, string&& t, attributes&) override
- {
- code = move (t);
- return true;
- }
+ recipe_text (context&, string&& t, attributes&) override;
virtual
~adhoc_cxx_rule () override;
@@ -258,6 +260,7 @@ namespace build2
// Note that this recipe (rule instance) can be shared between multiple
// targets which could all be matched in parallel.
//
+ uint64_t version;
string code;
mutable atomic<cxx_rule*> impl;
};
diff --git a/tests/dependency/recipe/testscript b/tests/dependency/recipe/testscript
index 5510e3c..c5e4a8c 100644
--- a/tests/dependency/recipe/testscript
+++ b/tests/dependency/recipe/testscript
@@ -76,14 +76,14 @@ EOE
:
$* <<EOI 2>>/~%EOE%
alias{x}:
-{{ c++
+{{ c++ 1
void f ();
}}
dump alias{x}
EOI
<stdin>:5:1: dump:
% .+/alias\{x\}:%
- {{ c++
+ {{ c++ 1
void f ();
}}
EOE