aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libbuild2/cc/compile-rule.cxx105
-rw-r--r--libbuild2/cc/compile-rule.hxx7
-rw-r--r--libbuild2/types.hxx2
3 files changed, 78 insertions, 36 deletions
diff --git a/libbuild2/cc/compile-rule.cxx b/libbuild2/cc/compile-rule.cxx
index 93f05f1..62391f3 100644
--- a/libbuild2/cc/compile-rule.cxx
+++ b/libbuild2/cc/compile-rule.cxx
@@ -1683,9 +1683,42 @@ namespace build2
//
auto enter = [&trace, &m] (dir_path p, dir_path d, size_t prio)
{
- auto j (m.find (p));
+ auto j (m.lower_bound (p)), e (m.end ());
- if (j != m.end ())
+ if (j != e && j->first != p)
+ j = e;
+
+ if (j == m.end ())
+ {
+ if (verb >= 4)
+ trace << "new mapping for prefix '" << p << "'\n"
+ << " new mapping to " << d << " priority " << prio;
+
+ m.emplace (move (p), prefix_value {move (d), prio});
+ }
+ else if (p.empty ())
+ {
+ // For prefixless we keep all the entries since for them we have
+ // an extra check (target must be explicitly spelled out in a
+ // buildfile).
+ //
+ if (verb >= 4)
+ trace << "additional mapping for prefix '" << p << "'\n"
+ << " new mapping to " << d << " priority " << prio;
+
+ // Find the position where to insert according to the priority.
+ // For equal priorities we use the insertion order.
+ //
+ do
+ {
+ if (j->second.priority > prio)
+ break;
+ }
+ while (++j != e && j->first == p);
+
+ m.emplace_hint (j, move (p), prefix_value {move (d), prio});
+ }
+ else
{
prefix_value& v (j->second);
@@ -1724,12 +1757,6 @@ namespace build2
v.priority = prio;
}
}
- else
- {
- l6 ([&]{trace << "'" << p << "' -> " << d << " priority "
- << prio;});
- m.emplace (move (p), prefix_value {move (d), prio});
- }
};
#if 1
@@ -1737,11 +1764,7 @@ namespace build2
//
// The prefixless part is fuzzy but seems to be doing the right
// thing ignoring/overriding-wise, at least in cases where one of
- // the competing -I paths is a subdirectory of another. But the
- // proper solution will be to keep all the prefixless entries (by
- // changing prefix_map to a multimap) since for them we have an
- // extra check (target must be explicitly spelled out in a
- // buildfile).
+ // the competing -I paths is a subdirectory of another.
//
for (size_t prio (0);; ++prio)
{
@@ -3068,7 +3091,11 @@ namespace build2
// possibly find an explicit target of this type.
//
if (!insert)
+ {
+ l6 ([&]{trace << "unknown header " << n << " extension '"
+ << e << "'";});
return nullptr;
+ }
tts.push_back (&h::static_type);
}
@@ -3090,8 +3117,12 @@ namespace build2
// absolute path with a spelled-out extension to multiple targets.
//
for (const target_type* tt: tts)
+ {
if ((r = t.ctx.targets.find (*tt, d, out, n, e, trace)) != nullptr)
break;
+ else
+ l6 ([&]{trace << "no targe with target type " << tt->name;});
+ }
// Note: we can't do this because of the in-source builds where
// there won't be explicit targets for non-generated headers.
@@ -3195,32 +3226,40 @@ namespace build2
if (!pfx_map->empty ())
{
dir_path d (f.directory ());
- auto i (pfx_map->find_sup (d));
+ auto p (pfx_map->sup_range (d));
- if (i != pfx_map->end ())
+ if (p.first != p.second)
{
- // Note: value in pfx_map is not necessarily canonical.
+ // Note that we can only have multiple entries for the
+ // prefixless mapping.
//
- dir_path pd (i->second.directory);
- pd.canonicalize ();
+ dir_path pd; // Reuse.
+ for (auto i (p.first); i != p.second; ++i)
+ {
+ // Note: value in pfx_map is not necessarily canonical.
+ //
+ pd = i->second.directory;
+ pd.canonicalize ();
- l4 ([&]{trace << "prefix '" << d << "' mapped to " << pd;});
+ l4 ([&]{trace << "try prefix '" << d << "' mapped to " << pd;});
- // If this is a prefixless mapping, then only use it if we can
- // resolve it to an existing target (i.e., it is explicitly
- // spelled out in a buildfile).
- //
- // Note that at some point we will probably have a list of
- // directories.
- //
- pt = find (pd / d, f.leaf (), !i->first.empty ());
- if (pt != nullptr)
- {
- f = pd / f;
- l4 ([&]{trace << "mapped as auto-generated " << f;});
+ // If this is a prefixless mapping, then only use it if we can
+ // resolve it to an existing target (i.e., it is explicitly
+ // spelled out in a buildfile). @@ Hm, I wonder why, it's not
+ // like we can generate any header without an explicit target.
+ // Maybe for diagnostics (i.e., we will actually try to build
+ // something there instead of just saying no mapping).
+ //
+ pt = find (pd / d, f.leaf (), !i->first.empty ());
+ if (pt != nullptr)
+ {
+ f = pd / f;
+ l4 ([&]{trace << "mapped as auto-generated " << f;});
+ break;
+ }
+ else
+ l4 ([&]{trace << "no explicit target in " << pd;});
}
- else
- l4 ([&]{trace << "no explicit target in " << pd;});
}
else
l4 ([&]{trace << "no prefix map entry for '" << d << "'";});
diff --git a/libbuild2/cc/compile-rule.hxx b/libbuild2/cc/compile-rule.hxx
index daea600..f573968 100644
--- a/libbuild2/cc/compile-rule.hxx
+++ b/libbuild2/cc/compile-rule.hxx
@@ -100,8 +100,9 @@ namespace build2
// don't treat foobar as a sub-directory of foo.
//
// The priority is used to decide who should override whom. Lesser
- // values are considered higher priority. See append_prefixes() for
- // details.
+ // values are considered higher priority. Note that we can have multiple
+ // prefixless mapping (where priority is used to determine the order).
+ // See append_prefixes() for details.
//
// @@ The keys should be normalized.
//
@@ -110,7 +111,7 @@ namespace build2
dir_path directory;
size_t priority;
};
- using prefix_map = dir_path_map<prefix_value>;
+ using prefix_map = dir_path_multimap<prefix_value>;
void
append_prefixes (prefix_map&, const target&, const variable&) const;
diff --git a/libbuild2/types.hxx b/libbuild2/types.hxx
index 99cc0dc..af1a4de 100644
--- a/libbuild2/types.hxx
+++ b/libbuild2/types.hxx
@@ -292,6 +292,8 @@ namespace build2
using butl::path_map;
using butl::dir_path_map;
+ using butl::path_multimap;
+ using butl::dir_path_multimap;
// Absolute directory path. Note that for now we don't do any checking that
// the path is in fact absolute.