From edbb2e3156714887b2334e5b6748f463e2d35ba3 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 1 Jun 2020 09:15:11 +0200 Subject: Extend target metadata to include variable prefix, stable name --- libbuild2/context.cxx | 4 +- libbuild2/context.hxx | 28 ++++++++++++-- libbuild2/file.cxx | 102 ++++++++++++++++++++++++++++++++++++------------- libbuild2/variable.cxx | 3 ++ 4 files changed, 106 insertions(+), 31 deletions(-) diff --git a/libbuild2/context.cxx b/libbuild2/context.cxx index a3455ea..202cd35 100644 --- a/libbuild2/context.cxx +++ b/libbuild2/context.cxx @@ -540,7 +540,7 @@ namespace build2 // var_project = &vp.insert ("project"); var_amalgamation = &vp.insert ("amalgamation"); - var_subprojects = &vp.insert ("subprojects"); + var_subprojects = &vp.insert ("subprojects"); // Untyped. var_version = &vp.insert ("version"); var_project_url = &vp.insert ("project.url"); @@ -549,7 +549,7 @@ namespace build2 var_import_target = &vp.insert ("import.target"); var_import_metadata = &vp.insert ("import.metadata"); - var_export_metadata = &vp.insert ("export.metadata", v_t); + var_export_metadata = &vp.insert ("export.metadata", v_t); // Untyped. var_extension = &vp.insert ("extension", v_t); var_clean = &vp.insert ("clean", v_t); diff --git a/libbuild2/context.hxx b/libbuild2/context.hxx index 2a9c93e..5f6e810 100644 --- a/libbuild2/context.hxx +++ b/libbuild2/context.hxx @@ -348,14 +348,36 @@ namespace build2 // const variable* var_project_summary; - // import.* + // import.* and export.* // const variable* var_import_build2; const variable* var_import_target; - const variable* var_import_metadata; - // export.* + // The import.metadata variable and the --build2-metadata option are used + // to pass the metadata compatibility version. + // + // This serves both as an indication that the metadata is required (can be + // useful, for example, in cases where it is expensive to calculate) as + // well as the maximum version we recognize. The exporter may return it in + // any version up to and including this maximum. And it may return it even + // if not requested (but only in version 1). The exporter should also set + // the returned version as the target-specific export.metadata variable. + // + // The export.metadata value should start with the version optionally + // followed by the metadata variable prefix (for example, cli in + // cli.version). If the variable prefix is missing, it is assumed to be + // the target name as imported. + // + // The following metadata variable names have pre-defined meaning: // + // .name = [string] # Stable name for diagnostics. + // .version = [string] # Version for diagnostics. + // .checksum = [string] # Checksum for change tracking. + // + // If the .name variable is missing, it is set to the target + // name as imported. + // + const variable* var_import_metadata; const variable* var_export_metadata; // [string] target visibility diff --git a/libbuild2/file.cxx b/libbuild2/file.cxx index 571980e..bf97ea7 100644 --- a/libbuild2/file.cxx +++ b/libbuild2/file.cxx @@ -2173,13 +2173,6 @@ namespace build2 // Pass the metadata compatibility version in import.metadata. // - // This serves both as an indication that the metadata is required (can be - // useful, for example, in cases where it is expensive to calculate) as - // well as the maximum version we recognize. The exporter may return it in - // any version up to and including this maximum. And it may return it even - // if not requested (but only in version 1). The exporter should also set - // the returned version as the target-specific export.metadata variable. - // if (meta) ts.assign (ctx.var_import_metadata) = uint64_t (1); @@ -2456,7 +2449,7 @@ namespace build2 names ns; import_kind k; - const target* t (nullptr); + const target* pt (nullptr); pair> r ( import_search (new_value, @@ -2477,7 +2470,7 @@ namespace build2 if (r.first.empty ()) { assert (opt); - return make_pair (t, k); // NULL + return make_pair (pt, k); // NULL } else if (r.first.qualified ()) { @@ -2488,16 +2481,16 @@ namespace build2 // This is tricky: we only want the optional semantics for the // fallback case. // - t = import (ctx, - base.find_prerequisite_key (ns, loc), - opt && !r.second, - meta, - false /* existing */, - loc); + pt = import (ctx, + base.find_prerequisite_key (ns, loc), + opt && !r.second, + meta, + false /* existing */, + loc); } - if (t == nullptr) - return make_pair (t, k); // NULL + if (pt == nullptr) + return make_pair (pt, k); // NULL // Otherwise fall through. } @@ -2510,29 +2503,86 @@ namespace build2 ns = import_load (base.ctx, move (r), metadata, loc).first; } - if (t == nullptr) + if (pt == nullptr) { // Similar logic to perform's search(). // target_key tk (base.find_target_key (ns, loc)); - t = ctx.targets.find (tk, trace); - if (t == nullptr) + pt = ctx.targets.find (tk, trace); + if (pt == nullptr) fail (loc) << "unknown imported target " << tk; } + target& t (pt->rw ()); // Load phase. + if (meta) { - if (auto* v = cast_null (t->vars[ctx.var_export_metadata])) + // The export.metadata value should start with the version optionally + // followed by the metadata variable prefix. If the variable prefix is + // missing, set it to the metadata key (i.e., target name as imported) + // by default. + // + value& v (t.assign (*ctx.var_export_metadata)); + if (v && !v.empty ()) { - if (*v != 1) - fail (loc) << "unexpected metadata version " << *v - << " in imported target " << *t; + names& ns (cast (v)); + + // First verify the version. + // + uint64_t ver; + try + { + // Note: does not change the passed name. + // + ver = value_traits::convert ( + move (ns[0]), ns[0].pair ? &ns[1] : nullptr); + } + catch (const invalid_argument& e) + { + fail (loc) << "invalid metadata version in imported target " << t + << ": " << e; + } + + if (ver != 1) + fail (loc) << "unexpected metadata version " << ver + << " in imported target " << t; + + // Next see if we have the metadata variable prefix. + // + switch (ns.size ()) + { + case 1: + { + ns.push_back (name (*meta)); + break; + } + case 2: + { + if (ns[1].simple ()) + break; + } + // Fall through. + default: + { + fail (loc) << "invalid metadata variable prefix in imported " + << "target " << t; + } + } + + // See if we have the stable program name in the .name + // variable. If its missing, set it to the metadata key (i.e., target + // name as imported) by default. + // + auto& vp (ctx.var_pool.rw ()); // Load phase. + value& nv (t.assign (vp.insert (ns[1].value + ".name"))); + if (!nv) + nv = *meta; } else - fail (loc) << "no metadata for imported target " << *t; + fail (loc) << "no metadata for imported target " << t; } - return make_pair (t, k); + return make_pair (pt, k); } ostream& diff --git a/libbuild2/variable.cxx b/libbuild2/variable.cxx index 206eb54..14803cb 100644 --- a/libbuild2/variable.cxx +++ b/libbuild2/variable.cxx @@ -485,6 +485,9 @@ namespace build2 uint64_t value_traits:: convert (name&& n, name* r) { + // Note: in some places we reply on this function not + // changing the passed name. + // if (r == nullptr && n.simple ()) { try -- cgit v1.1