diff options
32 files changed, 271 insertions, 116 deletions
diff --git a/build2/algorithm.hxx b/build2/algorithm.hxx index 22b8471..430cc9f 100644 --- a/build2/algorithm.hxx +++ b/build2/algorithm.hxx @@ -65,7 +65,7 @@ namespace build2 const string& name, const string* ext = nullptr, // NULL means unspecified. const scope* = nullptr, // NULL means dir is absolute. - const optional<string>& proj = nullopt); + const optional<project_name>& proj = nullopt); const target* search_existing (const target_type& type, @@ -74,7 +74,7 @@ namespace build2 const string& name, const string* ext = nullptr, const scope* = nullptr, - const optional<string>& proj = nullopt); + const optional<project_name>& proj = nullopt); // As above but specify the target type as template argument. // diff --git a/build2/algorithm.ixx b/build2/algorithm.ixx index fb77e9c..e41b87f 100644 --- a/build2/algorithm.ixx +++ b/build2/algorithm.ixx @@ -78,7 +78,7 @@ namespace build2 const string& name, const string* ext, const scope* scope, - const optional<string>& proj) + const optional<project_name>& proj) { return search ( t, @@ -99,7 +99,7 @@ namespace build2 const string& name, const string* ext, const scope* scope, - const optional<string>& proj) + const optional<project_name>& proj) { return search_existing ( prerequisite_key { diff --git a/build2/bash/init.cxx b/build2/bash/init.cxx index ff653c2..7bfea58 100644 --- a/build2/bash/init.cxx +++ b/build2/bash/init.cxx @@ -54,7 +54,7 @@ namespace build2 // Install into bin/<project>/ by default stripping the .bash // extension from <project> if present. // - const string& p (cast<string> (rs.vars[var_project])); + const project_name& p (cast<project_name> (rs.vars[var_project])); install_path<bash> (bs, dir_path ("bin") /= project_base (p)); install_mode<bash> (bs, "644"); diff --git a/build2/bash/utility.hxx b/build2/bash/utility.hxx index d8d9a43..67f4552 100644 --- a/build2/bash/utility.hxx +++ b/build2/bash/utility.hxx @@ -14,13 +14,12 @@ namespace build2 { // Strip the .bash extension from the project name. // + // Note that the result may not be a valid project name. + // inline string - project_base (const string& n) + project_base (const project_name& pn) { - size_t p (path::traits::find_extension (n)); - return p == string::npos || casecmp (n.c_str () + p, ".bash", 5) != 0 - ? n - : string (n, 0, p); + return pn.base ("bash"); } } } diff --git a/build2/cc/common.cxx b/build2/cc/common.cxx index 3c4994e..ca73483 100644 --- a/build2/cc/common.cxx +++ b/build2/cc/common.cxx @@ -444,6 +444,7 @@ namespace build2 // search (name, scope). // dir_path out; + prerequisite_key pk {n.proj, {tt, &n.dir, &out, &n.value, ext}, &s}; xt = search_library_existing (a, sysd, usrd, pk); diff --git a/build2/cc/common.hxx b/build2/cc/common.hxx index 27706f3..18824cb 100644 --- a/build2/cc/common.hxx +++ b/build2/cc/common.hxx @@ -288,7 +288,7 @@ namespace build2 bool pkgconfig_load (action, const scope&, bin::lib&, bin::liba*, bin::libs*, - const optional<string>&, + const optional<project_name>&, const string&, const dir_path&, const dir_paths&, diff --git a/build2/cc/pkgconfig.cxx b/build2/cc/pkgconfig.cxx index 5ace6ec..55c8b35 100644 --- a/build2/cc/pkgconfig.cxx +++ b/build2/cc/pkgconfig.cxx @@ -456,7 +456,7 @@ namespace build2 lib& lt, liba* at, libs* st, - const optional<string>& proj, + const optional<project_name>& proj, const string& stem, const dir_path& libd, const dir_paths& top_sysd, @@ -551,7 +551,7 @@ namespace build2 if (proj) { f = dir; - f /= *proj; + f /= proj->string (); f += sfx; f += ".pc"; if (exists (f)) @@ -1102,7 +1102,7 @@ namespace build2 lib&, liba*, libs*, - const optional<string>&, + const optional<project_name>&, const string&, const dir_path&, const dir_paths&, @@ -1142,7 +1142,7 @@ namespace build2 ofdstream os (p); { - const string& n (cast<string> (rs.vars[var_project])); + const project_name& n (cast<project_name> (rs.vars[var_project])); lookup vl (rs.vars[var_version]); if (!vl) diff --git a/build2/context.cxx b/build2/context.cxx index 225ff1c..a8cf042 100644 --- a/build2/context.cxx +++ b/build2/context.cxx @@ -718,10 +718,10 @@ namespace build2 // Note that subprojects is not typed since the value requires // pre-processing (see file.cxx). // - var_project = &vp.insert<string> ("project", v_p); - var_amalgamation = &vp.insert<dir_path> ("amalgamation", v_p); - var_subprojects = &vp.insert ("subprojects", v_p); - var_version = &vp.insert<string> ("version", v_p); + var_project = &vp.insert<project_name> ("project", v_p); + var_amalgamation = &vp.insert<dir_path> ("amalgamation", v_p); + var_subprojects = &vp.insert ("subprojects", v_p); + var_version = &vp.insert<string> ("version", v_p); var_project_url = &vp.insert<string> ("project.url", v_p); var_project_summary = &vp.insert<string> ("project.summary", v_p); diff --git a/build2/context.hxx b/build2/context.hxx index cfe770f..cf7eee6 100644 --- a/build2/context.hxx +++ b/build2/context.hxx @@ -408,11 +408,11 @@ namespace build2 // Return the project name or empty string if unnamed. // - inline const string& + inline const project_name& project (const scope& root) { auto l (root[var_project]); - return l ? cast<string> (l) : empty_string; + return l ? cast<project_name> (l) : empty_project_name; } // Return the src/out directory corresponding to the given out/src. The diff --git a/build2/file.cxx b/build2/file.cxx index 1367b8c..d987226 100644 --- a/build2/file.cxx +++ b/build2/file.cxx @@ -47,9 +47,10 @@ namespace build2 { // See find_subprojects() for details. // - const string& n (path::traits::is_separator (i->first.back ()) - ? empty_string - : i->first); + const project_name& n ( + path::traits::is_separator (i->first.string ().back ()) + ? empty_project_name + : i->first); os << (i != b ? " " : "") << n << '@' << i->second; } @@ -464,7 +465,7 @@ namespace build2 // Extract the project name from bootstrap.build. // - static string + static project_name find_project_name (const dir_path& out_root, const dir_path& fallback_src_root, bool* src_hint = nullptr) @@ -480,7 +481,7 @@ namespace build2 if (s.root_scope () == &s && s.out_path () == out_root) { if (lookup l = s.vars[var_project]) - return cast<string> (l); + return cast<project_name> (l); src_root = s.src_path_; } @@ -518,7 +519,7 @@ namespace build2 } } - string name; + project_name name; { path f (*src_root / bootstrap_file); auto p (extract_variable (f, *var_project)); @@ -527,7 +528,7 @@ namespace build2 fail << "variable " << var_project->name << " expected " << "as a first line in " << f; - name = cast<string> (move (p.first)); + name = cast<project_name> (move (p.first)); } l5 ([&]{trace << "extracted project name '" << name << "' for " @@ -576,7 +577,7 @@ namespace build2 // Load its name. Note that here we don't use fallback src_root // since this function is used to scan both out_root and src_root. // - string name (find_project_name (sd, dir_path (), &src)); + project_name name (find_project_name (sd, dir_path (), &src)); // If the name is empty, then is is an unnamed project. While the // 'project' variable stays empty, here we come up with a surrogate @@ -585,7 +586,8 @@ namespace build2 // sub-directory and appending a trailing directory separator to it. // if (name.empty ()) - name = dir.posix_string () + path::traits::directory_separator; + name = project_name (dir.posix_string () + '/', + project_name::raw_string); // @@ Can't use move() because we may need the values in diagnostics // below. Looks like C++17 try_emplace() is what we need. @@ -770,7 +772,7 @@ namespace build2 { // Project name. // - string n; + project_name n; if (i->pair) { if (i->pair != '@') @@ -778,7 +780,7 @@ namespace build2 try { - n = convert<string> (move (*i)); + n = convert<project_name> (move (*i)); if (n.empty ()) fail << "empty project name in variable subprojects"; @@ -821,7 +823,8 @@ namespace build2 // See find_subprojects() for details on unnamed projects. // if (n.empty ()) - n = d.posix_string () + '/'; + n = project_name (d.posix_string () + '/', + project_name::raw_string); } sps.emplace (move (n), move (d)); @@ -1082,24 +1085,6 @@ namespace build2 return rs; } - // Convert project name to import variable name. - // - static inline string - import_name (const string& p) - { - // For simplicity let's assume project name is a package name and only - // sanitize characters that we don't like from what's valid there. - // - auto sanitize = [] (char c) - { - return (c == '-' || c == '+' || c == '.') ? '_' : c; - }; - - string r; - transform (p.begin (), p.end (), back_inserter (r), sanitize); - return r; - } - names import (scope& ibase, name target, const location& loc) { @@ -1113,13 +1098,13 @@ namespace build2 // if (target.unqualified ()) { - target.proj = string (); + target.proj = project_name (); return names {move (target)}; } // Otherwise, get the project name and convert the target to unqualified. // - string proj (move (*target.proj)); + project_name proj (move (*target.proj)); target.proj = nullopt; scope& iroot (*ibase.root_scope ()); @@ -1137,7 +1122,7 @@ namespace build2 for (;;) // Break-out loop. { - string n ("config.import." + import_name (proj)); + string n ("config.import." + proj.variable ()); // config.import.<proj> // @@ -1230,7 +1215,7 @@ namespace build2 // First check the amalgamation itself. // - if (r != &iroot && cast<string> (r->vars[var_project]) == proj) + if (r != &iroot && cast<project_name> (r->vars[var_project]) == proj) { out_root = r->out_path (); break; @@ -1345,7 +1330,7 @@ namespace build2 // Now we know this project's name as well as all its subprojects. // - if (cast<string> (root->vars[var_project]) == proj) + if (cast<project_name> (root->vars[var_project]) == proj) break; if (auto l = root->vars[var_subprojects]) @@ -1422,7 +1407,7 @@ namespace build2 tracer trace ("import"); assert (pk.proj); - const string& proj (*pk.proj); + const project_name& proj (*pk.proj); // Target type-specific search. // @@ -1492,7 +1477,7 @@ namespace build2 dr << info << "consider adding its installation location" << info << "or explicitly specify its project name"; else - dr << info << "use config.import." << import_name (proj) + dr << info << "use config.import." << proj.variable () << " command line variable to specifying its project out_root"; dr << endf; diff --git a/build2/file.hxx b/build2/file.hxx index bb136cf..9f93365 100644 --- a/build2/file.hxx +++ b/build2/file.hxx @@ -19,7 +19,7 @@ namespace build2 class location; class prerequisite_key; - using subprojects = std::map<string, dir_path>; + using subprojects = std::map<project_name, dir_path>; ostream& operator<< (ostream&, const subprojects&); // Print as name@dir sequence. diff --git a/build2/function.cxx b/build2/function.cxx index f1e0fdd..44bda57 100644 --- a/build2/function.cxx +++ b/build2/function.cxx @@ -375,6 +375,7 @@ namespace build2 void regex_functions (); // functions-regex.cxx void string_functions (); // functions-string.cxx void target_triplet_functions (); // functions-target-triplet.cxx + void project_name_functions (); // functions-target-triplet.cxx struct functions_init { @@ -389,6 +390,7 @@ namespace build2 regex_functions (); string_functions (); target_triplet_functions (); + project_name_functions (); } }; diff --git a/build2/functions-project-name.cxx b/build2/functions-project-name.cxx new file mode 100644 index 0000000..f77b9cd --- /dev/null +++ b/build2/functions-project-name.cxx @@ -0,0 +1,63 @@ +// file : build2/functions-project-name.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include <build2/function.hxx> +#include <build2/variable.hxx> + +using namespace std; + +namespace build2 +{ + void + project_name_functions () + { + function_family f ("project_name"); + + f["string"] = [](project_name p) {return move (p).string ();}; + + f["base"] = [](project_name p, optional<string> ext) + { + return ext ? p.base (ext->c_str ()) : p.base (); + }; + + f["base"] = [](project_name p, names ext) + { + return p.base (convert<string> (move (ext)).c_str ()); + }; + + f["extension"] = &project_name::extension; + f["variable"] = &project_name::variable; + + // Project name-specific overloads from builtins. + // + function_family b ("builtin"); + + b[".concat"] = [](project_name n, string s) + { + string r (move (n).string ()); + r += s; + return r; + }; + + b[".concat"] = [](string s, project_name n) + { + s += n.string (); + return s; + }; + + b[".concat"] = [](project_name n, names ns) + { + string r (move (n).string ()); + r += convert<string> (move (ns)); + return r; + }; + + b[".concat"] = [](names ns, project_name n) + { + string r (convert<string> (move (ns))); + r += n.string (); + return r; + }; + } +} diff --git a/build2/install/init.cxx b/build2/install/init.cxx index 682f6b0..5c28cfa 100644 --- a/build2/install/init.cxx +++ b/build2/install/init.cxx @@ -250,7 +250,7 @@ namespace build2 if (s) config::save_module (rs, "install", INT32_MAX); - const string& n (project (rs)); + const string& n (project (rs).string ()); // Global config.install.* values. // diff --git a/build2/name.cxx b/build2/name.cxx index 9fc661b..d1f9ce6 100644 --- a/build2/name.cxx +++ b/build2/name.cxx @@ -25,7 +25,7 @@ namespace build2 if (n.proj) { - r += *n.proj; + r += n.proj->string (); r += '%'; } @@ -119,7 +119,7 @@ namespace build2 if (n.proj) { - write_string (*n.proj); + write_string (n.proj->string ()); os << '%'; } diff --git a/build2/name.hxx b/build2/name.hxx index 54fd130..e688aed 100644 --- a/build2/name.hxx +++ b/build2/name.hxx @@ -33,7 +33,7 @@ namespace build2 // struct name { - optional<string> proj; + optional<project_name> proj; dir_path dir; string type; string value; @@ -48,7 +48,7 @@ namespace build2 name (dir_path d, string t, string v) : dir (move (d)), type (move (t)), value (move (v)) {} - name (optional<string> p, dir_path d, string t, string v) + name (optional<project_name> p, dir_path d, string t, string v) : proj (move (p)), dir (move (d)), type (move (t)), value (move (v)) {} bool diff --git a/build2/operation.cxx b/build2/operation.cxx index 37e7c91..c42f92a 100644 --- a/build2/operation.cxx +++ b/build2/operation.cxx @@ -493,7 +493,7 @@ namespace build2 // This could be a simple project that doesn't set project name. // cout - << "project: " << cast_empty<string> (s[var_project]) << endl + << "project: " << cast_empty<project_name> (s[var_project]) << endl << "version: " << cast_empty<string> (s[var_version]) << endl << "summary: " << cast_empty<string> (s[var_project_summary]) << endl << "url: " << cast_empty<string> (s[var_project_url]) << endl diff --git a/build2/parser.cxx b/build2/parser.cxx index 4fe30e9..57c7fc9 100644 --- a/build2/parser.cxx +++ b/build2/parser.cxx @@ -2150,6 +2150,7 @@ namespace build2 n == "name" ? ptr (value_traits<name>::value_type) : n == "name_pair" ? ptr (value_traits<name_pair>::value_type) : n == "target_triplet" ? ptr (value_traits<target_triplet>::value_type) : + n == "project_name" ? ptr (value_traits<project_name>::value_type) : n == "uint64s" ? ptr (value_traits<uint64s>::value_type) : n == "strings" ? ptr (value_traits<strings>::value_type) : @@ -2799,7 +2800,7 @@ namespace build2 names& ns, const char* what, size_t pairn, - const optional<string>& pp, + const optional<project_name>& pp, const dir_path* dp, const string* tp) { @@ -2827,7 +2828,7 @@ namespace build2 // Project. // - optional<string> p; + optional<project_name> p; if (cn.proj) { if (pp) @@ -3186,7 +3187,7 @@ namespace build2 const char* what, const string* separators, size_t pairn, - const optional<string>& pp, + const optional<project_name>& pp, const dir_path* dp, const string* tp, bool cross) @@ -3209,7 +3210,7 @@ namespace build2 // Parse names until closing '}' expanding patterns. // auto parse = [&r, &t, &tt, pmode, what, separators, this] ( - const optional<string>& pp, + const optional<project_name>& pp, const dir_path* dp, const string* tp) { @@ -3350,7 +3351,7 @@ namespace build2 const char* what, const string* separators, size_t pairn, - const optional<string>& pp, + const optional<project_name>& pp, const dir_path* dp, const string* tp, bool cross) -> parse_names_result @@ -3708,8 +3709,8 @@ namespace build2 // First take care of project. A project-qualified name is not very // common, so we can afford some copying for the sake of simplicity. // - optional<string> p1; - const optional<string>* pp1 (&pp); + optional<project_name> p1; + const optional<project_name>* pp1 (&pp); if (p != string::npos) { @@ -3733,7 +3734,17 @@ namespace build2 if (pp) fail (t) << "nested project name " << proj; - p1 = move (proj); + try + { + p1 = !proj.empty () + ? project_name (move (proj)) + : project_name (); + } + catch (const invalid_argument& e) + { + fail (t) << "invalid project name '" << proj << "': " << e; + } + pp1 = &p1; } } diff --git a/build2/parser.hxx b/build2/parser.hxx index edb2f84..acd0845 100644 --- a/build2/parser.hxx +++ b/build2/parser.hxx @@ -307,7 +307,7 @@ namespace build2 const char* what = "name", const string* separators = &name_separators, size_t pairn = 0, - const optional<string>& prj = nullopt, + const optional<project_name>& prj = nullopt, const dir_path* dir = nullptr, const string* type = nullptr, bool cross = true); @@ -319,7 +319,7 @@ namespace build2 const char* what, const string* separators, size_t pairn, - const optional<string>& prj, + const optional<project_name>& prj, const dir_path* dir, const string* type, bool cross); @@ -341,7 +341,7 @@ namespace build2 names&, const char* what, size_t pairn, - const optional<string>& prj, + const optional<project_name>& prj, const dir_path* dir, const string* type); diff --git a/build2/prerequisite.cxx b/build2/prerequisite.cxx index 5900589..5837328 100644 --- a/build2/prerequisite.cxx +++ b/build2/prerequisite.cxx @@ -15,8 +15,6 @@ namespace build2 { // prerequisite_key // - const optional<string> prerequisite_key::nullproj = nullopt; - ostream& operator<< (ostream& os, const prerequisite_key& pk) { diff --git a/build2/prerequisite.hxx b/build2/prerequisite.hxx index b8707ce..3d8121a 100644 --- a/build2/prerequisite.hxx +++ b/build2/prerequisite.hxx @@ -31,12 +31,10 @@ namespace build2 public: typedef build2::scope scope_type; - const optional<string>& proj; + const optional<project_name>& proj; target_key tk; // The .dir and .out members can be relative. const scope_type* scope; // Can be NULL if tk.dir is absolute. - static const optional<string> nullproj; - template <typename T> bool is_a () const {return tk.is_a<T> ();} bool is_a (const target_type& tt) const {return tk.is_a (tt);} @@ -65,7 +63,7 @@ namespace build2 // bar/ here is relative to the scope, not to foo/. Plus, bar/ can resolve // to either src or out. // - const optional<string> proj; + const optional<project_name> proj; const target_type_type& type; const dir_path dir; // Normalized absolute or relative (to scope). const dir_path out; // Empty, normalized absolute, or relative. @@ -102,7 +100,7 @@ namespace build2 append (const variable&, const target_type&); public: - prerequisite (optional<string> p, + prerequisite (optional<project_name> p, const target_type_type& t, dir_path d, dir_path o, diff --git a/build2/target.hxx b/build2/target.hxx index 0f8c8ea..db5de67 100644 --- a/build2/target.hxx +++ b/build2/target.hxx @@ -882,14 +882,12 @@ namespace build2 return member != nullptr ? member->dir : prerequisite.dir; } - const optional<string>& + const optional<project_name>& proj () const { // Member cannot be project-qualified. // - return member != nullptr - ? prerequisite_key::nullproj - : prerequisite.proj; + return member != nullptr ? nullopt_project_name : prerequisite.proj; } const scope_type& diff --git a/build2/types.hxx b/build2/types.hxx index 8764c35..94604e0 100644 --- a/build2/types.hxx +++ b/build2/types.hxx @@ -42,6 +42,7 @@ #include <libbutl/timestamp.mxx> #include <libbutl/vector-view.mxx> #include <libbutl/small-vector.mxx> +#include <libbutl/project-name.mxx> #include <libbutl/target-triplet.mxx> #include <libbutl/standard-version.mxx> @@ -273,6 +274,10 @@ namespace build2 using butl::standard_version; using butl::standard_version_constraint; + // <libbutl/project-name.mxx> + // + using butl::project_name; + // Diagnostics location. // class location diff --git a/build2/utility.cxx b/build2/utility.cxx index 07cf88e..2d8e59b 100644 --- a/build2/utility.cxx +++ b/build2/utility.cxx @@ -254,13 +254,15 @@ namespace build2 fail (loc) << "unable to execute " << args[0] << ": " << e << endf; } - const string empty_string; - const path empty_path; - const dir_path empty_dir_path; - - const optional<string> nullopt_string; - const optional<path> nullopt_path; - const optional<dir_path> nullopt_dir_path; + const string empty_string; + const path empty_path; + const dir_path empty_dir_path; + const project_name empty_project_name; + + const optional<string> nullopt_string; + const optional<path> nullopt_path; + const optional<dir_path> nullopt_dir_path; + const optional<project_name> nullopt_project_name; void append_options (cstrings& args, const lookup& l, const char* e) diff --git a/build2/utility.hxx b/build2/utility.hxx index 6e76f05..0beec2e 100644 --- a/build2/utility.hxx +++ b/build2/utility.hxx @@ -388,15 +388,17 @@ namespace build2 verbosity, pp, args, forward<F> (f), error, ignore_exit, checksum); } - // Empty/nullopt string and path. + // Empty/nullopt string, path, and project name. // - extern const string empty_string; - extern const path empty_path; - extern const dir_path empty_dir_path; + extern const string empty_string; + extern const path empty_path; + extern const dir_path empty_dir_path; + extern const project_name empty_project_name; - extern const optional<string> nullopt_string; - extern const optional<path> nullopt_path; - extern const optional<dir_path> nullopt_dir_path; + extern const optional<string> nullopt_string; + extern const optional<path> nullopt_path; + extern const optional<dir_path> nullopt_dir_path; + extern const optional<project_name> nullopt_project_name; // Hash a path potentially without the specific directory prefix. // diff --git a/build2/variable.cxx b/build2/variable.cxx index 406123d..c304d0c 100644 --- a/build2/variable.cxx +++ b/build2/variable.cxx @@ -549,7 +549,7 @@ namespace build2 // if (n.qualified ()) { - string p (*n.proj); + string p (move (*n.proj).string ()); p += '%'; p += s; p.swap (s); @@ -563,7 +563,7 @@ namespace build2 if (r->qualified ()) { - s += *r->proj; + s += r->proj->string (); s += '%'; } @@ -1080,6 +1080,55 @@ namespace build2 &default_empty<target_triplet> }; + // project_name value + // + project_name value_traits<project_name>:: + convert (name&& n, name* r) + { + if (r == nullptr) + { + if (n.simple ()) + { + try + { + return n.empty () ? project_name () : project_name (move (n.value)); + } + catch (const invalid_argument& e) + { + throw invalid_argument ( + string ("invalid project_name value: ") + e.what ()); + } + } + + // Fall through. + } + + throw_invalid_argument (n, r, "project_name"); + } + + const project_name& + value_traits<project_name>::empty_instance = empty_project_name; + + const char* const value_traits<project_name>::type_name = "project_name"; + + const value_type value_traits<project_name>::value_type + { + type_name, + sizeof (project_name), + nullptr, // No base. + nullptr, // No element. + &default_dtor<project_name>, + &default_copy_ctor<project_name>, + &default_copy_assign<project_name>, + &simple_assign<project_name>, + nullptr, // Append not supported. + nullptr, // Prepend not supported. + &simple_reverse<project_name>, + nullptr, // No cast (cast data_ directly). + &simple_compare<project_name>, + &default_empty<project_name> + }; + // variable_pool // void variable_pool:: diff --git a/build2/variable.hxx b/build2/variable.hxx index f9b8b3c..401cc77 100644 --- a/build2/variable.hxx +++ b/build2/variable.hxx @@ -820,7 +820,6 @@ namespace build2 static const build2::value_type value_type; }; - // target_triplet // template <> @@ -841,6 +840,27 @@ namespace build2 static const build2::value_type value_type; }; + // project_name + // + template <> + struct value_traits<project_name> + { + static_assert (sizeof (project_name) <= value::size_, + "insufficient space"); + + static project_name convert (name&&, name*); + static void assign (value&, project_name&&); + static name reverse (const project_name& x) {return name (x.string ());} + static int compare (const project_name& x, const project_name& y) { + return x.compare (y);} + static bool empty (const project_name& x) {return x.empty ();} + + static const bool empty_value = true; + static const project_name& empty_instance; + static const char* const type_name; + static const build2::value_type value_type; + }; + // vector<T> // template <typename T> diff --git a/build2/variable.ixx b/build2/variable.ixx index 991556a..8c16559 100644 --- a/build2/variable.ixx +++ b/build2/variable.ixx @@ -611,6 +611,17 @@ namespace build2 new (&v.data_) target_triplet (move (x)); } + // project_name value + // + inline void value_traits<project_name>:: + assign (value& v, project_name&& x) + { + if (v) + v.as<project_name> () = move (x); + else + new (&v.data_) project_name (move (x)); + } + // vector<T> value // template <typename T> diff --git a/build2/version/init.cxx b/build2/version/init.cxx index 397d7da..4234451 100644 --- a/build2/version/init.cxx +++ b/build2/version/init.cxx @@ -138,10 +138,18 @@ namespace build2 catch (const invalid_argument& e) { fail (l) << "invalid version constraint for dependency " - << b << ": " << e; + << d << ": " << e; } - ds.emplace (move (n), move (c)); + try + { + ds.emplace (project_name (move (n)).variable (), move (c)); + } + catch (const invalid_argument& e) + { + fail (l) << "invalid package name for dependency " + << d << ": " << e; + } } } } @@ -232,7 +240,7 @@ namespace build2 // Create the module. // - mod.reset (new module (cast<string> (rs.vars[var_project]), + mod.reset (new module (cast<project_name> (rs.vars[var_project]), move (v), committed, rewritten, @@ -284,7 +292,7 @@ namespace build2 if (!val) { - string p (cast<string> (rs.vars[var_project])); + string p (cast<project_name> (rs.vars[var_project]).string ()); p += '-'; p += v.string (); val = move (p); diff --git a/build2/version/module.hxx b/build2/version/module.hxx index 56536c3..36dd735 100644 --- a/build2/version/module.hxx +++ b/build2/version/module.hxx @@ -16,7 +16,8 @@ namespace build2 { namespace version { - // The 'depends' values from manifest. + // The 'depends' values from manifest. Note that the package names are + // sanitized for use in variable names. // using dependency_constraints = std::map<string, string>; @@ -24,7 +25,9 @@ namespace build2 { static const string name; - const string& project; // The project variable value. + // The project variable value sanitized for use in variable names. + // + const string project; butl::standard_version version; bool committed; // Whether this is a committed snapshot. @@ -34,12 +37,12 @@ namespace build2 bool dist_uncommitted = false; - module (const string& p, + module (const project_name& p, butl::standard_version v, bool c, bool r, dependency_constraints d) - : project (p), + : project (p.variable ()), version (move (v)), committed (c), rewritten (r), diff --git a/tests/name/pattern.test b/tests/name/pattern.test index 792a7c3..fad8478 100644 --- a/tests/name/pattern.test +++ b/tests/name/pattern.test @@ -9,8 +9,8 @@ define txt: file txt{*}: extension = txt EOI -$* <'print p%*.txt' >'p%*.txt' : project-simple -$* <'print p%{*.txt -x*}' >'p%*.txt p%-x*' : project-group +$* <'print pp%*.txt' >'pp%*.txt' : project-simple +$* <'print pp%{*.txt -x*}' >'pp%*.txt pp%-x*' : project-group $* <"print '*.txt'" >'*.txt' : quoted-single $* <'print "*.txt"' >'*.txt' : quoted-double diff --git a/tests/value/reverse.test b/tests/value/reverse.test index 5208536..9ea9d09 100644 --- a/tests/value/reverse.test +++ b/tests/value/reverse.test @@ -42,9 +42,9 @@ : combined : $* <<EOI >>EOO - print ([strings] x%foo@y%bar x%foo/@y%bar/) + print ([strings] xx%foo@yy%bar xx%foo/@yy%bar/) EOI - x%foo@y%bar x%foo/@y%bar/ + xx%foo@yy%bar xx%foo/@yy%bar/ EOO } |