From a3ed04f37c47e2eaa83d87dda2ec4ab060a7a2d0 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 2 Jun 2020 07:35:44 +0200 Subject: Add process_path_ex with program stable name and checksum --- libbuild2/bin/init.cxx | 30 ++--- libbuild2/c/init.cxx | 8 +- libbuild2/cc/module.cxx | 2 +- libbuild2/context.hxx | 2 + libbuild2/cxx/init.cxx | 8 +- libbuild2/functions-process-path.cxx | 23 ++-- libbuild2/types.hxx | 24 ++++ libbuild2/variable.cxx | 222 +++++++++++++++++++++++++++++++---- libbuild2/variable.hxx | 24 +++- libbuild2/variable.ixx | 20 +++- 10 files changed, 305 insertions(+), 58 deletions(-) diff --git a/libbuild2/bin/init.cxx b/libbuild2/bin/init.cxx index 4af3c1d..a1ac61e 100644 --- a/libbuild2/bin/init.cxx +++ b/libbuild2/bin/init.cxx @@ -574,11 +574,8 @@ namespace build2 { auto& vp (rs.var_pool ()); - vp.insert ("bin.ar.path"); - vp.insert ("bin.ranlib.path"); - - vp.insert ("config.bin.ar"); - vp.insert ("config.bin.ranlib"); + vp.insert ("config.bin.ar"); + vp.insert ("config.bin.ranlib"); } // Configuration. @@ -672,7 +669,8 @@ namespace build2 } } - rs.assign ("bin.ar.path") = move (ari.ar_path); + rs.assign ("bin.ar.path") = + process_path_ex (move (ari.ar_path), "ar", ari.ar_checksum); rs.assign ("bin.ar.id") = move (ari.ar_id); rs.assign ("bin.ar.signature") = move (ari.ar_signature); rs.assign ("bin.ar.checksum") = move (ari.ar_checksum); @@ -689,8 +687,12 @@ namespace build2 if (ranlib != nullptr) { - rs.assign ("bin.ranlib.path") = move (ari.ranlib_path); - rs.assign ("bin.ranlib.id") = move (ari.ranlib_id); + rs.assign ("bin.ranlib.path") = + process_path_ex (move (ari.ranlib_path), + "ranlib", + ari.ranlib_checksum); + rs.assign ("bin.ranlib.id") = + move (ari.ranlib_id); rs.assign ("bin.ranlib.signature") = move (ari.ranlib_signature); rs.assign ("bin.ranlib.checksum") = @@ -741,8 +743,7 @@ namespace build2 { auto& vp (rs.var_pool ()); - vp.insert ("bin.ld.path"); - vp.insert ("config.bin.ld"); + vp.insert ("config.bin.ld"); } // Configuration. @@ -804,7 +805,8 @@ namespace build2 << " checksum " << ldi.checksum; } - rs.assign ("bin.ld.path") = move (ldi.path); + rs.assign ("bin.ld.path") = + process_path_ex (move (ldi.path), "ld", ldi.checksum); rs.assign ("bin.ld.id") = move (ldi.id); rs.assign ("bin.ld.signature") = move (ldi.signature); rs.assign ("bin.ld.checksum") = move (ldi.checksum); @@ -881,8 +883,7 @@ namespace build2 { auto& vp (rs.var_pool ()); - vp.insert ("bin.rc.path"); - vp.insert ("config.bin.rc"); + vp.insert ("config.bin.rc"); } // Configuration. @@ -926,7 +927,8 @@ namespace build2 << " checksum " << rci.checksum; } - rs.assign ("bin.rc.path") = move (rci.path); + rs.assign ("bin.rc.path") = + process_path_ex (move (rci.path), "rc", rci.checksum); rs.assign ("bin.rc.id") = move (rci.id); rs.assign ("bin.rc.signature") = move (rci.signature); rs.assign ("bin.rc.checksum") = move (rci.checksum); diff --git a/libbuild2/c/init.cxx b/libbuild2/c/init.cxx index 5eea8de..5a70b54 100644 --- a/libbuild2/c/init.cxx +++ b/libbuild2/c/init.cxx @@ -177,10 +177,10 @@ namespace build2 vp.insert ("config.c.libs"), nullptr /* config.c.translatable_headers */, - vp.insert ("c.path"), - vp.insert ("c.mode"), - vp.insert ("c.sys_lib_dirs"), - vp.insert ("c.sys_inc_dirs"), + vp.insert ("c.path"), + vp.insert ("c.mode"), + vp.insert ("c.sys_lib_dirs"), + vp.insert ("c.sys_inc_dirs"), vp.insert ("c.std"), diff --git a/libbuild2/cc/module.cxx b/libbuild2/cc/module.cxx index a485b46..a80d770 100644 --- a/libbuild2/cc/module.cxx +++ b/libbuild2/cc/module.cxx @@ -197,7 +197,7 @@ namespace build2 // Assign values to variables that describe the compiler. // - rs.assign (x_path) = process_path (xi.path, false /* init */); + rs.assign (x_path) = process_path_ex (xi.path, x_name, xi.checksum); const strings& xm (cast (rs.assign (x_mode) = move (mode))); rs.assign (x_id) = xi.id.string (); diff --git a/libbuild2/context.hxx b/libbuild2/context.hxx index 5f6e810..e4d4d4c 100644 --- a/libbuild2/context.hxx +++ b/libbuild2/context.hxx @@ -377,6 +377,8 @@ namespace build2 // If the .name variable is missing, it is set to the target // name as imported. // + // See also process_path_ex. + // const variable* var_import_metadata; const variable* var_export_metadata; diff --git a/libbuild2/cxx/init.cxx b/libbuild2/cxx/init.cxx index 265bbc0..65d13cf 100644 --- a/libbuild2/cxx/init.cxx +++ b/libbuild2/cxx/init.cxx @@ -427,10 +427,10 @@ namespace build2 // &vp.insert ("config.cxx.translatable_headers"), - vp.insert ("cxx.path"), - vp.insert ("cxx.mode"), - vp.insert ("cxx.sys_lib_dirs"), - vp.insert ("cxx.sys_inc_dirs"), + vp.insert ("cxx.path"), + vp.insert ("cxx.mode"), + vp.insert ("cxx.sys_lib_dirs"), + vp.insert ("cxx.sys_inc_dirs"), vp.insert ("cxx.std"), diff --git a/libbuild2/functions-process-path.cxx b/libbuild2/functions-process-path.cxx index 15bec81..86d4445 100644 --- a/libbuild2/functions-process-path.cxx +++ b/libbuild2/functions-process-path.cxx @@ -11,14 +11,23 @@ namespace build2 void process_path_functions (function_map& m) { - function_family f (m, "process_path"); + { + function_family f (m, "process_path"); + + // As discussed in value_traits, we always have recall. + // + f["recall"] = &process_path::recall; + f["effect"] = [](process_path p) + { + return move (p.effect.empty () ? p.recall : p.effect); + }; + } - // As discussed in value_traits, we always have recall. - // - f["recall"] = &process_path::recall; - f["effect"] = [](process_path p) { - return move (p.effect.empty () ? p.recall : p.effect); - }; + function_family f (m, "process_path_ex"); + + f["name"] = &process_path_ex::name; + f["checksum"] = &process_path_ex::checksum; + } } } diff --git a/libbuild2/types.hxx b/libbuild2/types.hxx index 6582c3a..65e0918 100644 --- a/libbuild2/types.hxx +++ b/libbuild2/types.hxx @@ -283,6 +283,30 @@ namespace build2 using butl::process_path; using butl::process_error; + // Extended process_path with additional information. + // + // See also {import,export}.metadata. + // + struct process_path_ex: process_path + { + optional name; // Stable name for diagnostics. + optional checksum; // Checksum for change tracking. + + using process_path::process_path; + + process_path_ex (const process_path& p, string n, optional c = {}) + : process_path (p, false /* init */), + name (std::move (n)), + checksum (std::move (c)) {} + + process_path_ex (process_path&& p, string n, optional c = {}) + : process_path (std::move (p)), + name (std::move (n)), + checksum (std::move (c)) {} + + process_path_ex () = default; + }; + // // using butl::auto_fd; diff --git a/libbuild2/variable.cxx b/libbuild2/variable.cxx index 14803cb..ed710af 100644 --- a/libbuild2/variable.cxx +++ b/libbuild2/variable.cxx @@ -839,7 +839,7 @@ namespace build2 return name_pair (move (n), r != nullptr ? move (*r) : name ()); } - void + static void name_pair_assign (value& v, names&& ns, const variable* var) { using traits = value_traits; @@ -911,8 +911,9 @@ namespace build2 // process_path value // - process_path value_traits:: - convert (name&& n, name* r) + template + static T + process_path_convert (name&& n, name* r, const char* what) { if ( n.untyped () && n.unqualified () && !n.empty () && (r == nullptr || (r->untyped () && r->unqualified () && !r->empty ()))) @@ -933,15 +934,21 @@ namespace build2 ep /= r->value; } - process_path pp (nullptr, move (rp), move (ep)); + T pp (nullptr, move (rp), move (ep)); pp.initial = pp.recall.string ().c_str (); return pp; } - throw_invalid_argument (n, r, "process_path"); + throw_invalid_argument (n, r, what); } - void + process_path value_traits:: + convert (name&& n, name* r) + { + return process_path_convert (move (n), r, "process_path"); + } + + static void process_path_assign (value& v, names&& ns, const variable* var) { using traits = value_traits; @@ -969,23 +976,24 @@ namespace build2 dr << " in variable " << var->name; } - void + template + static void process_path_copy_ctor (value& l, const value& r, bool m) { - const auto& rhs (r.as ()); + const auto& rhs (r.as ()); if (m) - new (&l.data_) process_path (move (const_cast (rhs))); + new (&l.data_) T (move (const_cast (rhs))); else { auto& lhs ( - *new (&l.data_) process_path ( + *new (&l.data_) T ( nullptr, path (rhs.recall), path (rhs.effect))); lhs.initial = lhs.recall.string ().c_str (); } } - void + static void process_path_copy_assign (value& l, const value& r, bool m) { auto& lhs (l.as ()); @@ -1001,26 +1009,31 @@ namespace build2 } } + static void + process_path_reverse_impl (const process_path& x, names& s) + { + s.push_back (name (x.recall.directory (), + string (), + x.recall.leaf ().string ())); + + if (!x.effect.empty ()) + { + s.back ().pair = '@'; + s.push_back (name (x.effect.directory (), + string (), + x.effect.leaf ().string ())); + } + } + static names_view process_path_reverse (const value& v, names& s) { - const process_path& x (v.as ()); + const auto& x (v.as ()); if (!x.empty ()) { s.reserve (x.effect.empty () ? 1 : 2); - - s.push_back (name (x.recall.directory (), - string (), - x.recall.leaf ().string ())); - - if (!x.effect.empty ()) - { - s.back ().pair = '@'; - s.push_back (name (x.effect.directory (), - string (), - x.effect.leaf ().string ())); - } + process_path_reverse_impl (x, s); } return s; @@ -1035,7 +1048,7 @@ namespace build2 nullptr, // No base. nullptr, // No element. &default_dtor, - &process_path_copy_ctor, + &process_path_copy_ctor, &process_path_copy_assign, &process_path_assign, nullptr, // Append not supported. @@ -1046,6 +1059,165 @@ namespace build2 &default_empty }; + // process_path_ex value + // + process_path_ex value_traits:: + convert (names&& ns) + { + if (ns.empty ()) + return process_path_ex (); + + bool p (ns[0].pair); + + process_path_ex pp ( + process_path_convert ( + move (ns[0]), p ? &ns[1] : nullptr, "process_path_ex")); + + for (auto i (ns.begin () + (p ? 2 : 1)); i != ns.end (); ++i) + { + if (!i->pair) + throw invalid_argument ("non-pair in process_path_ex value"); + + if (!i->simple ()) + throw_invalid_argument (*i, nullptr, "process_path_ex"); + + const string& k ((i++)->value); + + if (k == "name") + { + if (!i->simple ()) + throw_invalid_argument (*i, nullptr, "process_path_ex name"); + + pp.name = move (i->value); + } + else if (k == "checksum") + { + if (!i->simple ()) + throw_invalid_argument (*i, nullptr, "process_path_ex checksum"); + + pp.checksum = move (i->value); + } + else + throw invalid_argument ( + "unknown key '" + k + "' in process_path_ex value"); + } + + return pp; + } + + static void + process_path_ex_assign (value& v, names&& ns, const variable* var) + { + using traits = value_traits; + + try + { + traits::assign (v, traits::convert (move (ns))); + } + catch (const invalid_argument& e) + { + // Note: ns is not guaranteed to be valid. + // + diag_record dr (fail); + dr << "invalid process_path_ex value"; + + if (var != nullptr) + dr << " in variable " << var->name; + + dr << ": " << e; + } + } + + static void + process_path_ex_copy_ex (value& l, const value& r, bool m) + { + auto& lhs (l.as ()); + + if (m) + { + const auto& rhs (const_cast (r).as ()); + + lhs.name = move (rhs.name); + lhs.checksum = move (rhs.checksum); + } + else + { + const auto& rhs (r.as ()); + + lhs.name = rhs.name; + lhs.checksum = rhs.checksum; + } + } + + static void + process_path_ex_copy_ctor (value& l, const value& r, bool m) + { + process_path_copy_ctor (l, r, m); + + if (!m) + process_path_ex_copy_ex (l, r, false); + } + + static void + process_path_ex_copy_assign (value& l, const value& r, bool m) + { + process_path_copy_assign (l, r, m); + process_path_ex_copy_ex (l, r, m); + } + + static names_view + process_path_ex_reverse (const value& v, names& s) + { + const auto& x (v.as ()); + + if (!x.empty ()) + { + s.reserve ((x.effect.empty () ? 1 : 2) + + (x.name ? 2 : 0) + + (x.checksum ? 2 : 0)); + + process_path_reverse_impl (x, s); + + if (x.name) + { + s.push_back (name ("name")); + s.back ().pair = '@'; + s.push_back (name (*x.name)); + } + + if (x.checksum) + { + s.push_back (name ("checksum")); + s.back ().pair = '@'; + s.push_back (name (*x.checksum)); + } + } + + return s; + } + + const char* const value_traits::type_name = + "process_path_ex"; + + const value_type value_traits::value_type + { + type_name, + sizeof (process_path_ex), + &value_traits< // Base (assuming direct cast works + process_path>::value_type, // for both). + nullptr, // No element. + &default_dtor, + &process_path_ex_copy_ctor, + &process_path_ex_copy_assign, + &process_path_ex_assign, + nullptr, // Append not supported. + nullptr, // Prepend not supported. + &process_path_ex_reverse, + nullptr, // No cast (cast data_ directly). + &simple_compare, // For now compare as process_path. + &default_empty + }; + // target_triplet value // target_triplet value_traits:: diff --git a/libbuild2/variable.hxx b/libbuild2/variable.hxx index 409a4aa..e5d8e72 100644 --- a/libbuild2/variable.hxx +++ b/libbuild2/variable.hxx @@ -881,8 +881,8 @@ namespace build2 static_assert (sizeof (process_path) <= value::size_, "insufficient space"); - // This one is represented as a @-pair of names. As a result it cannot - // be stored in a container. + // Represented as a @-pair of names. As a result it cannot be stored in a + // container. // static process_path convert (name&&, name*); static void assign (value&, process_path&&); @@ -894,6 +894,26 @@ namespace build2 static const build2::value_type value_type; }; + // process_path_ex + // + template <> + struct LIBBUILD2_SYMEXPORT value_traits + { + static_assert (sizeof (process_path_ex) <= value::size_, + "insufficient space"); + + // Represented as a @-pair of names corresponding to process_path followed + // by the name@ and checksum@ pairs. So it's a container-like. + // + static process_path_ex convert (names&&); + static void assign (value&, process_path_ex&&); + static bool empty (const process_path_ex& x) {return x.empty ();} + + static const bool empty_value = true; + static const char* const type_name; + static const build2::value_type value_type; + }; + // target_triplet // template <> diff --git a/libbuild2/variable.ixx b/libbuild2/variable.ixx index 50cce78..84bf20c 100644 --- a/libbuild2/variable.ixx +++ b/libbuild2/variable.ixx @@ -614,7 +614,7 @@ namespace build2 inline void value_traits:: assign (value& v, process_path&& x) { - // Convert the value to its "self-sufficient" form. + // Convert the value to its "self-sufficient" form (see also below). // if (x.recall.empty ()) x.recall = path (x.initial); @@ -638,6 +638,24 @@ namespace build2 return r; } + // process_path_ex value + // + inline void value_traits:: + assign (value& v, process_path_ex&& x) + { + // Convert the value to its "self-sufficient" form (see also above). + // + if (x.recall.empty ()) + x.recall = path (x.initial); + + x.initial = x.recall.string ().c_str (); + + if (v) + v.as () = move (x); + else + new (&v.data_) process_path_ex (move (x)); + } + // target_triplet value // inline void value_traits:: -- cgit v1.1