aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build2/bin/module.cxx32
-rw-r--r--build2/cli/module.cxx6
-rw-r--r--build2/cli/rule.cxx4
-rw-r--r--build2/context.cxx16
-rw-r--r--build2/cxx/compile.cxx8
-rw-r--r--build2/cxx/guess28
-rw-r--r--build2/cxx/guess.cxx159
-rw-r--r--build2/cxx/link.cxx14
-rw-r--r--build2/cxx/module.cxx17
-rw-r--r--build2/dist/module.cxx10
-rw-r--r--build2/dist/operation.cxx14
-rw-r--r--build2/install/module.cxx30
-rw-r--r--build2/install/rule.cxx10
-rw-r--r--build2/variable40
-rw-r--r--build2/variable.cxx79
-rw-r--r--build2/variable.ixx121
16 files changed, 429 insertions, 159 deletions
diff --git a/build2/bin/module.cxx b/build2/bin/module.cxx
index 496b1da..13bf2a8 100644
--- a/build2/bin/module.cxx
+++ b/build2/bin/module.cxx
@@ -47,20 +47,20 @@ namespace build2
{
auto& v (var_pool);
- v.find<string> ("config.bin.ar"); //@@ VAR path_type
- v.find<string> ("config.bin.ranlib"); //@@ VAR path_type
+ v.find<path> ("config.bin.ar");
+ v.find<path> ("config.bin.ranlib");
- v.find<string> ("config.bin.lib");
- v.find<strings> ("config.bin.exe.lib");
- v.find<strings> ("config.bin.liba.lib");
- v.find<strings> ("config.bin.libso.lib");
- v.find<strings> ("config.bin.rpath"); //@@ VAR paths_type
+ v.find<string> ("config.bin.lib");
+ v.find<strings> ("config.bin.exe.lib");
+ v.find<strings> ("config.bin.liba.lib");
+ v.find<strings> ("config.bin.libso.lib");
+ v.find<dir_paths> ("config.bin.rpath");
- v.find<string> ("bin.lib");
- v.find<strings> ("bin.exe.lib");
- v.find<strings> ("bin.liba.lib");
- v.find<strings> ("bin.libso.lib");
- v.find<strings> ("bin.rpath"); //@@ VAR paths_type
+ v.find<string> ("bin.lib");
+ v.find<strings> ("bin.exe.lib");
+ v.find<strings> ("bin.liba.lib");
+ v.find<strings> ("bin.libso.lib");
+ v.find<dir_paths> ("bin.rpath");
v.find<string> ("bin.libprefix");
}
@@ -156,7 +156,7 @@ namespace build2
// See the cxx module for details on merging.
//
if (const value& v = config::optional (r, "config.bin.rpath"))
- b.assign ("bin.rpath") += cast<strings> (v);
+ b.assign ("bin.rpath") += cast<dir_paths> (v);
// config.bin.ar
// config.bin.ranlib
@@ -167,11 +167,11 @@ namespace build2
//
if (first)
{
- auto p (config::required (r, "config.bin.ar", "ar"));
+ auto p (config::required (r, "config.bin.ar", path ("ar")));
auto& v (config::optional (r, "config.bin.ranlib"));
- const path& ar (path (cast<string> (p.first))); // @@ VAR
- const path& ranlib (v ? path (cast<string> (v)) : path ()); // @@ VAR
+ const path& ar (cast<path> (p.first));
+ const path& ranlib (v ? cast<path> (v) : path ());
bin_info bi (guess (ar, ranlib));
diff --git a/build2/cli/module.cxx b/build2/cli/module.cxx
index 4e81908..15c8b90 100644
--- a/build2/cli/module.cxx
+++ b/build2/cli/module.cxx
@@ -57,7 +57,7 @@ namespace build2
v.find<bool> ("config.cli.configured");
- v.find<string> ("config.cli"); //@@ VAR type
+ v.find<path> ("config.cli");
v.find<strings> ("config.cli.options");
v.find<strings> ("cli.options");
@@ -174,13 +174,13 @@ namespace build2
}
else
{
- auto p (config::required (root, "config.cli", cli));
+ auto p (config::required (root, "config.cli", path (cli)));
assert (p.second && cast<string> (p.first) == cli);
}
}
else
{
- auto p (config::required (root, "config.cli", cli));
+ auto p (config::required (root, "config.cli", path (cli)));
// If we actually set a new value, test it by trying to execute.
//
diff --git a/build2/cli/rule.cxx b/build2/cli/rule.cxx
index de14aa1..ece5424 100644
--- a/build2/cli/rule.cxx
+++ b/build2/cli/rule.cxx
@@ -244,9 +244,9 @@ namespace build2
path rels (relative (s->path ()));
scope& rs (t.root_scope ());
- const string& cli (cast<string> (rs["config.cli"]));
+ const path& cli (cast<path> (rs["config.cli"]));
- cstrings args {cli.c_str ()};
+ cstrings args {cli.string ().c_str ()};
// See if we need to pass --output-{prefix,suffix}
//
diff --git a/build2/context.cxx b/build2/context.cxx
index 53ea467..8941f3e 100644
--- a/build2/context.cxx
+++ b/build2/context.cxx
@@ -96,23 +96,21 @@ namespace build2
// Enter the version.
//
- // @@ VAR types
- //
{
- gs.assign<string> ("build.version") = to_string (BUILD2_VERSION);
+ gs.assign<uint64_t> ("build.version") = uint64_t (BUILD2_VERSION);
gs.assign<string> ("build.version.string") = BUILD2_VERSION_STR;
// AABBCCDD
//
- auto comp = [] (unsigned int d) -> string
+ auto comp = [] (unsigned int d) -> uint64_t
{
- return to_string ((BUILD2_VERSION / d)% 100);
+ return (BUILD2_VERSION / d) % 100;
};
- gs.assign<string> ("build.version.release") = comp (1);
- gs.assign<string> ("build.version.patch") = comp (100);
- gs.assign<string> ("build.version.minor") = comp (10000);
- gs.assign<string> ("build.version.major") = comp (1000000);
+ gs.assign<uint64_t> ("build.version.release") = comp (1);
+ gs.assign<uint64_t> ("build.version.patch") = comp (100);
+ gs.assign<uint64_t> ("build.version.minor") = comp (10000);
+ gs.assign<uint64_t> ("build.version.major") = comp (1000000);
}
// Enter the host information. Rather than jumping through hoops like
diff --git a/build2/cxx/compile.cxx b/build2/cxx/compile.cxx
index cf0c91c..c4e9cee 100644
--- a/build2/cxx/compile.cxx
+++ b/build2/cxx/compile.cxx
@@ -461,10 +461,10 @@ namespace build2
auto init_args = [&t, &s, &rs, &args, &cxx_std] ()
{
- const string& cxx (cast<string> (rs["config.cxx"]));
+ const path& cxx (cast<path> (rs["config.cxx"]));
const string& sys (cast<string> (rs["cxx.target.system"]));
- args.push_back (cxx.c_str ());
+ args.push_back (cxx.string ().c_str ());
// Add cxx.export.poptions from prerequisite libraries. Note
// that here we don't need to see group members (see apply()).
@@ -923,10 +923,10 @@ namespace build2
path rels (relative (s->path ()));
scope& rs (t.root_scope ());
- const string& cxx (cast<string> (rs["config.cxx"]));
+ const path& cxx (cast<path> (rs["config.cxx"]));
const string& sys (cast<string> (rs["cxx.target.system"]));
- cstrings args {cxx.c_str ()};
+ cstrings args {cxx.string ().c_str ()};
// Add cxx.export.poptions from prerequisite libraries. Note that
// here we don't need to see group members (see apply()).
diff --git a/build2/cxx/guess b/build2/cxx/guess
index cd9f740..0588523 100644
--- a/build2/cxx/guess
+++ b/build2/cxx/guess
@@ -8,8 +8,6 @@
#include <build2/types>
#include <build2/utility>
-#include <build2/variable>
-
namespace build2
{
namespace cxx
@@ -62,22 +60,18 @@ namespace build2
//
struct compiler_version
{
- std::string major;
- std::string minor;
- std::string patch;
- std::string build;
+ std::string string;
- // The format is always A.B[.C][-D].
+ // Currently all the compilers that we support have numeric MAJOR,
+ // MINOR, and PATCH components and it makes sense to represent them as
+ // integers for easy comparison. If we meet a compiler for which this
+ // doesn't hold, then we will probably just set these to 0 and let the
+ // user deal with the string representation.
//
- std::string
- string () const
- {
- std::string r (major);
- r += '.'; r += minor;
- if (!patch.empty ()) {r += '.'; r += patch;}
- if (!build.empty ()) {r += '-'; r += build;}
- return r;
- }
+ uint64_t major;
+ uint64_t minor;
+ uint64_t patch;
+ std::string build;
};
// C++ compiler information.
@@ -106,7 +100,7 @@ namespace build2
};
compiler_info
- guess (const path& cxx, lookup<const value> coptions); // @@ VAR
+ guess (const path& cxx, const strings* coptions);
}
}
diff --git a/build2/cxx/guess.cxx b/build2/cxx/guess.cxx
index d2f828d..ad52847 100644
--- a/build2/cxx/guess.cxx
+++ b/build2/cxx/guess.cxx
@@ -277,9 +277,7 @@ namespace build2
}
static compiler_info
- guess_gcc (const path& cxx,
- lookup<const value> coptions,
- guess_result&& gr)
+ guess_gcc (const path& cxx, const strings* coptions, guess_result&& gr)
{
tracer trace ("cxx::guess_gcc");
@@ -309,19 +307,27 @@ namespace build2
if (b == e)
fail << "unable to extract gcc version from '" << s << "'";
+ compiler_version v;
+ v.string.assign (s, b, string::npos);
+
// Split the version into components.
//
size_t vb (b), ve (b);
- auto next = [&s, b, e, &vb, &ve] (const char* m) -> string
+ auto next = [&s, b, e, &vb, &ve] (const char* m) -> uint64_t
{
- if (!next_word (s, e, vb, ve, '.'))
- fail << "unable to extract gcc " << m << " version from '"
- << string (s, b, e - b) << "'";
+ try
+ {
+ if (next_word (s, e, vb, ve, '.'))
+ return stoull (string (s, vb, ve - vb));
+ }
+ catch (const invalid_argument&) {}
+ catch (const out_of_range&) {}
- return string (s, vb, ve - vb);
+ error << "unable to extract gcc " << m << " version from '"
+ << string (s, b, e - b) << "'";
+ throw failed ();
};
- compiler_version v;
v.major = next ("major");
v.minor = next ("minor");
v.patch = next ("patch");
@@ -351,7 +357,8 @@ namespace build2
// -dumpmachine (older gcc or not multi-arch).
//
cstrings args {cxx.string ().c_str (), "-print-multiarch"};
- append_options (args, coptions);
+ if (coptions != nullptr)
+ append_options (args, *coptions);
args.push_back (nullptr);
// The output of both -print-multiarch and -dumpmachine is a single line
@@ -383,9 +390,7 @@ namespace build2
}
static compiler_info
- guess_clang (const path& cxx,
- lookup<const value> coptions,
- guess_result&& gr)
+ guess_clang (const path& cxx, const strings* coptions, guess_result&& gr)
{
// Extract the version. Here we will try to handle both vanilla and
// Apple clang since the signature lines are fairly similar. They have
@@ -425,25 +430,33 @@ namespace build2
if (b == e)
fail << "unable to extract clang version from '" << s << "'";
+ compiler_version v;
+ v.string.assign (s, b, string::npos);
+
// Split the version into components.
//
size_t vb (b), ve (b);
- auto next = [&s, b, e, &vb, &ve] (const char* m) -> string
+ auto next = [&s, b, e, &vb, &ve] (const char* m, bool opt) -> uint64_t
{
- if (next_word (s, e, vb, ve, '.'))
- return string (s, vb, ve - vb);
+ try
+ {
+ if (next_word (s, e, vb, ve, '.'))
+ return stoull (string (s, vb, ve - vb));
- if (m != nullptr)
- fail << "unable to extract clang " << m << " version from '"
- << string (s, b, e - b) << "'";
+ if (opt)
+ return 0;
+ }
+ catch (const invalid_argument&) {}
+ catch (const out_of_range&) {}
- return string ();
+ error << "unable to extract clang " << m << " version from '"
+ << string (s, b, e - b) << "'";
+ throw failed ();
};
- compiler_version v;
- v.major = next ("major");
- v.minor = next ("minor");
- v.patch = next (gr.id.variant == "apple" ? nullptr : "patch");
+ v.major = next ("major", false);
+ v.minor = next ("minor", false);
+ v.patch = next ("patch", gr.id.variant == "apple");
if (e != s.size ())
v.build.assign (s, e + 1, string::npos);
@@ -454,7 +467,8 @@ namespace build2
// however, respects the compile options (e.g., -m32).
//
cstrings args {cxx.string ().c_str (), "-dumpmachine"};
- append_options (args, coptions);
+ if (coptions != nullptr)
+ append_options (args, *coptions);
args.push_back (nullptr);
// The output of -dumpmachine is a single line containing just the
@@ -475,9 +489,7 @@ namespace build2
}
static compiler_info
- guess_icc (const path& cxx,
- lookup<const value> coptions,
- guess_result&& gr)
+ guess_icc (const path& cxx, const strings* coptions, guess_result&& gr)
{
// Extract the version. If the version has the fourth component, then
// the signature line (extracted with --version) won't include it. So we
@@ -513,7 +525,9 @@ namespace build2
: string ();
};
- s = run<string> (cxx, "-V", f);
+ // The -V output is sent to STDERR.
+ //
+ s = run<string> (cxx, "-V", f, false);
if (s.empty ())
fail << "unable to extract signature from " << cxx << " -V output";
@@ -553,27 +567,36 @@ namespace build2
if (b == e)
fail << "unable to extract icc version from '" << s << "'";
+ compiler_version v;
+ v.string.assign (s, b, string::npos);
+
// Split the version into components.
//
size_t vb (b), ve (b);
- auto next = [&s, b, e, &vb, &ve] (const char* m) -> string
+ auto next = [&s, b, e, &vb, &ve] (const char* m, bool opt) -> uint64_t
{
- if (next_word (s, e, vb, ve, '.'))
- return string (s, vb, ve - vb);
+ try
+ {
+ if (next_word (s, e, vb, ve, '.'))
+ return stoull (string (s, vb, ve - vb));
- if (m != nullptr)
- fail << "unable to extract icc " << m << " version from '"
- << string (s, b, e - b) << "'";
+ if (opt)
+ return 0;
+ }
+ catch (const invalid_argument&) {}
+ catch (const out_of_range&) {}
- return "";
+ error << "unable to extract icc " << m << " version from '"
+ << string (s, b, e - b) << "'";
+ throw failed ();
};
- compiler_version v;
- v.major = next ("major");
- v.minor = next ("minor");
- v.patch = next (nullptr);
- if (!v.patch.empty ())
- v.build = next (nullptr);
+ v.major = next ("major", false);
+ v.minor = next ("minor", false);
+ v.patch = next ("patch", true);
+
+ if (vb != ve && next_word (s, e, vb, ve, '.'))
+ v.build.assign (s, vb, ve - vb);
if (e != s.size ())
{
@@ -597,10 +620,13 @@ namespace build2
// "Intel(R)" "MIC" (-dumpmachine says: x86_64-k1om-linux)
//
cstrings args {cxx.string ().c_str (), "-V"};
- append_options (args, coptions);
+ if (coptions != nullptr)
+ append_options (args, *coptions);
args.push_back (nullptr);
- string t (run<string> (args.data (), f));
+ // The -V output is sent to STDERR.
+ //
+ string t (run<string> (args.data (), f, false));
if (t.empty ())
fail << "unable to extract target architecture from " << cxx
@@ -735,26 +761,33 @@ namespace build2
if (b == e)
fail << "unable to extract msvc version from '" << s << "'";
+ compiler_version v;
+ v.string.assign (s, b, e - b);
+
// Split the version into components.
//
size_t vb (b), ve (b);
- auto next = [&s, b, e, &vb, &ve] (const char* m) -> string
+ auto next = [&s, b, e, &vb, &ve] (const char* m) -> uint64_t
{
- if (next_word (s, e, vb, ve, '.'))
- return string (s, vb, ve - vb);
-
- if (m != nullptr)
- fail << "unable to extract msvc " << m << " version from '"
- << string (s, b, e - b) << "'";
+ try
+ {
+ if (next_word (s, e, vb, ve, '.'))
+ return stoull (string (s, vb, ve - vb));
+ }
+ catch (const invalid_argument&) {}
+ catch (const out_of_range&) {}
- return "";
+ error << "unable to extract msvc " << m << " version from '"
+ << string (s, b, e - b) << "'";
+ throw failed ();
};
- compiler_version v;
v.major = next ("major");
v.minor = next ("minor");
v.patch = next ("patch");
- v.build = next (nullptr);
+
+ if (next_word (s, e, vb, ve, '.'))
+ v.build.assign (s, vb, ve - vb);
// Continue scanning for the CPU.
//
@@ -837,14 +870,14 @@ namespace build2
// 14.00 80/8.0 VS2005
// 13.10 71/7.1 VS2003
//
- /**/ if (v.major == "19" && v.minor == "00") arch += "14.0";
- else if (v.major == "18" && v.minor == "00") arch += "12.0";
- else if (v.major == "17" && v.minor == "00") arch += "11.0";
- else if (v.major == "16" && v.minor == "00") arch += "10.0";
- else if (v.major == "15" && v.minor == "00") arch += "9.0";
- else if (v.major == "14" && v.minor == "00") arch += "8.0";
- else if (v.major == "13" && v.minor == "10") arch += "7.1";
- else fail << "unable to map msvc compiler version '" << v.string ()
+ /**/ if (v.major == 19 && v.minor == 0) arch += "14.0";
+ else if (v.major == 18 && v.minor == 0) arch += "12.0";
+ else if (v.major == 17 && v.minor == 0) arch += "11.0";
+ else if (v.major == 16 && v.minor == 0) arch += "10.0";
+ else if (v.major == 15 && v.minor == 0) arch += "9.0";
+ else if (v.major == 14 && v.minor == 0) arch += "8.0";
+ else if (v.major == 13 && v.minor == 10) arch += "7.1";
+ else fail << "unable to map msvc compiler version '" << v.string
<< "' to runtime version";
}
@@ -861,7 +894,7 @@ namespace build2
}
compiler_info
- guess (const path& cxx, lookup<const value> coptions)
+ guess (const path& cxx, const strings* coptions)
{
string pre (pre_guess (cxx));
guess_result gr;
diff --git a/build2/cxx/link.cxx b/build2/cxx/link.cxx
index c0ea6d3..aa60c7e 100644
--- a/build2/cxx/link.cxx
+++ b/build2/cxx/link.cxx
@@ -123,7 +123,7 @@ namespace build2
cstrings args;
string std_storage;
- args.push_back (cast<string> (rs["config.cxx"]).c_str ());
+ args.push_back (cast<path> (rs["config.cxx"]).string ().c_str ());
append_options (args, bs, "cxx.coptions");
append_std (args, bs, std_storage);
append_options (args, bs, "cxx.loptions");
@@ -877,8 +877,8 @@ namespace build2
// precedence.
//
if (auto l = t["bin.rpath"])
- for (const string& p: cast<strings> (l))
- sargs.push_back ("-Wl,-rpath," + p);
+ for (const dir_path& p: cast<dir_paths> (l))
+ sargs.push_back ("-Wl,-rpath," + p.string ());
// Then the paths of the shared libraries we are linking to. Unless
// this is update for install, in which case we have to do something
@@ -978,12 +978,12 @@ namespace build2
if (lt == type::a)
{
- args[0] = cast<string> (rs["config.bin.ar"]).c_str ();
+ args[0] = cast<path> (rs["config.bin.ar"]).string ().c_str ();
args.push_back (relt.string ().c_str ());
}
else
{
- args[0] = cast<string> (rs["config.cxx"]).c_str ();
+ args[0] = cast<path> (rs["config.cxx"]).string ().c_str ();
args.push_back ("-o");
args.push_back (relt.string ().c_str ());
}
@@ -1048,7 +1048,9 @@ namespace build2
if (ranlib)
{
const char* args[] = {
- cast<string> (ranlib).c_str (), relt.string ().c_str (), nullptr};
+ cast<path> (ranlib).string ().c_str (),
+ relt.string ().c_str (),
+ nullptr};
if (verb >= 2)
print_process (args);
diff --git a/build2/cxx/module.cxx b/build2/cxx/module.cxx
index 18f9e53..7b0f04e 100644
--- a/build2/cxx/module.cxx
+++ b/build2/cxx/module.cxx
@@ -62,7 +62,7 @@ namespace build2
{
auto& v (var_pool);
- v.find<string> ("config.cxx"); //@@ VAR type
+ v.find<path> ("config.cxx");
v.find<strings> ("config.cxx.poptions");
v.find<strings> ("config.cxx.coptions");
@@ -172,12 +172,12 @@ namespace build2
//
if (first)
{
- auto p (config::required (r, "config.cxx", "g++"));
+ auto p (config::required (r, "config.cxx", path ("g++")));
// Figure out which compiler we are dealing with, its target, etc.
//
- const path& cxx (path (cast<string> (p.first))); // @@ VAR
- compiler_info ci (guess (cxx, r["cxx.coptions"]));
+ const path& cxx (cast<path> (p.first));
+ compiler_info ci (guess (cxx, cast_null<strings> (r["cxx.coptions"])));
// If this is a new value (e.g., we are configuring), then print the
// report at verbosity level 2 and up (-v).
@@ -188,6 +188,7 @@ namespace build2
text << cxx << ":\n"
<< " id " << ci.id << "\n"
+ << " version " << ci.version.string << "\n"
<< " major " << ci.version.major << "\n"
<< " minor " << ci.version.minor << "\n"
<< " patch " << ci.version.patch << "\n"
@@ -201,10 +202,10 @@ namespace build2
r.assign<string> ("cxx.id.type") = move (ci.id.type);
r.assign<string> ("cxx.id.variant") = move (ci.id.variant);
- r.assign<string> ("cxx.version") = ci.version.string ();
- r.assign<string> ("cxx.version.major") = move (ci.version.major);
- r.assign<string> ("cxx.version.minor") = move (ci.version.minor);
- r.assign<string> ("cxx.version.patch") = move (ci.version.patch);
+ r.assign<string> ("cxx.version") = move (ci.version.string);
+ r.assign<uint64_t> ("cxx.version.major") = ci.version.major;
+ r.assign<uint64_t> ("cxx.version.minor") = ci.version.minor;
+ r.assign<uint64_t> ("cxx.version.patch") = ci.version.patch;
r.assign<string> ("cxx.version.build") = move (ci.version.build);
r.assign<string> ("cxx.signature") = move (ci.signature);
diff --git a/build2/dist/module.cxx b/build2/dist/module.cxx
index 6f40b33..ab8c5a3 100644
--- a/build2/dist/module.cxx
+++ b/build2/dist/module.cxx
@@ -46,10 +46,8 @@ namespace build2
v.find<dir_path> ("dist.root");
v.find<dir_path> ("config.dist.root");
- //@@ VAR type
- //
- v.find<string> ("dist.cmd");
- v.find<string> ("config.dist.cmd");
+ v.find<path> ("dist.cmd");
+ v.find<path> ("config.dist.cmd");
v.find<strings> ("dist.archives");
v.find<strings> ("config.dist.archives");
@@ -112,13 +110,13 @@ namespace build2
if (s)
{
const value& cv (
- config::required (r, "config.dist.cmd", "install").first);
+ config::required (r, "config.dist.cmd", path ("install")).first);
if (cv && !cv.empty ())
v = cv;
}
else
- v = "install";
+ v = path ("install");
}
// dist.archives
diff --git a/build2/dist/operation.cxx b/build2/dist/operation.cxx
index cb418be..11ee313 100644
--- a/build2/dist/operation.cxx
+++ b/build2/dist/operation.cxx
@@ -49,12 +49,12 @@ namespace build2
// install -d <dir>
//
static void
- install (const string& cmd, const dir_path&);
+ install (const path& cmd, const dir_path&);
// install <file> <dir>
//
static void
- install (const string& cmd, file&, const dir_path&);
+ install (const path& cmd, file&, const dir_path&);
// cd <root> && tar|zip ... <pkg>.<ext> <pkg>
//
@@ -103,7 +103,7 @@ namespace build2
info << "did you forget to set dist.package?";
const string& dist_package (cast<string> (l));
- const string& dist_cmd (cast<string> (rs->vars["dist.cmd"]));
+ const path& dist_cmd (cast<path> (rs->vars["dist.cmd"]));
// Get the list of operations supported by this project. Skip
// default_id.
@@ -303,11 +303,11 @@ namespace build2
// install -d <dir>
//
static void
- install (const string& cmd, const dir_path& d)
+ install (const path& cmd, const dir_path& d)
{
path reld (relative (d));
- cstrings args {cmd.c_str (), "-d"};
+ cstrings args {cmd.string ().c_str (), "-d"};
args.push_back ("-m");
args.push_back ("755");
@@ -340,12 +340,12 @@ namespace build2
// install <file> <dir>
//
static void
- install (const string& cmd, file& t, const dir_path& d)
+ install (const path& cmd, file& t, const dir_path& d)
{
path reld (relative (d));
path relf (relative (t.path ()));
- cstrings args {cmd.c_str ()};
+ cstrings args {cmd.string ().c_str ()};
// Preserve timestamps. This could becomes important if, for
// example, we have pre-generated sources. Note that the
diff --git a/build2/install/module.cxx b/build2/install/module.cxx
index 3890901..0c17c05 100644
--- a/build2/install/module.cxx
+++ b/build2/install/module.cxx
@@ -77,21 +77,23 @@ namespace build2
}
static void
- set_dir (bool s, // specified
- scope& r, // root scope
- const char* n, // var name
- const string& ps, // path (as string)
- const string& fm = string (), // file mode
- const string& dm = string (), // dir mode
- const string& c = string (), // command
- bool o = false) // override
+ set_dir (bool s, // specified
+ scope& r, // root scope
+ const char* n, // var name
+ const string& ps, // path (as string)
+ const string& fm = string (), // file mode
+ const string& dm = string (), // dir mode
+ const build2::path& c = build2::path (), // command
+ bool o = false) // override
{
+ using build2::path;
+
dir_path p (ps);
set_var (s, r, n, "", p.empty () ? nullptr : &p, o);
set_var (s, r, n, ".mode", fm.empty () ? nullptr : &fm);
set_var (s, r, n, ".dir_mode", dm.empty () ? nullptr : &dm);
set_var<string> (s, r, n, ".sudo", nullptr);
- set_var (s, r, n, ".cmd", c.empty () ? nullptr : &c);
+ set_var<path> (s, r, n, ".cmd", c.empty () ? nullptr : &c);
set_var<strings> (s, r, n, ".options", nullptr);
}
@@ -153,22 +155,24 @@ namespace build2
//
if (first)
{
+ using build2::path;
+
bool s (config::specified (r, "config.install"));
const string& n (cast<string> (r["project"]));
- set_dir (s, r, "root", "", "", "755", "install");
+ set_dir (s, r, "root", "", "", "755", path ("install"));
set_dir (s, r, "data_root", "root", "644");
set_dir (s, r, "exec_root", "root", "755");
set_dir (s, r, "sbin", "exec_root/sbin");
set_dir (s, r, "bin", "exec_root/bin");
set_dir (s, r, "lib", "exec_root/lib");
- set_dir (s, r, "libexec", "exec_root/libexec/" + n, "", "", "", true);
+ set_dir (s, r, "libexec", "exec_root/libexec/" + n, "", "", path (), true);
- set_dir (s, r, "data", "data_root/share/" + n, "", "", "", true);
+ set_dir (s, r, "data", "data_root/share/" + n, "", "", path (), true);
set_dir (s, r, "include", "data_root/include");
- set_dir (s, r, "doc", "data_root/share/doc/" + n, "", "", "", true);
+ set_dir (s, r, "doc", "data_root/share/doc/" + n, "", "", path (), true);
set_dir (s, r, "man", "data_root/share/man");
set_dir (s, r, "man1", "man/man1");
diff --git a/build2/install/rule.cxx b/build2/install/rule.cxx
index 25259cf..e756fc2 100644
--- a/build2/install/rule.cxx
+++ b/build2/install/rule.cxx
@@ -221,7 +221,7 @@ namespace build2
dir_path dir;
string sudo;
- string cmd; //@@ VAR type
+ path cmd;
strings options;
string mode;
string dir_mode;
@@ -239,7 +239,7 @@ namespace build2
if (!base.sudo.empty ())
args.push_back (base.sudo.c_str ());
- args.push_back (base.cmd.c_str ());
+ args.push_back (base.cmd.string ().c_str ());
args.push_back ("-d");
if (!base.options.empty ())
@@ -286,7 +286,7 @@ namespace build2
if (!base.sudo.empty ())
args.push_back (base.sudo.c_str ());
- args.push_back (base.cmd.c_str ());
+ args.push_back (base.cmd.string ().c_str ());
if (!base.options.empty ())
append_options (args, base.options);
@@ -359,7 +359,7 @@ namespace build2
if (var != nullptr)
{
if (auto l = s[*var + ".sudo"]) r.sudo = cast<string> (l);
- if (auto l = s[*var + ".cmd"]) r.cmd = cast<string> (l);
+ if (auto l = s[*var + ".cmd"]) r.cmd = cast<path> (l);
if (auto l = s[*var + ".mode"]) r.mode = cast<string> (l);
if (auto l = s[*var + ".dir_mode"]) r.dir_mode = cast<string> (l);
if (auto l = s[*var + ".options"]) r.options = cast<strings> (l);
@@ -367,7 +367,7 @@ namespace build2
// Set defaults for unspecified components.
//
- if (r.cmd.empty ()) r.cmd = "install";
+ if (r.cmd.empty ()) r.cmd = path ("install");
if (r.mode.empty ()) r.mode = "644";
if (r.dir_mode.empty ()) r.dir_mode = "755";
diff --git a/build2/variable b/build2/variable
index 57debfa..931b4f7 100644
--- a/build2/variable
+++ b/build2/variable
@@ -200,6 +200,15 @@ namespace build2
template <typename T> T& cast (const lookup<value>&);
template <typename T> const T& cast (const lookup<const value>&);
+ // As above but returns NULL if the value is NULL (or not defined, in
+ // case of lookup).
+ //
+ template <typename T> T* cast_null (value&);
+ template <typename T> const T* cast_null (const value&);
+
+ template <typename T> T* cast_null (const lookup<value>&);
+ template <typename T> const T* cast_null (const lookup<const value>&);
+
// Assign value type to the value. Variable is normally only used for
// diagnostics.
//
@@ -367,6 +376,20 @@ namespace build2
static const build2::value_type value_type;
};
+ template <>
+ struct value_traits<uint64_t>
+ {
+ static_assert (sizeof (uint64_t) <= value::size_, "insufficient space");
+
+ static uint64_t convert (name&&, name*);
+ static bool assign (value&, uint64_t);
+ static bool append (value&, uint64_t); // ADD.
+ static name reverse (uint64_t x) {return name (to_string (x));}
+ static int compare (uint64_t, uint64_t);
+
+ static const build2::value_type value_type;
+ };
+
// string
//
template <>
@@ -384,6 +407,23 @@ namespace build2
static const build2::value_type value_type;
};
+ // path
+ //
+ template <>
+ struct value_traits<path>
+ {
+ static_assert (sizeof (path) <= value::size_, "insufficient space");
+
+ static path convert (name&&, name*);
+ static bool assign (value&, path&&);
+ static bool append (value&, path&&); // operator/
+ static bool prepend (value&, path&&); // operator/
+ static name reverse (const path& x) {return name (x.string ());}
+ static int compare (const path&, const path&);
+
+ static const build2::value_type value_type;
+ };
+
// dir_path
//
template <>
diff --git a/build2/variable.cxx b/build2/variable.cxx
index c15a773..7b7f16d 100644
--- a/build2/variable.cxx
+++ b/build2/variable.cxx
@@ -316,6 +316,43 @@ namespace build2
nullptr // No compare (compare as POD).
};
+ // uint64_t value
+ //
+ uint64_t value_traits<uint64_t>::
+ convert (name&& n, name* r)
+ {
+ if (r == nullptr && n.simple ())
+ {
+ try
+ {
+ // May throw invalid_argument or out_of_range.
+ //
+ return stoull (n.value);
+ }
+ catch (const out_of_range&)
+ {
+ // Fall through.
+ }
+ }
+
+ throw invalid_argument (string ());
+ }
+
+ const value_type value_traits<uint64_t>::value_type
+ {
+ "uint64",
+ sizeof (uint64_t),
+ nullptr, // No dtor (POD).
+ nullptr, // No copy_ctor (POD).
+ nullptr, // No copy_assign (POD).
+ &simple_assign<uint64_t, false>, // No empty value.
+ &simple_append<uint64_t, false>,
+ &simple_append<uint64_t, false>, // Prepend same as append.
+ &simple_reverse<uint64_t>,
+ nullptr, // No cast (cast data_ directly).
+ nullptr // No compare (compare as POD).
+ };
+
// string value
//
string value_traits<string>::
@@ -399,6 +436,48 @@ namespace build2
&simple_compare<string>
};
+ // path value
+ //
+ path value_traits<path>::
+ convert (name&& n, name* r)
+ {
+ if (r == nullptr)
+ {
+ // A directory path is a path.
+ //
+ if (n.directory ())
+ return move (n.dir);
+
+ if (n.simple ())
+ {
+ try
+ {
+ return path (move (n.value));
+ }
+ catch (const invalid_path&) {} // Fall through.
+ }
+
+ // Fall through.
+ }
+
+ throw invalid_argument (string ());
+ }
+
+ const value_type value_traits<path>::value_type
+ {
+ "path",
+ sizeof (path),
+ &default_dtor<path>,
+ &default_copy_ctor<path>,
+ &default_copy_assign<path>,
+ &simple_assign<path, true>, // Allow empty paths.
+ &simple_append<path, true>,
+ &simple_prepend<path, true>,
+ &simple_reverse<path>,
+ nullptr, // No cast (cast data_ directly).
+ &simple_compare<path>
+ };
+
// dir_path value
//
dir_path value_traits<dir_path>::
diff --git a/build2/variable.ixx b/build2/variable.ixx
index 8a03996..67f8c56 100644
--- a/build2/variable.ixx
+++ b/build2/variable.ixx
@@ -118,6 +118,34 @@ namespace build2
}
template <typename T>
+ inline T*
+ cast_null (value& v)
+ {
+ return v ? &cast<T> (v) : nullptr;
+ }
+
+ template <typename T>
+ inline const T*
+ cast_null (const value& v)
+ {
+ return v ? &cast<T> (v) : nullptr;
+ }
+
+ template <typename T>
+ inline T*
+ cast_null (const lookup<value>& l)
+ {
+ return l ? &cast<T> (*l) : nullptr;
+ }
+
+ template <typename T>
+ inline const T*
+ cast_null (const lookup<const value>& l)
+ {
+ return l ? &cast<T> (*l) : nullptr;
+ }
+
+ template <typename T>
inline void
typify (value& v, const variable& var)
{
@@ -184,6 +212,38 @@ namespace build2
return l < r ? -1 : (l > r ? 1 : 0);
}
+ // uint64_t value
+ //
+ inline bool value_traits<uint64_t>::
+ assign (value& v, uint64_t x)
+ {
+ if (v.null ())
+ new (&v.data_) uint64_t (x);
+ else
+ v.as<uint64_t> () = x;
+
+ return true;
+ }
+
+ inline bool value_traits<uint64_t>::
+ append (value& v, uint64_t x)
+ {
+ // ADD.
+ //
+ if (v.null ())
+ new (&v.data_) uint64_t (x);
+ else
+ v.as<uint64_t> () += x;
+
+ return true;
+ }
+
+ inline int value_traits<uint64_t>::
+ compare (uint64_t l, uint64_t r)
+ {
+ return l < r ? -1 : (l > r ? 1 : 0);
+ }
+
// string value
//
inline bool value_traits<string>::
@@ -245,6 +305,67 @@ namespace build2
return l.compare (r);
}
+ // path value
+ //
+ inline bool value_traits<path>::
+ assign (value& v, path&& x)
+ {
+ path* p;
+
+ if (v.null ())
+ p = new (&v.data_) path (move (x));
+ else
+ p = &(v.as<path> () = move (x));
+
+ return !p->empty ();
+ }
+
+ inline bool value_traits<path>::
+ append (value& v, path&& x)
+ {
+ path* p;
+
+ if (v.null ())
+ p = new (&v.data_) path (move (x));
+ else
+ {
+ p = &v.as<path> ();
+
+ if (p->empty ())
+ p->swap (x);
+ else
+ *p /= x;
+ }
+
+ return !p->empty ();
+ }
+
+ inline bool value_traits<path>::
+ prepend (value& v, path&& x)
+ {
+ path* p;
+
+ if (v.null ())
+ new (&v.data_) path (move (x));
+ else
+ {
+ p = &v.as<path> ();
+
+ if (!p->empty ())
+ x /= *p;
+
+ p->swap (x);
+ }
+
+ return !p->empty ();
+ }
+
+ inline int value_traits<path>::
+ compare (const path& l, const path& r)
+ {
+ return l.compare (r);
+ }
+
// dir_path value
//
inline bool value_traits<dir_path>::