aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-01-06 17:28:45 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2017-01-06 17:28:45 +0200
commit9f5c4c1ae3bff517eefb39130287016514fb31c7 (patch)
treece230ddff1c623a4b329c3ae74fe6e77243be068
parent6f1d989609ac5d13e204fab3bd85f6364e12edd5 (diff)
Store platform targets as typed target_triplet
-rw-r--r--build2/bin/init.cxx30
-rw-r--r--build2/buildfile171
-rw-r--r--build2/c/init.cxx9
-rw-r--r--build2/cc/common14
-rw-r--r--build2/cc/guess.cxx4
-rw-r--r--build2/cc/init.cxx55
-rw-r--r--build2/cc/link.cxx2
-rw-r--r--build2/cc/module.cxx104
-rw-r--r--build2/context.cxx23
-rw-r--r--build2/cxx/init.cxx9
-rw-r--r--build2/function.cxx12
-rw-r--r--build2/functions-target-triplet.cxx36
-rw-r--r--build2/parser.cxx23
-rw-r--r--build2/pkgconfig/init.cxx8
-rw-r--r--build2/types5
-rw-r--r--build2/variable29
-rw-r--r--build2/variable.cxx45
-rw-r--r--build2/variable.ixx11
-rw-r--r--unit-tests/function/buildfile3
-rw-r--r--unit-tests/test/script/parser/buildfile4
20 files changed, 358 insertions, 239 deletions
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 <map>
-#include <butl/triplet>
-
#include <build2/scope>
#include <build2/variable>
#include <build2/diagnostics>
@@ -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<string> ("config.bin.target", true);
v.insert<string> ("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<string> ("bin.target") = move (canon);
- r.assign<string> ("bin.target.cpu") = move (t.cpu);
- r.assign<string> ("bin.target.vendor") = move (t.vendor);
- r.assign<string> ("bin.target.system") = move (t.system);
- r.assign<string> ("bin.target.version") = move (t.version);
- r.assign<string> ("bin.target.class") = move (t.class_);
+ r.assign<string> ("bin.target.cpu") = t.cpu;
+ r.assign<string> ("bin.target.vendor") = t.vendor;
+ r.assign<string> ("bin.target.system") = t.system;
+ r.assign<string> ("bin.target.version") = t.version;
+ r.assign<string> ("bin.target.class") = t.class_;
+
+ r.assign<target_triplet> ("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<string> (r["bin.target"]);
+ << " target " << cast<target_triplet> (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<string> ("c.signature"),
v.insert<string> ("c.checksum"),
- v.insert<string> ("c.target"),
+ v.insert<target_triplet> ("c.target"),
+
v.insert<string> ("c.target.cpu"),
v.insert<string> ("c.target.vendor"),
v.insert<string> ("c.target.system"),
@@ -235,10 +236,8 @@ namespace build2
"c.install",
"c.uninstall",
- cast<string> (rs[cm.x_id]),
- cast<string> (rs[cm.x_target]),
- cast<string> (rs[cm.x_target_system]),
- cast<string> (rs[cm.x_target_class]),
+ cast<string> (rs[cm.x_id]),
+ cast<target_triplet> (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 <butl/triplet>, we need
- // something in the CPU-VENDOR-OS-ABI form.
+ // them ourselves. Based on the discussion in <butl/target-triplet>,
+ // 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 <build2/cc/init>
-#include <butl/triplet>
-
#include <build2/scope>
#include <build2/context>
#include <build2/diagnostics>
@@ -56,9 +54,9 @@ namespace build2
// Hint variables (not overridable).
//
- v.insert<string> ("config.cc.id");
- v.insert<string> ("config.cc.target");
- v.insert<string> ("config.cc.pattern");
+ v.insert<string> ("config.cc.id");
+ v.insert<string> ("config.cc.pattern");
+ v.insert<target_triplet> ("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<string> (hints["config.cc.target"]));
+ const auto& t (cast<target_triplet> (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<string> ("cc.target") = s;
- rs.assign<string> ("cc.target.cpu") = move (t.cpu);
- rs.assign<string> ("cc.target.vendor") = move (t.vendor);
- rs.assign<string> ("cc.target.system") = move (t.system);
- rs.assign<string> ("cc.target.version") = move (t.version);
- rs.assign<string> ("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<string> ("cc.target.cpu") = t.cpu;
+ rs.assign<string> ("cc.target.vendor") = t.vendor;
+ rs.assign<string> ("cc.target.system") = t.system;
+ rs.assign<string> ("cc.target.version") = t.version;
+ rs.assign<string> ("cc.target.class") = t.class_;
+
+ rs.assign<target_triplet> ("cc.target") = t;
}
// config.cc.pattern
@@ -182,10 +169,11 @@ namespace build2
variable_map h;
if (first)
{
- h.assign ("config.bin.target") = cast<string> (rs["cc.target"]);
+ h.assign ("config.bin.target") =
+ cast<target_triplet> (rs["cc.target"]).string ();
if (auto l = hints["config.bin.pattern"])
- h.assign ("config.bin.pattern") = cast<string> (l);
+ h.assign ("config.bin.pattern") = cast<string> (l);
}
load_module ("bin.config", rs, rs, loc, false, h);
@@ -197,8 +185,8 @@ namespace build2
//
if (first)
{
- const string& ct (cast<string> (rs["cc.target"]));
- const string& bt (cast<string> (rs["bin.target"]));
+ const auto& ct (cast<target_triplet> (rs["cc.target"]));
+ const auto& bt (cast<target_triplet> (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<string> (rs["cc.target"]);
+ h.assign ("config.pkgconfig.target") =
+ cast<target_triplet> (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 <iomanip> // left, setw()
-#include <butl/triplet>
-
#include <build2/scope>
#include <build2/context>
#include <build2/diagnostics>
@@ -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<string> (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<string> (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<string> (rs[x_id]);
- h.assign ("config.cc.target") = cast<string> (rs[x_target]);
+ h.assign ("config.cc.target") = cast<target_triplet> (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<string> (rs[cvar]));
- const string& xv (cast<string> (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<string> (rs["cc.id"]));
+ const auto& xv (cast<string> (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<target_triplet> (rs["cc.target"]));
+ const auto& xv (cast<target_triplet> (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 <sstream>
-#include <butl/triplet>
-
#include <build2/rule>
#include <build2/scope>
#include <build2/target>
@@ -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<string> ("build.host") = move (canon);
- gs.assign<string> ("build.host.cpu") = move (t.cpu);
- gs.assign<string> ("build.host.vendor") = move (t.vendor);
- gs.assign<string> ("build.host.system") = move (t.system);
- gs.assign<string> ("build.host.version") = move (t.version);
- gs.assign<string> ("build.host.class") = move (t.class_);
+ gs.assign<string> ("build.host.cpu") = t.cpu;
+ gs.assign<string> ("build.host.vendor") = t.vendor;
+ gs.assign<string> ("build.host.system") = t.system;
+ gs.assign<string> ("build.host.version") = t.version;
+ gs.assign<string> ("build.host.class") = t.class_;
+
+ gs.assign<target_triplet> ("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<string> ("cxx.signature"),
v.insert<string> ("cxx.checksum"),
- v.insert<string> ("cxx.target"),
+ v.insert<target_triplet> ("cxx.target"),
+
v.insert<string> ("cxx.target.cpu"),
v.insert<string> ("cxx.target.vendor"),
v.insert<string> ("cxx.target.system"),
@@ -305,10 +306,8 @@ namespace build2
"cxx.install",
"cxx.uninstall",
- cast<string> (rs[cm.x_id]),
- cast<string> (rs[cm.x_target]),
- cast<string> (rs[cm.x_target_system]),
- cast<string> (rs[cm.x_target_class]),
+ cast<string> (rs[cm.x_id]),
+ cast<target_triplet> (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 <build2/function>
+#include <build2/variable>
+
+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<string> (move (ur));
+ };
+
+ b[".concat"] = [](names ul, target_triplet r)
+ {
+ return convert<string> (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<bool>::value_type) :
- n == "uint64" ? ptr (value_traits<uint64_t>::value_type) :
- n == "string" ? ptr (value_traits<string>::value_type) :
- n == "path" ? ptr (value_traits<path>::value_type) :
- n == "dir_path" ? ptr (value_traits<dir_path>::value_type) :
- n == "abs_dir_path" ? ptr (value_traits<abs_dir_path>::value_type) :
- n == "name" ? ptr (value_traits<name>::value_type) :
- n == "strings" ? ptr (value_traits<strings>::value_type) :
- n == "paths" ? ptr (value_traits<paths>::value_type) :
- n == "dir_paths" ? ptr (value_traits<dir_paths>::value_type) :
- n == "names" ? ptr (value_traits<vector<name>>::value_type) :
+ n == "bool" ? ptr (value_traits<bool>::value_type) :
+ n == "uint64" ? ptr (value_traits<uint64_t>::value_type) :
+ n == "string" ? ptr (value_traits<string>::value_type) :
+ n == "path" ? ptr (value_traits<path>::value_type) :
+ n == "dir_path" ? ptr (value_traits<dir_path>::value_type) :
+ n == "abs_dir_path" ? ptr (value_traits<abs_dir_path>::value_type) :
+ n == "name" ? ptr (value_traits<name>::value_type) :
+ n == "target_triplet" ? ptr (value_traits<target_triplet>::value_type) :
+ n == "strings" ? ptr (value_traits<strings>::value_type) :
+ n == "paths" ? ptr (value_traits<paths>::value_type) :
+ n == "dir_paths" ? ptr (value_traits<dir_paths>::value_type) :
+ n == "names" ? ptr (value_traits<vector<name>>::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<path> ("config.pkgconfig", true));
- const variable& c_x_tgt (vp.insert<string> ("config.pkgconfig.target"));
const variable& x_path (vp.insert<process_path> ("pkgconfig.path"));
+ const variable& c_x_tgt (
+ vp.insert<target_triplet> ("config.pkgconfig.target"));
+
// Configure.
//
@@ -80,9 +82,9 @@ namespace build2
//
if (pp.empty ())
{
- if (const string* t = cast_null<string> (hints[c_x_tgt]))
+ if (const auto* t = cast_null<target_triplet> (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 <butl/timestamp>
#include <butl/vector-view>
#include <butl/small-vector>
+#include <butl/target-triplet>
namespace build2
{
@@ -137,6 +138,10 @@ namespace build2
using butl::auto_fd;
using butl::ifdstream;
using butl::ofdstream;
+
+ // <butl/target-triplet>
+ //
+ 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<const T&> (data_);}
public:
- // The maximum size we can store directly in the value is that of names
- // (which is a small_vector<name, 1>), 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<sizeof (names)>::type data_;
+ std::aligned_storage<sizeof (string) * 5>::type data_;
// VC14 needs decltype.
//
@@ -666,7 +665,8 @@ namespace build2
template <>
struct value_traits<process_path>
{
- 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<target_triplet>
+ {
+ 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<T>
//
template <typename T>
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<process_path>
};
+ // target_triplet value
+ //
+ target_triplet value_traits<target_triplet>::
+ 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<target_triplet>::type_name = "target_triplet";
+
+ const value_type value_traits<target_triplet>::value_type
+ {
+ type_name,
+ sizeof (target_triplet),
+ nullptr, // No base.
+ &default_dtor<target_triplet>,
+ &default_copy_ctor<target_triplet>,
+ &default_copy_assign<target_triplet>,
+ &simple_assign<target_triplet>,
+ nullptr, // Append not supported.
+ nullptr, // Prepend not supported.
+ &simple_reverse<target_triplet>,
+ nullptr, // No cast (cast data_ directly).
+ &simple_compare<target_triplet>,
+ &default_empty<target_triplet>
+ };
+
// 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<target_triplet>::
+ assign (value& v, target_triplet&& x)
+ {
+ if (v)
+ v.as<target_triplet> () = move (x);
+ else
+ new (&v.data_) target_triplet (move (x));
+ }
+
// vector<T> value
//
template <typename T>
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 \