aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-06-22 09:24:12 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-06-22 09:24:12 +0200
commit6ecaa7e76c91a2842bcc63626a908bb2340b77b6 (patch)
treeaa0e3d8d5f9f791dfa1735ce7d8cc276a2c0baf3
parent82ad80de9a967f253026c4874b47486c69402288 (diff)
Remove prerequisite rewriting for c/cxx chaining
-rw-r--r--build/algorithm27
-rw-r--r--build/algorithm.ixx23
-rw-r--r--build/bin/rule.cxx6
-rw-r--r--build/cxx/rule.cxx117
-rw-r--r--build/prerequisite13
-rw-r--r--build/target3
-rw-r--r--build/target-key2
7 files changed, 98 insertions, 93 deletions
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 <string>
+
#include <build/types>
#include <build/target>
#include <build/operation>
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 <typename T>
+ 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 <typename T>
+ inline T&
+ search (const dir_path& dir,
+ const std::string& name,
+ const std::string* ext,
+ scope* scope)
+ {
+ return static_cast<T&> (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<liba&> (search (prerequisite_key {
- {&liba::static_type, &t.dir, &t.name, &t.ext}, nullptr}));
+ t.a = &search<liba> (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<libso&> (search (prerequisite_key {
- {&libso::static_type, &t.dir, &t.name, &t.ext}, nullptr}));
+ t.so = &search<libso> (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<target*> (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<lib> ())
{
@@ -677,13 +672,8 @@ namespace build
pt = lso ? static_cast<target*> (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<obj&> (*ot));
- ot = so ? static_cast<target*> (o.so) : o.a;
-
- if (ot == nullptr)
- {
- const target_type& type (
- so ? objso::static_type : obja::static_type);
+ obj& o (static_cast<obj&> (ot));
+ pt = so ? static_cast<target*> (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<fsdir> () ||
+ p.is_a<h> () ||
+ (cp.is_a<cxx> () && (p.is_a<hxx> () ||
+ p.is_a<ixx> () ||
+ p.is_a<txx> ())) ||
p.is_a<lib> () ||
p.is_a<liba> () ||
p.is_a<libso> ())
continue;
- if (p.type.id == typeid (cxx))
+ if (p.is_a<cxx> ())
{
- 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<lib> () || p.is_a<liba> () || p.is_a<libso> ())
- 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)