From 96f2131e593e206f0e458409f22adfff8c1b5356 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 28 Mar 2016 15:59:06 +0200 Subject: Clean up variable usage --- build2/bin/module.cxx | 32 +++++----- build2/cli/module.cxx | 6 +- build2/cli/rule.cxx | 4 +- build2/context.cxx | 16 ++--- build2/cxx/compile.cxx | 8 +-- build2/cxx/guess | 28 ++++---- build2/cxx/guess.cxx | 159 ++++++++++++++++++++++++++++------------------ build2/cxx/link.cxx | 14 ++-- build2/cxx/module.cxx | 17 ++--- build2/dist/module.cxx | 10 ++- build2/dist/operation.cxx | 14 ++-- build2/install/module.cxx | 30 +++++---- build2/install/rule.cxx | 10 +-- build2/variable | 40 ++++++++++++ build2/variable.cxx | 79 +++++++++++++++++++++++ build2/variable.ixx | 121 +++++++++++++++++++++++++++++++++++ 16 files changed, 429 insertions(+), 159 deletions(-) (limited to 'build2') 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 ("config.bin.ar"); //@@ VAR path_type - v.find ("config.bin.ranlib"); //@@ VAR path_type + v.find ("config.bin.ar"); + v.find ("config.bin.ranlib"); - v.find ("config.bin.lib"); - v.find ("config.bin.exe.lib"); - v.find ("config.bin.liba.lib"); - v.find ("config.bin.libso.lib"); - v.find ("config.bin.rpath"); //@@ VAR paths_type + v.find ("config.bin.lib"); + v.find ("config.bin.exe.lib"); + v.find ("config.bin.liba.lib"); + v.find ("config.bin.libso.lib"); + v.find ("config.bin.rpath"); - v.find ("bin.lib"); - v.find ("bin.exe.lib"); - v.find ("bin.liba.lib"); - v.find ("bin.libso.lib"); - v.find ("bin.rpath"); //@@ VAR paths_type + v.find ("bin.lib"); + v.find ("bin.exe.lib"); + v.find ("bin.liba.lib"); + v.find ("bin.libso.lib"); + v.find ("bin.rpath"); v.find ("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 (v); + b.assign ("bin.rpath") += cast (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 (p.first))); // @@ VAR - const path& ranlib (v ? path (cast (v)) : path ()); // @@ VAR + const path& ar (cast (p.first)); + const path& ranlib (v ? cast (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 ("config.cli.configured"); - v.find ("config.cli"); //@@ VAR type + v.find ("config.cli"); v.find ("config.cli.options"); v.find ("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 (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 (rs["config.cli"])); + const path& cli (cast (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 ("build.version") = to_string (BUILD2_VERSION); + gs.assign ("build.version") = uint64_t (BUILD2_VERSION); gs.assign ("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 ("build.version.release") = comp (1); - gs.assign ("build.version.patch") = comp (100); - gs.assign ("build.version.minor") = comp (10000); - gs.assign ("build.version.major") = comp (1000000); + gs.assign ("build.version.release") = comp (1); + gs.assign ("build.version.patch") = comp (100); + gs.assign ("build.version.minor") = comp (10000); + gs.assign ("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 (rs["config.cxx"])); + const path& cxx (cast (rs["config.cxx"])); const string& sys (cast (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 (rs["config.cxx"])); + const path& cxx (cast (rs["config.cxx"])); const string& sys (cast (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 #include -#include - 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 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 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 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 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 (cxx, "-V", f); + // The -V output is sent to STDERR. + // + s = run (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 (args.data (), f)); + // The -V output is sent to STDERR. + // + string t (run (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 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 (rs["config.cxx"]).c_str ()); + args.push_back (cast (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 (l)) - sargs.push_back ("-Wl,-rpath," + p); + for (const dir_path& p: cast (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 (rs["config.bin.ar"]).c_str (); + args[0] = cast (rs["config.bin.ar"]).string ().c_str (); args.push_back (relt.string ().c_str ()); } else { - args[0] = cast (rs["config.cxx"]).c_str (); + args[0] = cast (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 (ranlib).c_str (), relt.string ().c_str (), nullptr}; + cast (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 ("config.cxx"); //@@ VAR type + v.find ("config.cxx"); v.find ("config.cxx.poptions"); v.find ("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 (p.first))); // @@ VAR - compiler_info ci (guess (cxx, r["cxx.coptions"])); + const path& cxx (cast (p.first)); + compiler_info ci (guess (cxx, cast_null (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 ("cxx.id.type") = move (ci.id.type); r.assign ("cxx.id.variant") = move (ci.id.variant); - r.assign ("cxx.version") = ci.version.string (); - r.assign ("cxx.version.major") = move (ci.version.major); - r.assign ("cxx.version.minor") = move (ci.version.minor); - r.assign ("cxx.version.patch") = move (ci.version.patch); + r.assign ("cxx.version") = move (ci.version.string); + r.assign ("cxx.version.major") = ci.version.major; + r.assign ("cxx.version.minor") = ci.version.minor; + r.assign ("cxx.version.patch") = ci.version.patch; r.assign ("cxx.version.build") = move (ci.version.build); r.assign ("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 ("dist.root"); v.find ("config.dist.root"); - //@@ VAR type - // - v.find ("dist.cmd"); - v.find ("config.dist.cmd"); + v.find ("dist.cmd"); + v.find ("config.dist.cmd"); v.find ("dist.archives"); v.find ("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 // static void - install (const string& cmd, const dir_path&); + install (const path& cmd, const dir_path&); // install // static void - install (const string& cmd, file&, const dir_path&); + install (const path& cmd, file&, const dir_path&); // cd && tar|zip ... . // @@ -103,7 +103,7 @@ namespace build2 info << "did you forget to set dist.package?"; const string& dist_package (cast (l)); - const string& dist_cmd (cast (rs->vars["dist.cmd"])); + const path& dist_cmd (cast (rs->vars["dist.cmd"])); // Get the list of operations supported by this project. Skip // default_id. @@ -303,11 +303,11 @@ namespace build2 // install -d // 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 // 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 (s, r, n, ".sudo", nullptr); - set_var (s, r, n, ".cmd", c.empty () ? nullptr : &c); + set_var (s, r, n, ".cmd", c.empty () ? nullptr : &c); set_var (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 (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 (l); - if (auto l = s[*var + ".cmd"]) r.cmd = cast (l); + if (auto l = s[*var + ".cmd"]) r.cmd = cast (l); if (auto l = s[*var + ".mode"]) r.mode = cast (l); if (auto l = s[*var + ".dir_mode"]) r.dir_mode = cast (l); if (auto l = s[*var + ".options"]) r.options = cast (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 T& cast (const lookup&); template const T& cast (const lookup&); + // As above but returns NULL if the value is NULL (or not defined, in + // case of lookup). + // + template T* cast_null (value&); + template const T* cast_null (const value&); + + template T* cast_null (const lookup&); + template const T* cast_null (const lookup&); + // 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 + { + 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 + { + 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:: + 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::value_type + { + "uint64", + sizeof (uint64_t), + nullptr, // No dtor (POD). + nullptr, // No copy_ctor (POD). + nullptr, // No copy_assign (POD). + &simple_assign, // No empty value. + &simple_append, + &simple_append, // Prepend same as append. + &simple_reverse, + nullptr, // No cast (cast data_ directly). + nullptr // No compare (compare as POD). + }; + // string value // string value_traits:: @@ -399,6 +436,48 @@ namespace build2 &simple_compare }; + // path value + // + path value_traits:: + 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::value_type + { + "path", + sizeof (path), + &default_dtor, + &default_copy_ctor, + &default_copy_assign, + &simple_assign, // Allow empty paths. + &simple_append, + &simple_prepend, + &simple_reverse, + nullptr, // No cast (cast data_ directly). + &simple_compare + }; + // dir_path value // dir_path value_traits:: 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 + inline T* + cast_null (value& v) + { + return v ? &cast (v) : nullptr; + } + + template + inline const T* + cast_null (const value& v) + { + return v ? &cast (v) : nullptr; + } + + template + inline T* + cast_null (const lookup& l) + { + return l ? &cast (*l) : nullptr; + } + + template + inline const T* + cast_null (const lookup& l) + { + return l ? &cast (*l) : nullptr; + } + + template 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:: + assign (value& v, uint64_t x) + { + if (v.null ()) + new (&v.data_) uint64_t (x); + else + v.as () = x; + + return true; + } + + inline bool value_traits:: + append (value& v, uint64_t x) + { + // ADD. + // + if (v.null ()) + new (&v.data_) uint64_t (x); + else + v.as () += x; + + return true; + } + + inline int value_traits:: + compare (uint64_t l, uint64_t r) + { + return l < r ? -1 : (l > r ? 1 : 0); + } + // string value // inline bool value_traits:: @@ -245,6 +305,67 @@ namespace build2 return l.compare (r); } + // path value + // + inline bool value_traits:: + assign (value& v, path&& x) + { + path* p; + + if (v.null ()) + p = new (&v.data_) path (move (x)); + else + p = &(v.as () = move (x)); + + return !p->empty (); + } + + inline bool value_traits:: + append (value& v, path&& x) + { + path* p; + + if (v.null ()) + p = new (&v.data_) path (move (x)); + else + { + p = &v.as (); + + if (p->empty ()) + p->swap (x); + else + *p /= x; + } + + return !p->empty (); + } + + inline bool value_traits:: + prepend (value& v, path&& x) + { + path* p; + + if (v.null ()) + new (&v.data_) path (move (x)); + else + { + p = &v.as (); + + if (!p->empty ()) + x /= *p; + + p->swap (x); + } + + return !p->empty (); + } + + inline int value_traits:: + compare (const path& l, const path& r) + { + return l.compare (r); + } + // dir_path value // inline bool value_traits:: -- cgit v1.1