aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-03-14 11:37:14 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2017-03-14 11:37:14 +0200
commit233255f0e14f364841751755958375fe27380ba6 (patch)
tree1571f125ad89f729cbf0c3d7c0b09aba8fe0fc20
parentf262632b20628136369889ebc67a65b252b233af (diff)
Implement implied buildfile support
In essence, if the buildfile is: ./: */ Then it can be omitted entirely (provided there is at least one subdirectory).
-rw-r--r--build2/b.cxx36
-rw-r--r--build2/config/operation.cxx1
-rw-r--r--build2/operation15
-rw-r--r--build2/operation.cxx19
-rw-r--r--build2/spec2
-rw-r--r--build2/target7
-rw-r--r--build2/target.cxx22
-rw-r--r--build2/target.txx46
-rw-r--r--tests/function/buildfile5
-rw-r--r--tests/search/buildfile5
-rw-r--r--tests/search/dir/testscript3
-rw-r--r--tests/variable/buildfile5
-rw-r--r--unit-tests/buildfile5
-rw-r--r--unit-tests/test/script/buildfile5
14 files changed, 121 insertions, 55 deletions
diff --git a/build2/b.cxx b/build2/b.cxx
index 15ace65..b13300e 100644
--- a/build2/b.cxx
+++ b/build2/b.cxx
@@ -911,16 +911,31 @@ main (int argc, char* argv[])
trace << " amalgamat: " << cast<dir_path> (l);
}
+ path bf;
const path& bfn (ops.buildfile ());
- path bf (bfn.string () != "-" ? src_base / bfn : bfn);
- // If we were guessing src_base, check that the buildfile
- // exists and if not, issue more detailed diagnostics.
- //
- if (guessing && bf.string () != "-" && !exists (bf))
- fail << bf << " does not exist"
- << info << "consider explicitly specifying src_base "
- << "for " << tn;
+ if (bfn.string () != "-")
+ {
+ bf = src_base / bfn;
+
+ if (!exists (bf))
+ {
+ // If we were guessing src_base then don't try any implied
+ // buildfile tricks.
+ //
+ if (guessing)
+ fail << bf << " does not exist" <<
+ info << "consider explicitly specifying src_base for " << tn;
+
+ // If the target is a directory and src_base exists, then assume
+ // implied buildfile; see dir::search_implied().
+ //
+ if ((tn.directory () || tn.type == "dir") && exists (src_base))
+ bf.clear ();
+ }
+ }
+ else
+ bf = bfn;
// Enter project-wide (as opposed to global) variable overrides.
//
@@ -1040,7 +1055,10 @@ main (int argc, char* argv[])
? out_src (d, rs)
: dir_path ());
- mif->search (rs, target_key {ti, &d, &out, &tn.value, e}, l, tgs);
+ mif->search (rs, bs,
+ target_key {ti, &d, &out, &tn.value, e},
+ l,
+ tgs);
}
} // target
diff --git a/build2/config/operation.cxx b/build2/config/operation.cxx
index 951da30..a029b60 100644
--- a/build2/config/operation.cxx
+++ b/build2/config/operation.cxx
@@ -479,6 +479,7 @@ namespace build2
static void
disfigure_search (const scope& root,
+ const scope&,
const target_key&,
const location&,
action_targets& ts)
diff --git a/build2/operation b/build2/operation
index e6c34d6..39bb799 100644
--- a/build2/operation
+++ b/build2/operation
@@ -206,6 +206,7 @@ namespace build2
const location&);
void (*search) (const scope& root,
+ const scope& base,
const target_key&,
const location&,
action_targets&);
@@ -230,17 +231,21 @@ namespace build2
// scope.
//
void
- load (scope& root,
- const path& buildfile,
- const dir_path& out_base,
- const dir_path& src_base,
+ load (scope&,
+ const path&,
+ const dir_path&,
+ const dir_path&,
const location&);
// Search and match the target. This is the default implementation
// that does just that and adds a pointer to the target to the list.
//
void
- search (const scope&, const target_key&, const location&, action_targets&);
+ search (const scope&,
+ const scope&,
+ const target_key&,
+ const location&,
+ action_targets&);
void
match (action, action_targets&);
diff --git a/build2/operation.cxx b/build2/operation.cxx
index ff2051d..b821b1d 100644
--- a/build2/operation.cxx
+++ b/build2/operation.cxx
@@ -60,25 +60,32 @@ namespace build2
auto i (scopes.rw (root).insert (out_base, false));
scope& base (setup_base (i, out_base, src_base));
- // Load the buildfile unless it has already been loaded.
+ // Load the buildfile unless it is implied.
//
- source_once (root, base, bf, root);
+ if (!bf.empty ())
+ source_once (root, base, bf, root);
}
void
search (const scope&,
+ const scope& bs,
const target_key& tk,
const location& l,
action_targets& ts)
{
tracer trace ("search");
- phase_lock pl (run_phase::match); // Never switched.
+ phase_lock pl (run_phase::match);
- if (const target* t = targets.find (tk, trace))
- ts.push_back (t);
- else
+ const target* t (targets.find (tk, trace));
+
+ if (t == nullptr && tk.is_a<dir> ())
+ t = dir::search_implied (bs, tk, trace);
+
+ if (t == nullptr)
fail (l) << "unknown target " << tk;
+
+ ts.push_back (t);
}
void
diff --git a/build2/spec b/build2/spec
index 7a7e55e..92b56ec 100644
--- a/build2/spec
+++ b/build2/spec
@@ -28,7 +28,7 @@ namespace build2
//
scope* root_scope = nullptr;
dir_path out_base;
- path buildfile;
+ path buildfile; // Empty if implied.
};
struct opspec: vector<targetspec>
diff --git a/build2/target b/build2/target
index ef1e34d..c196060 100644
--- a/build2/target
+++ b/build2/target
@@ -307,7 +307,7 @@ namespace build2
prerequisites () const;
// Swap-in a list of prerequisites. Return false if unsuccessful (i.e.,
- // some beat us to it). Note that it can be called on const target.
+ // someone beat us to it). Note that it can be called on const target.
//
bool
prerequisites (prerequisites_type&&) const;
@@ -1473,6 +1473,11 @@ namespace build2
public:
static const target_type static_type;
virtual const target_type& dynamic_type () const {return static_type;}
+
+ public:
+ template <typename K>
+ static const target*
+ search_implied (const scope&, const K&, tracer&);
};
// While a filesystem directory is mtime-based, the semantics is
diff --git a/build2/target.cxx b/build2/target.cxx
index 676dc6b..668db92 100644
--- a/build2/target.cxx
+++ b/build2/target.cxx
@@ -14,6 +14,7 @@
#include <build2/diagnostics>
using namespace std;
+using namespace butl;
namespace build2
{
@@ -732,7 +733,7 @@ namespace build2
const target* t (search_existing_target (pk));
if (t == nullptr || t->implied)
- fail << "no explicit target for prerequisite " << pk;
+ fail << "no explicit target for " << pk;
return t;
}
@@ -762,7 +763,10 @@ namespace build2
return t;
// If not found (or is implied), then try to load the corresponding
- // buildfile which would normally define this target.
+ // buildfile (which would normally define this target). Failed that, see
+ // if we can assume an implied buildfile which would be equivalent to:
+ //
+ // ./: */
//
const dir_path& d (*pk.tk.dir);
@@ -809,18 +813,25 @@ namespace build2
scope& base (sp.first);
scope& root (*sp.second);
- path bf (base.src_path () / "buildfile");
+ const dir_path& src_base (base.src_path ());
+
+ path bf (src_base / "buildfile");
if (exists (bf))
{
l5 ([&]{trace << "loading buildfile " << bf << " for " << pk;});
retest = source_once (root, base, bf, root);
}
+ else if (exists (src_base))
+ {
+ t = dir::search_implied (base, pk, trace);
+ retest = (t != nullptr);
+ }
}
}
assert (phase == run_phase::match);
- // If we loaded the buildfile, examine the target again.
+ // If we loaded/implied the buildfile, examine the target again.
//
if (retest)
{
@@ -832,8 +843,7 @@ namespace build2
}
}
- fail << "no explicit target for prerequisite " << pk <<
- info << "did you forget to include the corresponding buildfile?" << endf;
+ fail << "no explicit target for " << pk << endf;
}
static bool
diff --git a/build2/target.txx b/build2/target.txx
index dd087c0..d854ed2 100644
--- a/build2/target.txx
+++ b/build2/target.txx
@@ -2,6 +2,8 @@
// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
+#include <butl/filesystem> // dir_iterator
+
#include <build2/scope>
#include <build2/diagnostics>
#include <build2/prerequisite>
@@ -135,4 +137,48 @@ namespace build2
return false;
}
+
+ // dir
+ //
+ template <typename K>
+ const target* dir::
+ search_implied (const scope& base, const K& k, tracer& trace)
+ {
+ using namespace butl;
+
+ // See if we have any subdirectories.
+ //
+ prerequisites_type ps;
+
+ for (const dir_entry& e: dir_iterator (base.src_path ()))
+ {
+ if (e.type () == entry_type::directory)
+ ps.push_back (
+ prerequisite (nullopt,
+ dir::static_type,
+ dir_path (e.path ().representation ()),
+ dir_path (), // In the out tree.
+ string (),
+ nullopt,
+ base));
+ }
+
+ if (ps.empty ())
+ return nullptr;
+
+ l5 ([&]{trace << "implying buildfile for " << k;});
+
+ // We behave as if this target was explicitly mentioned in the (implied)
+ // buildfile. Thus not implied.
+ //
+ target& t (targets.insert (dir::static_type,
+ base.out_path (),
+ dir_path (),
+ string (),
+ nullopt,
+ false,
+ trace).first);
+ t.prerequisites (move (ps));
+ return &t;
+ }
}
diff --git a/tests/function/buildfile b/tests/function/buildfile
deleted file mode 100644
index 8034f2b..0000000
--- a/tests/function/buildfile
+++ /dev/null
@@ -1,5 +0,0 @@
-# file : tests/function/buildfile
-# copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
-# license : MIT; see accompanying LICENSE file
-
-./: builtin/ path/
diff --git a/tests/search/buildfile b/tests/search/buildfile
deleted file mode 100644
index a72ca71..0000000
--- a/tests/search/buildfile
+++ /dev/null
@@ -1,5 +0,0 @@
-# file : tests/search/buildfile
-# copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
-# license : MIT; see accompanying LICENSE file
-
-./: dir/
diff --git a/tests/search/dir/testscript b/tests/search/dir/testscript
index d580c4f..4cd368b 100644
--- a/tests/search/dir/testscript
+++ b/tests/search/dir/testscript
@@ -20,8 +20,7 @@ EOI
: no-buildfile
:
$* <'./: foo/' 2>>/EOE != 0
-error: no explicit target for prerequisite ../:dir{foo/}
- info: did you forget to include the corresponding buildfile?
+error: no explicit target for ../:dir{foo/}
EOE
: basic
diff --git a/tests/variable/buildfile b/tests/variable/buildfile
deleted file mode 100644
index 65a0791..0000000
--- a/tests/variable/buildfile
+++ /dev/null
@@ -1,5 +0,0 @@
-# file : tests/variable/buildfile
-# copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
-# license : MIT; see accompanying LICENSE file
-
-./: override/
diff --git a/unit-tests/buildfile b/unit-tests/buildfile
deleted file mode 100644
index 0e39bfe..0000000
--- a/unit-tests/buildfile
+++ /dev/null
@@ -1,5 +0,0 @@
-# file : unit-tests/buildfile
-# copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
-# license : MIT; see accompanying LICENSE file
-
-./: function/ lexer/ scheduler/ test/script/
diff --git a/unit-tests/test/script/buildfile b/unit-tests/test/script/buildfile
deleted file mode 100644
index 7e2aa9b..0000000
--- a/unit-tests/test/script/buildfile
+++ /dev/null
@@ -1,5 +0,0 @@
-# file : unit-tests/test/script/buildfile
-# copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
-# license : MIT; see accompanying LICENSE file
-
-./: lexer/ parser/ regex/