aboutsummaryrefslogtreecommitdiff
path: root/libbuild2
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2023-11-30 12:17:31 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2023-12-03 16:48:07 +0200
commit68a27c5bca208337f5749fe1959ac21c062b77fb (patch)
treeda96113dcb505bf56e03651d03aaba88c78aa077 /libbuild2
parent01226d547c006d29731747c2e8c9df4f9312815e (diff)
Search in src for existing prerequisites with unspecified out
Diffstat (limited to 'libbuild2')
-rw-r--r--libbuild2/algorithm.cxx12
-rw-r--r--libbuild2/cc/compile-rule.cxx6
-rw-r--r--libbuild2/search.cxx32
-rw-r--r--libbuild2/search.hxx7
-rw-r--r--libbuild2/target.cxx24
5 files changed, 58 insertions, 23 deletions
diff --git a/libbuild2/algorithm.cxx b/libbuild2/algorithm.cxx
index 1bb46d8..71bf134 100644
--- a/libbuild2/algorithm.cxx
+++ b/libbuild2/algorithm.cxx
@@ -96,7 +96,7 @@ namespace build2
{
return pk.proj
? import_existing (ctx, pk)
- : search_existing_target (ctx, pk);
+ : search_existing_target (ctx, pk, false /*out_only*/); // @@ TODO
}
const target&
@@ -104,7 +104,7 @@ namespace build2
{
assert (ctx.phase == run_phase::load || ctx.phase == run_phase::match);
- if (const target* pt = search_existing_target (ctx, pk))
+ if (const target* pt = search_existing_target (ctx, pk, true /*out_only*/))
return *pt;
return create_new_target (ctx, pk);
@@ -115,7 +115,7 @@ namespace build2
{
assert (ctx.phase == run_phase::load || ctx.phase == run_phase::match);
- if (const target* pt = search_existing_target (ctx, pk))
+ if (const target* pt = search_existing_target (ctx, pk, true /*out_only*/))
return {const_cast<target&> (*pt), ulock ()};
return create_new_target_locked (ctx, pk);
@@ -176,16 +176,12 @@ namespace build2
}
bool q (cn.qualified ());
-
- // @@ OUT: for now we assume the prerequisite's out is undetermined.
- // Would need to pass a pair of names.
- //
prerequisite_key pk {
n.proj, {tt, &n.dir, q ? &empty_dir_path : &out, &n.value, ext}, &s};
return q
? import_existing (s.ctx, pk)
- : search_existing_target (s.ctx, pk);
+ : search_existing_target (s.ctx, pk, false /*out_only*/); // @@ TODO
}
const target*
diff --git a/libbuild2/cc/compile-rule.cxx b/libbuild2/cc/compile-rule.cxx
index bbdc851..3b37cad 100644
--- a/libbuild2/cc/compile-rule.cxx
+++ b/libbuild2/cc/compile-rule.cxx
@@ -6262,9 +6262,9 @@ namespace build2
// target (which means the name can only be specified on the
// target itself, not target type/pattern-spec).
//
- const target* t (p.search_existing ());
- const string* n (t != nullptr
- ? cast_null<string> (t->vars[c_module_name])
+ const target* mt (p.search_existing ());
+ const string* n (mt != nullptr
+ ? cast_null<string> (mt->vars[c_module_name])
: nullptr);
if (n != nullptr)
{
diff --git a/libbuild2/search.cxx b/libbuild2/search.cxx
index 3bdb503..dee2ae8 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.
@@ -74,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;});
diff --git a/libbuild2/search.hxx b/libbuild2/search.hxx
index aa30648..e3b1442 100644
--- a/libbuild2/search.hxx
+++ b/libbuild2/search.hxx
@@ -15,8 +15,13 @@ namespace build2
// Search for an existing target in this prerequisite's scope. Scope can be
// NULL if directories are absolute.
//
+ // If dir is relative and out is not specified, then first search in the out
+ // tree and, if not found, then in the src tree, unless out_only is true.
+ // If dir is absolute, then out is expected to be specified as well, if
+ // necessary.
+ //
LIBBUILD2_SYMEXPORT const target*
- search_existing_target (context&, const prerequisite_key&);
+ search_existing_target (context&, const prerequisite_key&, bool out_only);
// Search for an existing file. If the prerequisite directory is relative,
// then look in the scope's src directory. Otherwise, if the absolute
diff --git a/libbuild2/target.cxx b/libbuild2/target.cxx
index bef7dce..1d21c07 100644
--- a/libbuild2/target.cxx
+++ b/libbuild2/target.cxx
@@ -1166,15 +1166,21 @@ namespace build2
// The default behavior is to look for an existing target in the
// prerequisite's directory scope.
//
- return search_existing_target (t.ctx, pk);
+ // Note that it would be reasonable to assume that such a target can only
+ // be found in the out tree (targets that can be in the src tree should
+ // use file_search()). But omitting the src search will make it hard to
+ // keep search() (which calls this) and search_existing() (which does not)
+ // consistent.
+ //
+ return search_existing_target (t.ctx, pk, false /* out_only */);
}
const target*
file_search (const target& t, const prerequisite_key& pk)
{
- // First see if there is an existing target.
+ // First see if there is an existing target in the out or src tree.
//
- if (const target* e = search_existing_target (t.ctx, pk))
+ if (const target* e = search_existing_target (t.ctx, pk, false /*out_only*/))
return e;
// Then look for an existing file in the src tree.
@@ -1335,7 +1341,9 @@ namespace build2
// is pull its prerequisites. And they are handy to use as metadata
// carriers.
//
- const target* e (search_existing_target (t.ctx, pk));
+ // Doesn't feel like an alias in the src tree makes much sense.
+ //
+ const target* e (search_existing_target (t.ctx, pk, true /* out_only */));
if (e == nullptr || !(operator>= (e->decl, target_decl::implied)))
fail << "no explicit target for " << pk;
@@ -1451,7 +1459,9 @@ namespace build2
// The first step is like in alias_search(): looks for an existing target
// (but unlike alias, no implied, think `test/: install=false`).
//
- const target* e (search_existing_target (t.ctx, pk));
+ // Likewise, dir{} in the src tree doesn't make much sense.
+ //
+ const target* e (search_existing_target (t.ctx, pk, true /* out_only */));
if (e != nullptr && e->decl == target_decl::real)
return e;
@@ -1500,7 +1510,7 @@ namespace build2
// phase.
//
if (e == nullptr)
- e = search_existing_target (t.ctx, pk);
+ e = search_existing_target (t.ctx, pk, true);
if (e != nullptr && e->decl == target_decl::real)
retest = true;
@@ -1545,7 +1555,7 @@ namespace build2
if (retest)
{
if (e == nullptr)
- e = search_existing_target (t.ctx, pk);
+ e = search_existing_target (t.ctx, pk, true);
if (e != nullptr && e->decl == target_decl::real)
return e;