diff options
Diffstat (limited to 'libbuild2/in/rule.cxx')
-rw-r--r-- | libbuild2/in/rule.cxx | 134 |
1 files changed, 110 insertions, 24 deletions
diff --git a/libbuild2/in/rule.cxx b/libbuild2/in/rule.cxx index faf1ec1..31a9d94 100644 --- a/libbuild2/in/rule.cxx +++ b/libbuild2/in/rule.cxx @@ -23,14 +23,14 @@ namespace build2 namespace in { bool rule:: - match (action a, target& xt, const string&) const + match (action a, target& xt) const { tracer trace ("in::rule::match"); if (!xt.is_a<file> ()) // See module init() for details. return false; - file& t (static_cast<file&> (xt)); + file& t (xt.as<file> ()); bool fi (false); // Found in. for (prerequisite_member p: group_prerequisite_members (a, t)) @@ -47,17 +47,24 @@ namespace build2 if (!fi) l5 ([&]{trace << "no in file prerequisite for target " << t;}); + // If we match, derive the file name here instead of in apply() to make + // it available early for the in{} prerequisite search (see + // install::file_rule::apply_impl() for background). + // + if (fi) + t.derive_path (); + return fi; } recipe rule:: apply (action a, target& xt) const { - file& t (static_cast<file&> (xt)); + file& t (xt.as<file> ()); - // Derive the file name. + // Make sure derived rules assign the path in match(). // - t.derive_path (); + assert (!t.path ().empty ()); // Inject dependency on the output directory. // @@ -108,7 +115,7 @@ namespace build2 // Substitution mode. // bool strict (strict_); - if (const string* s = cast_null<string> (t["in.substitution"])) + if (const string* s = cast_null<string> (t["in.mode"])) { if (*s == "lax") strict = false; @@ -116,6 +123,11 @@ namespace build2 fail << "invalid substitution mode '" << *s << "'"; } + // Substitution map. + // + const substitution_map* smap ( + cast_null<map<string, optional<string>>> (t["in.substitutions"])); + // NULL substitutions. // optional<string> null; @@ -251,10 +263,13 @@ namespace build2 substitute (location (ip, ln), a, t, name, flags, - strict, null)); + strict, smap, null)); assert (v); // Rule semantics change without version increment? + if (p3 != string::npos) + p3 -= p2; // Hash length. + if (s->compare (p2, p3, sha256 (*v).string ()) == 0) { dd_skip++; @@ -291,7 +306,35 @@ namespace build2 if (verb >= 2) text << program_ << ' ' << ip << " >" << tp; else if (verb) - text << program_ << ' ' << ip; + { + // If we straight print the target, in most cases we will end up with + // something ugly like in{version...h.in} (due to the in{} target + // type search semantics). There is the `...h` part but also the + // `.in` part that is redundant given in{}. So let's tidy this up + // a bit if the extension could have been derived by in_search(). + // + target_key ik (i.key ()); + + if (ik.ext) + { + string& ie (*ik.ext); + const string* te (t.ext ()); + + size_t in (ie.size ()); + size_t tn (te != nullptr ? te->size () : 0); + + if (in == tn + (tn != 0 ? 1 : 0) + 2) // [<te>.]in + { + if (ie.compare (in - 2, 2, "in") == 0) + { + if (tn == 0 || (ie.compare (0, tn, *te) == 0 && ie[tn] == '.')) + ie.clear (); + } + } + } + + print_diag (program_.c_str (), move (ik), t); + } // Read and process the file, one line at a time, while updating depdb. // @@ -336,7 +379,7 @@ namespace build2 #endif auto_rmfile arm (tp); - // Note: this default will only be used if the file if empty (i.e., + // Note: this default will only be used if the file is empty (i.e., // does not contain even a newline). // const char* nl ( @@ -347,8 +390,8 @@ namespace build2 #endif ); - string s; // Reuse the buffer. - for (uint64_t ln (1);; ++ln) + uint64_t ln (1); + for (string s;; ++ln) { what = "read"; whom = &ip; if (!getline (ifs, s)) @@ -361,22 +404,31 @@ namespace build2 if (crlf) s.pop_back(); + what = "write"; whom = &tp; + if (ln != 1) + ofs << nl; + + nl = crlf ? "\r\n" : "\n"; // Preserve the original line ending. + + if (ln == 1) + perform_update_pre (a, t, ofs, nl); + // Not tracking column for now (see also depdb above). // process (location (ip, ln), a, t, dd, dd_skip, s, 0, - (crlf ? "\r\n" : "\n"), sym, strict, null); + nl, sym, strict, smap, null); - what = "write"; whom = &tp; - if (ln != 1) - ofs << nl; // See below. ofs << s; - - nl = crlf ? "\r\n" : "\n"; // Preserve the original line ending. } + what = "write"; whom = &tp; + if (ln == 1) + perform_update_pre (a, t, ofs, nl); + perform_update_post (a, t, ofs, nl); + // Close depdb before closing the output file so its mtime is not // newer than of the output. // @@ -416,6 +468,16 @@ namespace build2 } void rule:: + perform_update_pre (action, const target&, ofdstream&, const char*) const + { + } + + void rule:: + perform_update_post (action, const target&, ofdstream&, const char*) const + { + } + + void rule:: process (const location& l, action a, const target& t, depdb& dd, size_t& dd_skip, @@ -423,6 +485,7 @@ namespace build2 const char* nl, char sym, bool strict, + const substitution_map* smap, const optional<string>& null) const { // Scan the line looking for substiutions in the $<name>$ form. In the @@ -478,8 +541,7 @@ namespace build2 dd, dd_skip, string (s, b + 1, e - b -1), nullopt /* flags */, - strict, - null)) + strict, smap, null)) { replace_newlines (*val, nl); @@ -500,9 +562,10 @@ namespace build2 const string& n, optional<uint64_t> flags, bool strict, + const substitution_map* smap, const optional<string>& null) const { - optional<string> val (substitute (l, a, t, n, flags, strict, null)); + optional<string> val (substitute (l, a, t, n, flags, strict, smap, null)); if (val) { @@ -539,6 +602,7 @@ namespace build2 const string& n, optional<uint64_t> flags, bool strict, + const substitution_map* smap, const optional<string>& null) const { // In the lax mode scan the fragment to make sure it is a variable name @@ -563,7 +627,7 @@ namespace build2 } } - return lookup (l, a, t, n, flags, null); + return lookup (l, a, t, n, flags, smap, null); } string rule:: @@ -571,10 +635,32 @@ namespace build2 action, const target& t, const string& n, optional<uint64_t> flags, + const substitution_map* smap, const optional<string>& null) const { assert (!flags); + // First look in the substitution map. + // + if (smap != nullptr) + { + auto i (smap->find (n)); + + if (i != smap->end ()) + { + if (i->second) + return *i->second; + + if (null) + return *null; + + fail (loc) << "null value in substitution map entry '" << n << "'" << + info << "use in.null to specify null value substiution string"; + } + } + + // Next look for the buildfile variable. + // auto l (t[n]); if (l.defined ()) @@ -585,9 +671,9 @@ namespace build2 { if (null) return *null; - else - fail (loc) << "null value in variable '" << n << "'" << - info << "use in.null to specify null value substiution string"; + + fail (loc) << "null value in variable '" << n << "'" << + info << "use in.null to specify null value substiution string"; } // For typed values call string() for conversion. |