From 9f5c4c1ae3bff517eefb39130287016514fb31c7 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 6 Jan 2017 17:28:45 +0200 Subject: Store platform targets as typed target_triplet --- build2/bin/init.cxx | 30 +++--- build2/buildfile | 171 ++++++++++++++++---------------- build2/c/init.cxx | 9 +- build2/cc/common | 14 ++- build2/cc/guess.cxx | 4 +- build2/cc/init.cxx | 55 ++++------ build2/cc/link.cxx | 2 +- build2/cc/module.cxx | 104 ++++++++++--------- build2/context.cxx | 23 ++--- build2/cxx/init.cxx | 9 +- build2/function.cxx | 12 ++- build2/functions-target-triplet.cxx | 36 +++++++ build2/parser.cxx | 23 +++-- build2/pkgconfig/init.cxx | 8 +- build2/types | 5 + build2/variable | 29 +++++- build2/variable.cxx | 45 +++++++++ build2/variable.ixx | 11 ++ unit-tests/function/buildfile | 3 +- unit-tests/test/script/parser/buildfile | 4 +- 20 files changed, 358 insertions(+), 239 deletions(-) create mode 100644 build2/functions-target-triplet.cxx diff --git a/build2/bin/init.cxx b/build2/bin/init.cxx index cb87dd8..89dea09 100644 --- a/build2/bin/init.cxx +++ b/build2/bin/init.cxx @@ -6,8 +6,6 @@ #include -#include - #include #include #include @@ -55,6 +53,9 @@ namespace build2 // Note: some overridable, some not. // + // Target is a string and not target_triplet because it can be + // specified by the user. + // v.insert ("config.bin.target", true); v.insert ("config.bin.pattern", true); @@ -222,22 +223,23 @@ namespace build2 try { - string canon; - triplet t (s, canon); + target_triplet t (s); - l5 ([&]{trace << "canonical target: '" << canon << "'; " + l5 ([&]{trace << "canonical target: '" << t.string () << "'; " << "class: " << t.class_;}); - assert (!hint || s == canon); + assert (!hint || s == t.string ()); - // Enter as bin.target.{cpu,vendor,system,version,class}. + // Also enter as bin.target.{cpu,vendor,system,version,class} + // for convenience of access. // - r.assign ("bin.target") = move (canon); - r.assign ("bin.target.cpu") = move (t.cpu); - r.assign ("bin.target.vendor") = move (t.vendor); - r.assign ("bin.target.system") = move (t.system); - r.assign ("bin.target.version") = move (t.version); - r.assign ("bin.target.class") = move (t.class_); + r.assign ("bin.target.cpu") = t.cpu; + r.assign ("bin.target.vendor") = t.vendor; + r.assign ("bin.target.system") = t.system; + r.assign ("bin.target.version") = t.version; + r.assign ("bin.target.class") = t.class_; + + r.assign ("bin.target") = move (t); } catch (const invalid_argument& e) { @@ -298,7 +300,7 @@ namespace build2 diag_record dr (text); dr << "bin " << project (r) << '@' << r.out_path () << '\n' - << " target " << cast (r["bin.target"]); + << " target " << cast (r["bin.target"]); if (auto l = r["bin.pattern"]) dr << '\n' diff --git a/build2/buildfile b/build2/buildfile index befddf4..83f29f8 100644 --- a/build2/buildfile +++ b/build2/buildfile @@ -4,91 +4,92 @@ import libs = libbutl%lib{butl} -exe{b}: \ - {hxx ixx cxx}{ algorithm } \ - { cxx}{ b } \ - {hxx ixx cxx}{ b-options } \ - {hxx cxx}{ context } \ - {hxx cxx}{ depdb } \ - {hxx cxx}{ diagnostics } \ - {hxx cxx}{ dump } \ - {hxx ixx cxx}{ file } \ - {hxx txx cxx}{ filesystem } \ - {hxx cxx}{ function } \ - { cxx}{ functions-builtin } \ - { cxx}{ functions-path } \ - { cxx}{ functions-process-path } \ - { cxx}{ functions-string } \ - {hxx cxx}{ lexer } \ - {hxx cxx}{ module } \ - {hxx ixx cxx}{ name } \ - {hxx cxx}{ operation } \ - {hxx cxx}{ parser } \ - {hxx cxx}{ prerequisite } \ - {hxx cxx}{ rule } \ - {hxx }{ rule-map } \ - {hxx txx cxx}{ scheduler } \ - {hxx cxx}{ scope } \ - {hxx cxx}{ search } \ - {hxx cxx}{ spec } \ - {hxx ixx txx cxx}{ target } \ - {hxx }{ target-key } \ - {hxx }{ target-type } \ - {hxx cxx}{ token } \ - {hxx }{ types } \ - {hxx cxx}{ types-parsers } \ - {hxx ixx txx cxx}{ utility } \ - {hxx ixx txx cxx}{ variable } \ - {hxx }{ version } \ - bin/{hxx cxx}{ guess } \ - bin/{hxx cxx}{ init } \ - bin/{hxx cxx}{ rule } \ - bin/{hxx cxx}{ target } \ - c/{hxx cxx}{ init } \ - c/{hxx }{ target } \ - cc/{hxx cxx}{ common } \ - cc/{hxx cxx}{ compile } \ - cc/{ cxx}{ gcc } \ - cc/{hxx cxx}{ guess } \ - cc/{hxx cxx}{ init } \ - cc/{hxx cxx}{ install } \ - cc/{hxx cxx}{ link } \ - cc/{hxx cxx}{ module } \ - cc/{ cxx}{ msvc } \ - cc/{ cxx}{ pkgconfig } \ - cc/{hxx cxx}{ target } \ - cc/{hxx }{ types } \ - cc/{hxx ixx cxx}{ utility } \ - cc/{ cxx}{ windows-manifest } \ - cc/{ cxx}{ windows-rpath } \ - cli/{hxx cxx}{ init } \ - cli/{hxx cxx}{ rule } \ - cli/{hxx cxx}{ target } \ - config/{hxx cxx}{ init } \ - config/{hxx }{ module } \ - config/{hxx cxx}{ operation } \ - config/{hxx txx cxx}{ utility } \ - cxx/{hxx cxx}{ init } \ - cxx/{hxx cxx}{ target } \ - dist/{hxx cxx}{ init } \ - dist/{hxx cxx}{ operation } \ - dist/{hxx cxx}{ rule } \ - pkgconfig/{hxx cxx}{ init } \ - install/{hxx cxx}{ init } \ - install/{hxx cxx}{ operation } \ - install/{hxx cxx}{ rule } \ - install/{hxx }{ utility } \ - test/{hxx cxx}{ init } \ - test/{hxx cxx}{ operation } \ - test/{hxx cxx}{ rule } \ - test/{hxx cxx}{ target } \ -test/script/{hxx cxx}{ builtin } \ -test/script/{hxx cxx}{ lexer } \ -test/script/{hxx cxx}{ parser } \ -test/script/{hxx cxx}{ regex } \ -test/script/{hxx cxx}{ runner } \ -test/script/{hxx ixx cxx}{ script } \ -test/script/{hxx cxx}{ token } \ +exe{b}: \ + {hxx ixx cxx}{ algorithm } \ + { cxx}{ b } \ + {hxx ixx cxx}{ b-options } \ + {hxx cxx}{ context } \ + {hxx cxx}{ depdb } \ + {hxx cxx}{ diagnostics } \ + {hxx cxx}{ dump } \ + {hxx ixx cxx}{ file } \ + {hxx txx cxx}{ filesystem } \ + {hxx cxx}{ function } \ + { cxx}{ functions-builtin } \ + { cxx}{ functions-path } \ + { cxx}{ functions-process-path } \ + { cxx}{ functions-string } \ + { cxx}{ functions-target-triplet } \ + {hxx cxx}{ lexer } \ + {hxx cxx}{ module } \ + {hxx ixx cxx}{ name } \ + {hxx cxx}{ operation } \ + {hxx cxx}{ parser } \ + {hxx cxx}{ prerequisite } \ + {hxx cxx}{ rule } \ + {hxx }{ rule-map } \ + {hxx txx cxx}{ scheduler } \ + {hxx cxx}{ scope } \ + {hxx cxx}{ search } \ + {hxx cxx}{ spec } \ + {hxx ixx txx cxx}{ target } \ + {hxx }{ target-key } \ + {hxx }{ target-type } \ + {hxx cxx}{ token } \ + {hxx }{ types } \ + {hxx cxx}{ types-parsers } \ + {hxx ixx txx cxx}{ utility } \ + {hxx ixx txx cxx}{ variable } \ + {hxx }{ version } \ + bin/{hxx cxx}{ guess } \ + bin/{hxx cxx}{ init } \ + bin/{hxx cxx}{ rule } \ + bin/{hxx cxx}{ target } \ + c/{hxx cxx}{ init } \ + c/{hxx }{ target } \ + cc/{hxx cxx}{ common } \ + cc/{hxx cxx}{ compile } \ + cc/{ cxx}{ gcc } \ + cc/{hxx cxx}{ guess } \ + cc/{hxx cxx}{ init } \ + cc/{hxx cxx}{ install } \ + cc/{hxx cxx}{ link } \ + cc/{hxx cxx}{ module } \ + cc/{ cxx}{ msvc } \ + cc/{ cxx}{ pkgconfig } \ + cc/{hxx cxx}{ target } \ + cc/{hxx }{ types } \ + cc/{hxx ixx cxx}{ utility } \ + cc/{ cxx}{ windows-manifest } \ + cc/{ cxx}{ windows-rpath } \ + cli/{hxx cxx}{ init } \ + cli/{hxx cxx}{ rule } \ + cli/{hxx cxx}{ target } \ + config/{hxx cxx}{ init } \ + config/{hxx }{ module } \ + config/{hxx cxx}{ operation } \ + config/{hxx txx cxx}{ utility } \ + cxx/{hxx cxx}{ init } \ + cxx/{hxx cxx}{ target } \ + dist/{hxx cxx}{ init } \ + dist/{hxx cxx}{ operation } \ + dist/{hxx cxx}{ rule } \ + pkgconfig/{hxx cxx}{ init } \ + install/{hxx cxx}{ init } \ + install/{hxx cxx}{ operation } \ + install/{hxx cxx}{ rule } \ + install/{hxx }{ utility } \ + test/{hxx cxx}{ init } \ + test/{hxx cxx}{ operation } \ + test/{hxx cxx}{ rule } \ + test/{hxx cxx}{ target } \ +test/script/{hxx cxx}{ builtin } \ +test/script/{hxx cxx}{ lexer } \ +test/script/{hxx cxx}{ parser } \ +test/script/{hxx cxx}{ regex } \ +test/script/{hxx cxx}{ runner } \ +test/script/{hxx ixx cxx}{ script } \ +test/script/{hxx cxx}{ token } \ $libs # Pass our compiler target to be used as build2 host. diff --git a/build2/c/init.cxx b/build2/c/init.cxx index c93fecb..95bfd7c 100644 --- a/build2/c/init.cxx +++ b/build2/c/init.cxx @@ -175,7 +175,8 @@ namespace build2 v.insert ("c.signature"), v.insert ("c.checksum"), - v.insert ("c.target"), + v.insert ("c.target"), + v.insert ("c.target.cpu"), v.insert ("c.target.vendor"), v.insert ("c.target.system"), @@ -235,10 +236,8 @@ namespace build2 "c.install", "c.uninstall", - cast (rs[cm.x_id]), - cast (rs[cm.x_target]), - cast (rs[cm.x_target_system]), - cast (rs[cm.x_target_class]), + cast (rs[cm.x_id]), + cast (rs[cm.x_target]), cm.tstd, diff --git a/build2/cc/common b/build2/cc/common index 3974a03..2c79fa6 100644 --- a/build2/cc/common +++ b/build2/cc/common @@ -97,10 +97,10 @@ namespace build2 // Cached values for some commonly-used variables/values. // - const string& cid; // x.id - const string& ctg; // x.target - const string& tsys; // x.target.system - const string& tclass; // x.target.class + const string& cid; // x.id + const target_triplet& ctg; // x.target + const string& tsys; // x.target.system + const string& tclass; // x.target.class const string& tstd; // Translated x_std value (can be empty). @@ -140,9 +140,7 @@ namespace build2 const char* install, const char* uninstall, const string& id, - const string& tg, - const string& ts, - const string& tc, + const target_triplet& tg, const string& std, const process_path* pkgc, const dir_paths& sld, @@ -155,7 +153,7 @@ namespace build2 x_link (link), x_install (install), x_uninstall (uninstall), - cid (id), ctg (tg), tsys (ts), tclass (tc), + cid (id), ctg (tg), tsys (ctg.system), tclass (ctg.class_), tstd (std), pkgconfig (pkgc), sys_lib_dirs (sld), sys_inc_dirs (sid), x_src (src), x_hdr (hdr), x_inc (inc) {} diff --git a/build2/cc/guess.cxx b/build2/cc/guess.cxx index e0b4911..8b45420 100644 --- a/build2/cc/guess.cxx +++ b/build2/cc/guess.cxx @@ -946,8 +946,8 @@ namespace build2 // Now we need to map x86, x64, and ARM to the target triplets. The // problem is, there aren't any established ones so we got to invent - // them ourselves. Based on the discussion in , we need - // something in the CPU-VENDOR-OS-ABI form. + // them ourselves. Based on the discussion in , + // we need something in the CPU-VENDOR-OS-ABI form. // // The CPU part is fairly straightforward with x86 mapped to 'i386' (or // maybe 'i686'), x64 to 'x86_64', and ARM to 'arm' (it could also diff --git a/build2/cc/init.cxx b/build2/cc/init.cxx index 32ea8f3..a162daa 100644 --- a/build2/cc/init.cxx +++ b/build2/cc/init.cxx @@ -4,8 +4,6 @@ #include -#include - #include #include #include @@ -56,9 +54,9 @@ namespace build2 // Hint variables (not overridable). // - v.insert ("config.cc.id"); - v.insert ("config.cc.target"); - v.insert ("config.cc.pattern"); + v.insert ("config.cc.id"); + v.insert ("config.cc.pattern"); + v.insert ("config.cc.target"); // Target type, for example, "C library" or "C++ library". Should be set // on the target by the matching rule to the name of the module (e.g., @@ -115,31 +113,20 @@ namespace build2 // config.cc.target // { - // This value must be hinted and already canonicalized. + // This value must be hinted. // - const string& s (cast (hints["config.cc.target"])); + const auto& t (cast (hints["config.cc.target"])); - try - { - //@@ We do it in the hinting module and here. Any way not to - // duplicate the effort? Maybe move the splitting here and - // simply duplicate the values there? - // - triplet t (s); - - // Enter as cc.target.{cpu,vendor,system,version,class}. - // - rs.assign ("cc.target") = s; - rs.assign ("cc.target.cpu") = move (t.cpu); - rs.assign ("cc.target.vendor") = move (t.vendor); - rs.assign ("cc.target.system") = move (t.system); - rs.assign ("cc.target.version") = move (t.version); - rs.assign ("cc.target.class") = move (t.class_); - } - catch (const invalid_argument& e) - { - assert (false); // Should have been caught by the hinting module. - } + // Also enter as cc.target.{cpu,vendor,system,version,class} for + // convenience of access. + // + rs.assign ("cc.target.cpu") = t.cpu; + rs.assign ("cc.target.vendor") = t.vendor; + rs.assign ("cc.target.system") = t.system; + rs.assign ("cc.target.version") = t.version; + rs.assign ("cc.target.class") = t.class_; + + rs.assign ("cc.target") = t; } // config.cc.pattern @@ -182,10 +169,11 @@ namespace build2 variable_map h; if (first) { - h.assign ("config.bin.target") = cast (rs["cc.target"]); + h.assign ("config.bin.target") = + cast (rs["cc.target"]).string (); if (auto l = hints["config.bin.pattern"]) - h.assign ("config.bin.pattern") = cast (l); + h.assign ("config.bin.pattern") = cast (l); } load_module ("bin.config", rs, rs, loc, false, h); @@ -197,8 +185,8 @@ namespace build2 // if (first) { - const string& ct (cast (rs["cc.target"])); - const string& bt (cast (rs["bin.target"])); + const auto& ct (cast (rs["cc.target"])); + const auto& bt (cast (rs["bin.target"])); if (bt != ct) fail (loc) << "cc and bin module target mismatch" << @@ -245,7 +233,8 @@ namespace build2 // Prepare configuration hints. // variable_map h; - h.assign ("config.pkgconfig.target") = cast (rs["cc.target"]); + h.assign ("config.pkgconfig.target") = + cast (rs["cc.target"]); load_module ("pkgconfig.config", rs, rs, loc, true, h); } diff --git a/build2/cc/link.cxx b/build2/cc/link.cxx index c90fcb1..f55013f 100644 --- a/build2/cc/link.cxx +++ b/build2/cc/link.cxx @@ -1046,7 +1046,7 @@ namespace build2 // Next check the target. While it might be incorporated into the linker // checksum, it also might not (e.g., VC link.exe). // - if (dd.expect (ctg) != nullptr) + if (dd.expect (ctg.string ()) != nullptr) l4 ([&]{trace << "target mismatch forcing update of " << t;}); // Start building the command line. While we don't yet know whether we diff --git a/build2/cc/module.cxx b/build2/cc/module.cxx index 5ac10f7..067aea3 100644 --- a/build2/cc/module.cxx +++ b/build2/cc/module.cxx @@ -6,8 +6,6 @@ #include // left, setw() -#include - #include #include #include @@ -93,31 +91,33 @@ namespace build2 // Split/canonicalize the target. First see if the user asked us to // use config.sub. // - string ct, st; - triplet tt; - - if (ops.config_sub_specified ()) + target_triplet tt; { - st = run (ops.config_sub (), - ci.target.c_str (), - [] (string& l) {return move (l);}); - l5 ([&]{trace << "config.sub target: '" << st << "'";}); - } + string ct; - try - { - tt = triplet (st.empty () ? ci.target : st, ct); - l5 ([&]{trace << "canonical target: '" << ct << "'; " - << "class: " << tt.class_;}); - } - catch (const invalid_argument& e) - { - // This is where we suggest that the user specifies --config-sub to - // help us out. - // - fail << "unable to parse " << x_lang << " compiler target '" - << ci.target << "': " << e.what () << - info << "consider using the --config-sub option"; + if (ops.config_sub_specified ()) + { + ct = run (ops.config_sub (), + ci.target.c_str (), + [] (string& l) {return move (l);}); + l5 ([&]{trace << "config.sub target: '" << ct << "'";}); + } + + try + { + tt = target_triplet (ct.empty () ? ci.target : ct); + l5 ([&]{trace << "canonical target: '" << tt.string () << "'; " + << "class: " << tt.class_;}); + } + catch (const invalid_argument& e) + { + // This is where we suggest that the user specifies --config-sub to + // help us out. + // + fail << "unable to parse " << x_lang << " compiler target '" + << ci.target << "': " << e.what () << + info << "consider using the --config-sub option"; + } } // Translate x_std value (if any) to the compiler option (if any). @@ -177,6 +177,8 @@ namespace build2 } { + const string& ct (tt.string ()); // Canonical target. + dr << " signature " << ci.signature << '\n' << " target " << ct; @@ -232,14 +234,16 @@ namespace build2 rs.assign (x_signature) = move (ci.signature); rs.assign (x_checksum) = move (ci.checksum); - // Enter as x.target.{cpu,vendor,system,version,class}. + // Also enter as x.target.{cpu,vendor,system,version,class} for + // convenience of access. // - rs.assign (x_target) = move (ct); - rs.assign (x_target_cpu) = move (tt.cpu); - rs.assign (x_target_vendor) = move (tt.vendor); - rs.assign (x_target_system) = move (tt.system); - rs.assign (x_target_version) = move (tt.version); - rs.assign (x_target_class) = move (tt.class_); + rs.assign (x_target_cpu) = tt.cpu; + rs.assign (x_target_vendor) = tt.vendor; + rs.assign (x_target_system) = tt.system; + rs.assign (x_target_version) = tt.version; + rs.assign (x_target_class) = tt.class_; + + rs.assign (x_target) = move (tt); // config.x.{p,c,l}options // config.x.libs @@ -278,7 +282,7 @@ namespace build2 variable_map h; h.assign ("config.cc.id") = cast (rs[x_id]); - h.assign ("config.cc.target") = cast (rs[x_target]); + h.assign ("config.cc.target") = cast (rs[x_target]); if (!ci.cc_pattern.empty ()) h.assign ("config.cc.pattern") = move (ci.cc_pattern); @@ -294,25 +298,29 @@ namespace build2 // matched ours since it could have been loaded by another c-family // module. // - auto check = [&rs, &loc, this](const char* cvar, - const variable& xvar, - const char* w) - { - const string& cv (cast (rs[cvar])); - const string& xv (cast (rs[xvar])); - - if (cv != xv) - fail (loc) << "cc and " << x << " module " << w << " mismatch" << - info << cvar << " is " << cv << - info << xvar.name << " is " << xv; - }; - // Note that we don't require that patterns match. Presumably, if the // toolchain id and target are the same, then where exactly the tools // come from doesn't really matter. // - check ("cc.id", x_id, "toolchain"); - check ("cc.target", x_target, "target"); + { + const auto& cv (cast (rs["cc.id"])); + const auto& xv (cast (rs[x_id])); + + if (cv != xv) + fail (loc) << "cc and " << x << " module toolchain mismatch" << + info << "cc.id is " << cv << + info << x_id.name << " is " << xv; + } + + { + const auto& cv (cast (rs["cc.target"])); + const auto& xv (cast (rs[x_target])); + + if (cv != xv) + fail (loc) << "cc and " << x << " module target mismatch" << + info << "cc.target is " << cv << + info << x_target.name << " is " << xv; + } } } diff --git a/build2/context.cxx b/build2/context.cxx index f9124d4..38c726d 100644 --- a/build2/context.cxx +++ b/build2/context.cxx @@ -6,8 +6,6 @@ #include -#include - #include #include #include @@ -283,20 +281,21 @@ namespace build2 try { - string canon; - triplet t (orig, canon); + target_triplet t (orig); - l5 ([&]{trace << "canonical host: '" << canon << "'; " + l5 ([&]{trace << "canonical host: '" << t.string () << "'; " << "class: " << t.class_;}); - // Enter as build.host.{cpu,vendor,system,version,class}. + // Also enter as build.host.{cpu,vendor,system,version,class} for + // convenience of access. // - gs.assign ("build.host") = move (canon); - gs.assign ("build.host.cpu") = move (t.cpu); - gs.assign ("build.host.vendor") = move (t.vendor); - gs.assign ("build.host.system") = move (t.system); - gs.assign ("build.host.version") = move (t.version); - gs.assign ("build.host.class") = move (t.class_); + gs.assign ("build.host.cpu") = t.cpu; + gs.assign ("build.host.vendor") = t.vendor; + gs.assign ("build.host.system") = t.system; + gs.assign ("build.host.version") = t.version; + gs.assign ("build.host.class") = t.class_; + + gs.assign ("build.host") = move (t); } catch (const invalid_argument& e) { diff --git a/build2/cxx/init.cxx b/build2/cxx/init.cxx index 9bcfd23..867deba 100644 --- a/build2/cxx/init.cxx +++ b/build2/cxx/init.cxx @@ -238,7 +238,8 @@ namespace build2 v.insert ("cxx.signature"), v.insert ("cxx.checksum"), - v.insert ("cxx.target"), + v.insert ("cxx.target"), + v.insert ("cxx.target.cpu"), v.insert ("cxx.target.vendor"), v.insert ("cxx.target.system"), @@ -305,10 +306,8 @@ namespace build2 "cxx.install", "cxx.uninstall", - cast (rs[cm.x_id]), - cast (rs[cm.x_target]), - cast (rs[cm.x_target_system]), - cast (rs[cm.x_target_class]), + cast (rs[cm.x_id]), + cast (rs[cm.x_target]), cm.tstd, diff --git a/build2/function.cxx b/build2/function.cxx index 8cfb857..c3a08c1 100644 --- a/build2/function.cxx +++ b/build2/function.cxx @@ -301,19 +301,21 @@ namespace build2 // function_map functions; - void builtin_functions (); // functions-builtin.cxx - void path_functions (); // functions-path.cxx - void process_path_functions (); // functions-process-path.cxx - void string_functions (); // functions-string.cxx + void builtin_functions (); // functions-builtin.cxx + void string_functions (); // functions-string.cxx + void path_functions (); // functions-path.cxx + void process_path_functions (); // functions-process-path.cxx + void target_triplet_functions (); // functions-target-triplet.cxx struct functions_init { functions_init () { builtin_functions (); + string_functions (); path_functions (); process_path_functions (); - string_functions (); + target_triplet_functions (); } }; diff --git a/build2/functions-target-triplet.cxx b/build2/functions-target-triplet.cxx new file mode 100644 index 0000000..fb95331 --- /dev/null +++ b/build2/functions-target-triplet.cxx @@ -0,0 +1,36 @@ +// file : build2/functions-target-triplet.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include +#include + +using namespace std; + +namespace build2 +{ + void + target_triplet_functions () + { + function_family f ("target_triplet"); + + f["string"] = [](target_triplet t) {return t.string ();}; + + // Target triplet-specific overloads from builtins. + // + function_family b ("builtin"); + + b[".concat"] = [](target_triplet l, string sr) {return l.string () + sr;}; + b[".concat"] = [](string sl, target_triplet r) {return sl + r.string ();}; + + b[".concat"] = [](target_triplet l, names ur) + { + return l.string () + convert (move (ur)); + }; + + b[".concat"] = [](names ul, target_triplet r) + { + return convert (move (ul)) + r.string (); + }; + } +} diff --git a/build2/parser.cxx b/build2/parser.cxx index c443ba5..d01b6fe 100644 --- a/build2/parser.cxx +++ b/build2/parser.cxx @@ -1523,17 +1523,18 @@ namespace build2 auto ptr = [] (const value_type& vt) {return &vt;}; return - n == "bool" ? ptr (value_traits::value_type) : - n == "uint64" ? ptr (value_traits::value_type) : - n == "string" ? ptr (value_traits::value_type) : - n == "path" ? ptr (value_traits::value_type) : - n == "dir_path" ? ptr (value_traits::value_type) : - n == "abs_dir_path" ? ptr (value_traits::value_type) : - n == "name" ? ptr (value_traits::value_type) : - n == "strings" ? ptr (value_traits::value_type) : - n == "paths" ? ptr (value_traits::value_type) : - n == "dir_paths" ? ptr (value_traits::value_type) : - n == "names" ? ptr (value_traits>::value_type) : + n == "bool" ? ptr (value_traits::value_type) : + n == "uint64" ? ptr (value_traits::value_type) : + n == "string" ? ptr (value_traits::value_type) : + n == "path" ? ptr (value_traits::value_type) : + n == "dir_path" ? ptr (value_traits::value_type) : + n == "abs_dir_path" ? ptr (value_traits::value_type) : + n == "name" ? ptr (value_traits::value_type) : + n == "target_triplet" ? ptr (value_traits::value_type) : + n == "strings" ? ptr (value_traits::value_type) : + n == "paths" ? ptr (value_traits::value_type) : + n == "dir_paths" ? ptr (value_traits::value_type) : + n == "names" ? ptr (value_traits>::value_type) : nullptr; } diff --git a/build2/pkgconfig/init.cxx b/build2/pkgconfig/init.cxx index ece0caf..7149eb6 100644 --- a/build2/pkgconfig/init.cxx +++ b/build2/pkgconfig/init.cxx @@ -42,9 +42,11 @@ namespace build2 auto& vp (var_pool); const variable& c_x (vp.insert ("config.pkgconfig", true)); - const variable& c_x_tgt (vp.insert ("config.pkgconfig.target")); const variable& x_path (vp.insert ("pkgconfig.path")); + const variable& c_x_tgt ( + vp.insert ("config.pkgconfig.target")); + // Configure. // @@ -80,9 +82,9 @@ namespace build2 // if (pp.empty ()) { - if (const string* t = cast_null (hints[c_x_tgt])) + if (const auto* t = cast_null (hints[c_x_tgt])) { - d = *t; + d = t->string (); d += "-pkg-config"; l5 ([&]{trace << "trying " << d;}); diff --git a/build2/types b/build2/types index e7ab8ba..f8abef2 100644 --- a/build2/types +++ b/build2/types @@ -32,6 +32,7 @@ #include #include #include +#include namespace build2 { @@ -137,6 +138,10 @@ namespace build2 using butl::auto_fd; using butl::ifdstream; using butl::ofdstream; + + // + // + using butl::target_triplet; } // In order to be found (via ADL) these have to be either in std:: or in diff --git a/build2/variable b/build2/variable index fbb7343..047dc04 100644 --- a/build2/variable +++ b/build2/variable @@ -226,14 +226,13 @@ namespace build2 return reinterpret_cast (data_);} public: - // The maximum size we can store directly in the value is that of names - // (which is a small_vector), which is sufficient for the most + // The maximum size we can store directly is sufficient for the most // commonly used types (string, vector, map) on all the platforms that we // support (each type should static assert this in its value_traits // specialization below). Types that don't fit will have to be handled // with an extra dynamic allocation. // - std::aligned_storage::type data_; + std::aligned_storage::type data_; // VC14 needs decltype. // @@ -666,7 +665,8 @@ namespace build2 template <> struct value_traits { - static_assert (sizeof (process_path) <= value::size_, "insufficient space"); + 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. @@ -681,6 +681,27 @@ namespace build2 static const build2::value_type value_type; }; + + // target_triplet + // + template <> + struct value_traits + { + static_assert (sizeof (target_triplet) <= value::size_, + "insufficient space"); + + static target_triplet convert (name&&, name*); + static void assign (value&, target_triplet&&); + static name reverse (const target_triplet& x) {return name (x.string ());} + static int compare (const target_triplet& x, const target_triplet& y) { + return x.compare (y);} + static bool empty (const target_triplet& x) {return x.empty ();} + + static const bool empty_value = true; + static const char* const type_name; + static const build2::value_type value_type; + }; + // vector // template diff --git a/build2/variable.cxx b/build2/variable.cxx index 1741172..48ea8aa 100644 --- a/build2/variable.cxx +++ b/build2/variable.cxx @@ -858,6 +858,51 @@ namespace build2 &default_empty }; + // target_triplet value + // + target_triplet value_traits:: + convert (name&& n, name* r) + { + if (r == nullptr) + { + if (n.simple ()) + { + try + { + return n.empty () ? target_triplet () : target_triplet (n.value); + } + catch (const invalid_argument& e) + { + throw invalid_argument ( + string ("invalid target_triplet value: ") + e.what ()); + } + } + + // Fall through. + } + + throw_invalid_argument (n, r, "target_triplet"); + } + + const char* const value_traits::type_name = "target_triplet"; + + const value_type value_traits::value_type + { + type_name, + sizeof (target_triplet), + nullptr, // No base. + &default_dtor, + &default_copy_ctor, + &default_copy_assign, + &simple_assign, + nullptr, // Append not supported. + nullptr, // Prepend not supported. + &simple_reverse, + nullptr, // No cast (cast data_ directly). + &simple_compare, + &default_empty + }; + // variable_pool // const variable& variable_pool:: diff --git a/build2/variable.ixx b/build2/variable.ixx index c580a8a..bb97750 100644 --- a/build2/variable.ixx +++ b/build2/variable.ixx @@ -525,6 +525,17 @@ namespace build2 return r; } + // target_triplet value + // + inline void value_traits:: + assign (value& v, target_triplet&& x) + { + if (v) + v.as () = move (x); + else + new (&v.data_) target_triplet (move (x)); + } + // vector value // template diff --git a/unit-tests/function/buildfile b/unit-tests/function/buildfile index 743ef64..5c326b8 100644 --- a/unit-tests/function/buildfile +++ b/unit-tests/function/buildfile @@ -8,7 +8,8 @@ import libs = libbutl%lib{butl} src = token lexer diagnostics utility variable name b-options types-parsers \ context scope parser target operation rule prerequisite file module function \ functions-builtin functions-path functions-process-path functions-string \ -algorithm search dump filesystem config/{utility init operation} +functions-target-triplet algorithm search dump filesystem \ +config/{utility init operation} exe{driver}: cxx{driver} ../../build2/cxx{$src} $libs test{call syntax} diff --git a/unit-tests/test/script/parser/buildfile b/unit-tests/test/script/parser/buildfile index 957222f..d25d9bf 100644 --- a/unit-tests/test/script/parser/buildfile +++ b/unit-tests/test/script/parser/buildfile @@ -10,8 +10,8 @@ import libs = libbutl%lib{butl} src = token lexer parser diagnostics utility variable name context target \ scope prerequisite file module operation rule b-options algorithm search \ filesystem function functions-builtin functions-path functions-process-path \ -functions-string config/{utility init operation} dump types-parsers \ -test/{target script/{token lexer parser regex script}} \ +functions-string functions-target-triplet config/{utility init operation} \ +dump types-parsers test/{target script/{token lexer parser regex script}} \ scheduler exe{driver}: cxx{driver} ../../../../build2/cxx{$src} $libs \ -- cgit v1.1