aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/search.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/search.cxx')
-rw-r--r--libbuild2/search.cxx128
1 files changed, 107 insertions, 21 deletions
diff --git a/libbuild2/search.cxx b/libbuild2/search.cxx
index 25a4199..4e855e3 100644
--- a/libbuild2/search.cxx
+++ b/libbuild2/search.cxx
@@ -15,7 +15,9 @@ using namespace butl;
namespace build2
{
const target*
- search_existing_target (context& ctx, const prerequisite_key& pk)
+ search_existing_target (context& ctx,
+ const prerequisite_key& pk,
+ bool out_only)
{
tracer trace ("search_existing_target");
@@ -39,9 +41,10 @@ namespace build2
// Prerequisite's out directory can be one of the following:
//
- // empty This means out is undetermined and we simply search for a
- // target that is in the out tree which happens to be indicated
- // by an empty value, so we can just pass this as is.
+ // empty This means out is undetermined and we search for a target
+ // first in the out tree (which happens to be indicated by an
+ // empty value, so we can just pass this as is) and if not
+ // found, then in the src tree (unless suppressed).
//
// absolute This is the "final" value that doesn't require any processing
// and we simply use it as is.
@@ -58,8 +61,11 @@ namespace build2
else
{
o = pk.scope->out_path ();
- o /= *tk.out;
- o.normalize ();
+ if (!tk.out->current ())
+ {
+ o /= *tk.out;
+ o.normalize ();
+ }
}
// Drop out if it is the same as src (in-src build).
@@ -71,6 +77,27 @@ namespace build2
const target* t (
ctx.targets.find (*tk.type, d, o, *tk.name, tk.ext, trace));
+ // Try in the src tree.
+ //
+ if (t == nullptr &&
+ !out_only &&
+ tk.out->empty () &&
+ tk.dir->relative () &&
+ !pk.scope->out_eq_src ())
+ {
+ o = move (d);
+
+ d = pk.scope->src_path ();
+
+ if (!tk.dir->empty ())
+ {
+ d /= *tk.dir;
+ d.normalize ();
+ }
+
+ t = ctx.targets.find (*tk.type, d, o, *tk.name, tk.ext, trace);
+ }
+
if (t != nullptr)
l5 ([&]{trace << "existing target " << *t
<< " for prerequisite " << pk;});
@@ -86,6 +113,10 @@ namespace build2
const target_key& ctk (cpk.tk);
const scope* s (cpk.scope);
+ // Has to be a file target.
+ //
+ assert (ctk.type->is_a<file> ());
+
path f;
if (ctk.dir->absolute ())
@@ -165,35 +196,49 @@ namespace build2
// will be from the src tree.
//
// In the other two cases we use the prerequisite's out (in case it is
- // relative, we need to complete it, which is @@ OUT TODO). Note that we
- // blindly trust the user's value which can be used for some interesting
- // tricks, for example:
- //
- // ../cxx{foo}@./
+ // relative, we need to complete it).
//
dir_path out;
if (tk.out->empty ())
{
- if (s->out_path () != s->src_path ())
+ if (!s->out_eq_src ())
out = out_src (d, *s->root_scope ());
}
else
- out = *tk.out;
+ {
+ if (tk.out->absolute ())
+ out = *tk.out; // Already normalized.
+ else
+ {
+ out = pk.scope->out_path ();
+ if (!tk.out->current ())
+ {
+ out /= *tk.out;
+ out.normalize ();
+ }
+ }
+
+ // Drop out if it is the same as src (in-src build).
+ //
+ if (out == d)
+ out.clear ();
+ }
// Find or insert. Note that we are using our updated extension.
//
+ // More often insert than find, so skip find in insert().
+ //
auto r (ctx.targets.insert (*tk.type,
move (d),
move (out),
*tk.name,
ext,
target_decl::prereq_file,
- trace));
+ trace,
+ true /* skip_find */));
- // Has to be a file_target.
- //
- const file& t (dynamic_cast<const file&> (r.first));
+ const file& t (r.first.as<file> ());
l5 ([&]{trace << (r.second ? "new" : "existing") << " target " << t
<< " for prerequisite " << cpk;});
@@ -210,11 +255,34 @@ namespace build2
const target_key& tk (pk.tk);
+ // If out is present, then it means the target is in src and we shouldn't
+ // be creating new targets in src, should we? Feels like this should not
+ // even be called if out is not empty.
+ //
+ assert (tk.out->empty ());
+
// We default to the target in this directory scope.
//
dir_path d;
if (tk.dir->absolute ())
+ {
d = *tk.dir; // Already normalized.
+
+ // Even if out is empty, it may still be (only) in src.
+ //
+ // Note: issue diagnostics consistent with search() after skipping this
+ // function due to non-empty out.
+ //
+ // @@ PERF: we could first check if it's in pk.scope, which feels like
+ // the common case. Though this doesn't seem to affect
+ // performance in any noticeable way.
+ //
+ auto p (ctx.scopes.find (d, false)); // Note: never empty.
+ if (*p.first == nullptr && ++p.first != p.second)
+ {
+ fail << "no existing source file for prerequisite " << pk << endf;
+ }
+ }
else
{
d = pk.scope->out_path ();
@@ -228,7 +296,7 @@ namespace build2
// Find or insert.
//
- // @@ OUT: same story as in search_existing_target() re out.
+ // More often insert than find, so skip find in insert().
//
auto r (ctx.targets.insert (*tk.type,
move (d),
@@ -236,7 +304,8 @@ namespace build2
*tk.name,
tk.ext,
target_decl::prereq_new,
- trace));
+ trace,
+ true /* skip_find */));
const target& t (r.first);
l5 ([&]{trace << (r.second ? "new" : "existing") << " target " << t
@@ -251,11 +320,27 @@ namespace build2
const target_key& tk (pk.tk);
+ // If out is present, then it means the target is in src and we shouldn't
+ // be creating new targets in src, should we? Feels like this should not
+ // even be called if out is not empty.
+ //
+ assert (tk.out->empty ());
+
// We default to the target in this directory scope.
//
dir_path d;
if (tk.dir->absolute ())
+ {
d = *tk.dir; // Already normalized.
+
+ // As above.
+ //
+ auto p (ctx.scopes.find (d, false));
+ if (*p.first == nullptr && ++p.first != p.second)
+ {
+ fail << "no existing source file for prerequisite " << pk << endf;
+ }
+ }
else
{
d = pk.scope->out_path ();
@@ -269,7 +354,7 @@ namespace build2
// Find or insert.
//
- // @@ OUT: same story as in search_existing_target() re out.
+ // More often insert than find, so skip find in insert_locked().
//
auto r (ctx.targets.insert_locked (*tk.type,
move (d),
@@ -277,7 +362,8 @@ namespace build2
*tk.name,
tk.ext,
target_decl::prereq_new,
- trace));
+ trace,
+ true /* skip_find */));
l5 ([&]
{
diag_record dr (trace);