From 6ecaa7e76c91a2842bcc63626a908bb2340b77b6 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 22 Jun 2015 09:24:12 +0200 Subject: Remove prerequisite rewriting for c/cxx chaining --- build/algorithm | 27 ++++++++++-- build/algorithm.ixx | 23 ++++++++++- build/bin/rule.cxx | 6 +-- build/cxx/rule.cxx | 117 ++++++++++++++++++---------------------------------- build/prerequisite | 13 ++++-- build/target | 3 +- build/target-key | 2 +- 7 files changed, 98 insertions(+), 93 deletions(-) (limited to 'build') diff --git a/build/algorithm b/build/algorithm index 5138dfa..2dc7164 100644 --- a/build/algorithm +++ b/build/algorithm @@ -5,12 +5,15 @@ #ifndef BUILD_ALGORITHM #define BUILD_ALGORITHM +#include + #include #include #include namespace build { + class scope; class prerequisite; class prerequisite_key; @@ -21,13 +24,31 @@ namespace build target& search (prerequisite&); - // As above but specify the prerequisite to search as a key. Useful - // for searching for target group members where we need to search - // for a different target type. + // As above but specify the prerequisite to search as a key. // target& search (const prerequisite_key&); + // As above but specify the prerequisite to search as individual + // key components. Useful for searching for target group members + // where we need to search for a different target type. + // + target& + search (const target_type& type, + const dir_path& dir, + const std::string& name, + const std::string* ext, + scope* scope); + + // As above but specify the target type as template argument. + // + template + T& + search (const dir_path& dir, + const std::string& name, + const std::string* ext, + scope* scope); + // Match a rule to the action/target with ambiguity detection. // void diff --git a/build/algorithm.ixx b/build/algorithm.ixx index 9435b2e..3907209 100644 --- a/build/algorithm.ixx +++ b/build/algorithm.ixx @@ -11,12 +11,31 @@ namespace build search (prerequisite& p) { if (p.target == nullptr) - p.target = &search ( - prerequisite_key {{&p.type, &p.dir, &p.name, &p.ext}, &p.scope}); + p.target = &search (p.key ()); return *p.target; } + inline target& + search (const target_type& type, + const dir_path& dir, + const std::string& name, + const std::string* ext, + scope* scope) + { + return search (prerequisite_key {{&type, &dir, &name, &ext}, scope}); + } + + template + inline T& + search (const dir_path& dir, + const std::string& name, + const std::string* ext, + scope* scope) + { + return static_cast (search (T::static_type, dir, name, ext, scope)); + } + void match_impl (action, target&); diff --git a/build/bin/rule.cxx b/build/bin/rule.cxx index 22b7bc2..1834f7a 100644 --- a/build/bin/rule.cxx +++ b/build/bin/rule.cxx @@ -62,8 +62,7 @@ namespace build if (ar) { if (t.a == nullptr) - t.a = &static_cast (search (prerequisite_key { - {&liba::static_type, &t.dir, &t.name, &t.ext}, nullptr})); + t.a = &search (t.dir, t.name, t.ext, nullptr); build::match (a, *t.a); } @@ -71,8 +70,7 @@ namespace build if (so) { if (t.so == nullptr) - t.so = &static_cast (search (prerequisite_key { - {&libso::static_type, &t.dir, &t.name, &t.ext}, nullptr})); + t.so = &search (t.dir, t.name, t.ext, nullptr); build::match (a, *t.so); } diff --git a/build/cxx/rule.cxx b/build/cxx/rule.cxx index 58d8e88..72c4e35 100644 --- a/build/cxx/rule.cxx +++ b/build/cxx/rule.cxx @@ -637,13 +637,8 @@ namespace build pt = so ? static_cast (o->so) : o->a; if (pt == nullptr) - { - const target_type& type ( - so ? objso::static_type : obja::static_type); - - pt = &search ( - prerequisite_key {{&type, &p.dir, &p.name, &p.ext}, &p.scope}); - } + pt = &search (so ? objso::static_type : obja::static_type, + p.dir, p.name, p.ext, &p.scope); } else if (lib* l = pt->is_a ()) { @@ -677,13 +672,8 @@ namespace build pt = lso ? static_cast (l->so) : l->a; if (pt == nullptr) - { - const target_type& type ( - lso ? libso::static_type : liba::static_type); - - pt = &search ( - prerequisite_key {{&type, &p.dir, &p.name, &p.ext}, &p.scope}); - } + pt = &search (lso ? libso::static_type : liba::static_type, + p.dir, p.name, p.ext, &p.scope); } build::match (a, *pt); @@ -698,18 +688,18 @@ namespace build // altogether. So we are going to use the target's project. // root = t.root_scope (); - assert (root != nullptr); // Shouldn't have matched. + assert (root != nullptr); // Otherwise shouldn't have matched. out_root = &root->path (); src_root = &root->src_path (); } - prerequisite& cp (p); + prerequisite& cp (p); // c(xx){} prerequisite. const target_type& o_type ( group ? obj::static_type : (so ? objso::static_type : obja::static_type)); - // Come up with the obj*{} prerequisite. The c(xx){} prerequisite + // Come up with the obj*{} target. The c(xx){} prerequisite // directory can be relative (to the scope) or absolute. If it is // relative, then use it as is. If it is absolute, then translate // it to the corresponding directory under out_root. While the @@ -729,105 +719,82 @@ namespace build d = *out_root / cp.dir.leaf (*src_root); } - prerequisite& op ( - cp.scope.prerequisites.insert ( - o_type, - move (d), - cp.name, - nullptr, - cp.scope, - trace).first); - - // Resolve this prerequisite to target. - // - target* ot (&search (op)); + target& ot (search (o_type, d, cp.name, nullptr, &cp.scope)); // If we are cleaning, check that this target is in the same or // a subdirectory of ours. // - // If it is not, then we are effectively leaving the prerequisites - // half-rewritten (we only rewrite those that we should clean). - // What will happen if, say, after clean we have update? Well, - // update will come and finish the rewrite process (it will even - // reuse op that we have created but then ignored). So all is good. - // - if (a.operation () == clean_id && !ot->dir.sub (t.dir)) + if (a.operation () == clean_id && !ot.dir.sub (t.dir)) { // If we shouldn't clean obj{}, then it is fair to assume // we shouldn't clean cxx{} either (generated source will // be in the same directory as obj{} and if not, well, go - // find yourself another build system). + // find yourself another build system ;-)). // continue; // Skip. } - pt = ot; - // If we have created the obj{} target group, pick one of its // members; the rest would be primarily concerned with it. // if (group) { - obj& o (static_cast (*ot)); - ot = so ? static_cast (o.so) : o.a; - - if (ot == nullptr) - { - const target_type& type ( - so ? objso::static_type : obja::static_type); + obj& o (static_cast (ot)); + pt = so ? static_cast (o.so) : o.a; - ot = &search ( - prerequisite_key {{&type, &o.dir, &o.name, &o.ext}, nullptr}); - } + if (pt == nullptr) + pt = &search (so ? objso::static_type : obja::static_type, + o.dir, o.name, o.ext, nullptr); } + else + pt = &ot; - // If this target already exists, then it needs to be "compatible" - // with what we are doing here. + // If this obj*{} target already exists, then it needs to be + // "compatible" with what we are doing here. // // This gets a bit tricky. We need to make sure the source files // are the same which we can only do by comparing the targets to // which they resolve. But we cannot search the ot's prerequisites // -- only the rule that matches can. Note, however, that if all - // this works out, then our next step is to search and match the - // re-written prerequisite (which points to ot). If things don't - // work out, then we fail, in which case searching and matching - // speculatively doesn't really hurt. + // this works out, then our next step is to match the obj*{} + // target. If things don't work out, then we fail, in which case + // searching and matching speculatively doesn't really hurt. // prerequisite* cp1 (nullptr); - for (prerequisite& p: reverse_iterate (group_prerequisites (*ot))) + for (prerequisite& p: reverse_iterate (group_prerequisites (*pt))) { // Ignore some known target types (fsdir, headers, libraries). // - if (p.type.id == typeid (fsdir) || - p.type.id == typeid (h) || - (cp.type.id == typeid (cxx) && (p.type.id == typeid (hxx) || - p.type.id == typeid (ixx) || - p.type.id == typeid (txx))) || + if (p.is_a () || + p.is_a () || + (cp.is_a () && (p.is_a () || + p.is_a () || + p.is_a ())) || p.is_a () || p.is_a () || p.is_a ()) continue; - if (p.type.id == typeid (cxx)) + if (p.is_a ()) { - cp1 = &p; // Check the rest of the prerequisites. - continue; + cp1 = &p; + continue; // Check the rest of the prerequisites. } fail << "synthesized target for prerequisite " << cp - << " would be incompatible with existing target " << *ot << + << " would be incompatible with existing target " << *pt << info << "unknown existing prerequisite type " << p << info << "specify corresponding obj{} target explicitly"; } if (cp1 != nullptr) { - build::match (a, *ot); // Now cp1 should be resolved. + build::match (a, *pt); // Now cp1 should be resolved. search (cp); // Our own prerequisite, so this is ok. if (cp.target != cp1->target) fail << "synthesized target for prerequisite " << cp - << " would be incompatible with existing target " << *ot << + << " would be incompatible with existing target " << *pt << info << "existing prerequisite " << *cp1 << " does not " << "match " << cp << info << "specify corresponding " << o_type.name << "{} " @@ -837,30 +804,26 @@ namespace build { // Note: add the source to the group, not the member. // - pt->prerequisites.emplace_back (cp); + ot.prerequisites.emplace_back (cp); // Add our lib*{} prerequisites to the object file (see // cxx.export.poptions above for details). // // Initially, we were only adding imported libraries, but // there is a problem with this approach: the non-imported - // library might depend on the imported one(s) which we - // will never "see" unless we add this library as well. + // library might depend on the imported one(s) which we will + // never "see" unless we start with this library. // for (prerequisite& p: group_prerequisites (t)) { if (p.is_a () || p.is_a () || p.is_a ()) - pt->prerequisites.emplace_back (p); + ot.prerequisites.emplace_back (p); } - build::match (a, *ot); + build::match (a, *pt); } - // Change the exe{} target's prerequisite from cxx{} to obj*{}. - // - pr = op; - - t.prerequisite_targets.push_back (ot); + t.prerequisite_targets.push_back (pt); } switch (a) diff --git a/build/prerequisite b/build/prerequisite index 0d3428f..529b225 100644 --- a/build/prerequisite +++ b/build/prerequisite @@ -69,6 +69,13 @@ namespace build target_type* target; // NULL if not yet resolved. Note that this should // always be the "primary target", not a member of // a target group. + + prerequisite_key + key () const + { + return prerequisite_key {{&type, &dir, &name, &ext}, &scope}; + } + public: // Prerequisite (target) type. // @@ -80,15 +87,13 @@ namespace build inline bool operator< (const prerequisite& x, const prerequisite& y) { - return prerequisite_key {{&x.type, &x.dir, &x.name, &x.ext}, &x.scope} < - prerequisite_key {{&y.type, &y.dir, &y.name, &y.ext}, &y.scope}; + return x.key () < y.key (); } inline std::ostream& operator<< (std::ostream& os, const prerequisite& p) { - return os << - prerequisite_key {{&p.type, &p.dir, &p.name, &p.ext}, &p.scope}; + return os << p.key (); } // Set of prerequisites in a scope. diff --git a/build/target b/build/target index 54b9daf..8eb7813 100644 --- a/build/target +++ b/build/target @@ -404,8 +404,7 @@ namespace build const std::string* ext, tracer& trace) const { - const std::string* e (ext); - return find (target_key {&type, &dir, &name, &e}, trace); + return find (target_key {&type, &dir, &name, &ext}, trace); } // As above but ignore the extension and return the target or diff --git a/build/target-key b/build/target-key index 9e74c27..04a5b26 100644 --- a/build/target-key +++ b/build/target-key @@ -43,7 +43,7 @@ namespace build mutable const target_type* type; mutable const dir_path* dir; mutable const std::string* name; - mutable const std::string* const* ext; + mutable const std::string* const* ext; // Note only *ext can be NULL. friend bool operator< (const target_key& x, const target_key& y) -- cgit v1.1