aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-12-13 14:20:54 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2017-12-13 14:22:07 +0200
commitf11d720f2fb62b46ad17d3aa3850140a4839f114 (patch)
tree7b077efc16b0362283e1857cf974090ee4ce8f26
parent08688bfc12a42a0399bcbdd6fe7d30d8f2486775 (diff)
Implement info meta operation
This meta operation can be used to print basic information (name, version, source/output roots, etc) for one or more projects.
-rw-r--r--build2/b.cli15
-rw-r--r--build2/config/init.cxx4
-rw-r--r--build2/config/operation.cxx6
-rw-r--r--build2/config/operation.hxx4
-rw-r--r--build2/context.cxx1
-rw-r--r--build2/context.hxx2
-rw-r--r--build2/dist/init.cxx2
-rw-r--r--build2/dist/operation.cxx34
-rw-r--r--build2/dist/operation.hxx2
-rw-r--r--build2/file.cxx32
-rw-r--r--build2/file.hxx3
-rw-r--r--build2/install/init.cxx4
-rw-r--r--build2/install/operation.cxx4
-rw-r--r--build2/install/operation.hxx4
-rw-r--r--build2/name.cxx3
-rw-r--r--build2/name.hxx5
-rw-r--r--build2/operation.cxx133
-rw-r--r--build2/operation.hxx12
-rw-r--r--build2/test/init.cxx2
-rw-r--r--build2/test/operation.cxx2
-rw-r--r--build2/test/operation.hxx2
-rw-r--r--build2/variable.cxx4
-rw-r--r--build2/variable.hxx12
-rw-r--r--build2/variable.txx6
24 files changed, 227 insertions, 71 deletions
diff --git a/build2/b.cli b/build2/b.cli
index 8148702..724a676 100644
--- a/build2/b.cli
+++ b/build2/b.cli
@@ -276,7 +276,20 @@ namespace build2
\li|\cb{dist}
Prepare a distribution containing all files necessary to perform all
- operations in a project. Implemented by the \cb{dist} module.||
+ operations in a project. Implemented by the \cb{dist} module.|
+
+ \li|\cb{info}
+
+ Print basic information (name, version, source and output
+ directories, etc) about one or more projects to \cb{STDOUT},
+ separating multiple projects with a blank line. Each project is
+ identified by its root directory target. For example:
+
+ \
+ b info: libfoo/ libbar/
+ \
+
+ ||
The build system has the following built-in and pre-defined operations:
diff --git a/build2/config/init.cxx b/build2/config/init.cxx
index 040aeca..7285671 100644
--- a/build2/config/init.cxx
+++ b/build2/config/init.cxx
@@ -53,8 +53,8 @@ namespace build2
// Register meta-operations. Note that we don't register create_id
// since it will be pre-processed into configure.
//
- rs.meta_operations.insert (configure_id, configure);
- rs.meta_operations.insert (disfigure_id, disfigure);
+ rs.meta_operations.insert (configure_id, mo_configure);
+ rs.meta_operations.insert (disfigure_id, mo_disfigure);
auto& vp (var_pool.rw (rs));
diff --git a/build2/config/operation.cxx b/build2/config/operation.cxx
index 2fad6b0..64919f8 100644
--- a/build2/config/operation.cxx
+++ b/build2/config/operation.cxx
@@ -395,7 +395,7 @@ namespace build2
}
}
- const meta_operation_info configure {
+ const meta_operation_info mo_configure {
configure_id,
"configure",
"configure",
@@ -624,7 +624,7 @@ namespace build2
}
}
- const meta_operation_info disfigure {
+ const meta_operation_info mo_disfigure {
disfigure_id,
"disfigure",
"disfigure",
@@ -807,7 +807,7 @@ namespace build2
}
params.clear ();
- return configure.name;
+ return mo_configure.name;
}
}
}
diff --git a/build2/config/operation.hxx b/build2/config/operation.hxx
index bf9403f..1317d38 100644
--- a/build2/config/operation.hxx
+++ b/build2/config/operation.hxx
@@ -14,8 +14,8 @@ namespace build2
{
namespace config
{
- extern const meta_operation_info configure;
- extern const meta_operation_info disfigure;
+ extern const meta_operation_info mo_configure;
+ extern const meta_operation_info mo_disfigure;
const string&
preprocess_create (const variable_overrides&,
diff --git a/build2/context.cxx b/build2/context.cxx
index b12920c..c4688be 100644
--- a/build2/context.cxx
+++ b/build2/context.cxx
@@ -386,6 +386,7 @@ namespace build2
meta_operation_table.insert (
meta_operation_data ("create", &config::preprocess_create));
meta_operation_table.insert ("dist");
+ meta_operation_table.insert ("info");
operation_table.clear ();
operation_table.insert ("default");
diff --git a/build2/context.hxx b/build2/context.hxx
index fed6bf1..d2daad6 100644
--- a/build2/context.hxx
+++ b/build2/context.hxx
@@ -258,6 +258,8 @@ namespace build2
// Cached variables.
//
+ // Note: consider printing in info meta-operation if adding anything here.
+ //
extern const variable* var_src_root;
extern const variable* var_out_root;
extern const variable* var_src_base;
diff --git a/build2/dist/init.cxx b/build2/dist/init.cxx
index d002868..33ddcd7 100644
--- a/build2/dist/init.cxx
+++ b/build2/dist/init.cxx
@@ -32,7 +32,7 @@ namespace build2
// Register meta-operation.
//
- rs.meta_operations.insert (dist_id, dist);
+ rs.meta_operations.insert (dist_id, mo_dist);
// Enter module variables. Do it during boot in case they get assigned
// in bootstrap.build (which is customary for, e.g., dist.package).
diff --git a/build2/dist/operation.cxx b/build2/dist/operation.cxx
index 6692156..d63e483 100644
--- a/build2/dist/operation.cxx
+++ b/build2/dist/operation.cxx
@@ -54,12 +54,6 @@ namespace build2
}
static void
- dist_match (const values&, action, action_targets&)
- {
- // Don't match anything -- see execute ().
- }
-
- static void
dist_execute (const values&, action, action_targets& ts, bool)
{
tracer trace ("dist_execute");
@@ -249,8 +243,8 @@ namespace build2
// Make sure what we need to distribute is up to date.
//
{
- if (perform.meta_operation_pre != nullptr)
- perform.meta_operation_pre (params, loc);
+ if (mo_perform.meta_operation_pre != nullptr)
+ mo_perform.meta_operation_pre (params, loc);
// This is a hack since according to the rules we need to completely
// reset the state. We could have done that (i.e., saved target names
@@ -259,24 +253,24 @@ namespace build2
// the dist mete-opreation is "compatible" with perform).
//
size_t on (current_on);
- set_current_mif (perform);
+ set_current_mif (mo_perform);
current_on = on + 1;
- if (perform.operation_pre != nullptr)
- perform.operation_pre (params, update_id);
+ if (mo_perform.operation_pre != nullptr)
+ mo_perform.operation_pre (params, update_id);
- set_current_oif (update);
+ set_current_oif (op_update);
action a (perform_id, update_id);
- perform.match (params, a, files);
- perform.execute (params, a, files, true); // Run quiet.
+ mo_perform.match (params, a, files);
+ mo_perform.execute (params, a, files, true); // Run quiet.
- if (perform.operation_post != nullptr)
- perform.operation_post (params, update_id);
+ if (mo_perform.operation_post != nullptr)
+ mo_perform.operation_post (params, update_id);
- if (perform.meta_operation_post != nullptr)
- perform.meta_operation_post (params);
+ if (mo_perform.meta_operation_post != nullptr)
+ mo_perform.meta_operation_post (params);
}
dir_path td (dist_root / dir_path (dist_package));
@@ -525,7 +519,7 @@ namespace build2
}
}
- const meta_operation_info dist {
+ const meta_operation_info mo_dist {
dist_id,
"dist",
"distribute",
@@ -536,7 +530,7 @@ namespace build2
&dist_operation_pre,
&load, // normal load
&search, // normal search
- &dist_match,
+ nullptr, // no match (see execute()).
&dist_execute,
nullptr, // operation post
nullptr // meta-operation post
diff --git a/build2/dist/operation.hxx b/build2/dist/operation.hxx
index c72e467..0639688 100644
--- a/build2/dist/operation.hxx
+++ b/build2/dist/operation.hxx
@@ -14,7 +14,7 @@ namespace build2
{
namespace dist
{
- extern const meta_operation_info dist;
+ extern const meta_operation_info mo_dist;
}
}
diff --git a/build2/file.cxx b/build2/file.cxx
index 1ad3500..edd3e28 100644
--- a/build2/file.cxx
+++ b/build2/file.cxx
@@ -38,6 +38,23 @@ namespace build2
//
const path config_file (build_dir / "config.build");
+ ostream&
+ operator<< (ostream& os, const subprojects& sps)
+ {
+ for (auto b (sps.begin ()), i (b); os && i != sps.end (); ++i)
+ {
+ // See find_subprojects() for details.
+ //
+ const string& n (path::traits::is_separator (i->first.back ())
+ ? empty_string
+ : i->first);
+
+ os << (i != b ? " " : "") << n << '@' << i->second;
+ }
+
+ return os;
+ }
+
bool
is_src_root (const dir_path& d)
{
@@ -151,12 +168,13 @@ namespace build2
//
if (first)
{
- rs.meta_operations.insert (noop_id, noop);
- rs.meta_operations.insert (perform_id, perform);
+ rs.meta_operations.insert (noop_id, mo_noop);
+ rs.meta_operations.insert (perform_id, mo_perform);
+ rs.meta_operations.insert (info_id, mo_info);
- rs.operations.insert (default_id, default_);
- rs.operations.insert (update_id, update);
- rs.operations.insert (clean_id, clean);
+ rs.operations.insert (default_id, op_default);
+ rs.operations.insert (update_id, op_update);
+ rs.operations.insert (clean_id, op_clean);
}
// If this is already a root scope, verify that things are
@@ -486,10 +504,10 @@ namespace build2
// 'project' variable stays empty, here we come up with a surrogate
// name for a key. The idea is that such a key should never conflict
// with a real project name. We ensure this by using the project's
- // sub-directory and appending trailing '/' to it.
+ // sub-directory and appending a trailing directory separator to it.
//
if (name.empty ())
- name = dir.posix_string () + '/';
+ name = dir.posix_string () + path::traits::directory_separator;
// @@ Can't use move() because we may need the values in diagnostics
// below. Looks like C++17 try_emplace() is what we need.
diff --git a/build2/file.hxx b/build2/file.hxx
index d946c88..f334d8c 100644
--- a/build2/file.hxx
+++ b/build2/file.hxx
@@ -21,6 +21,9 @@ namespace build2
using subprojects = std::map<string, dir_path>;
+ ostream&
+ operator<< (ostream&, const subprojects&); // Print as name@dir sequence.
+
extern const dir_path build_dir; // build
extern const dir_path bootstrap_dir; // build/bootstrap
diff --git a/build2/install/init.cxx b/build2/install/init.cxx
index b5fd007..3e4e1ff 100644
--- a/build2/install/init.cxx
+++ b/build2/install/init.cxx
@@ -142,8 +142,8 @@ namespace build2
// Register the install and uninstall operations.
//
- r.operations.insert (install_id, install);
- r.operations.insert (uninstall_id, uninstall);
+ r.operations.insert (install_id, op_install);
+ r.operations.insert (uninstall_id, op_uninstall);
}
static const path cmd ("install");
diff --git a/build2/install/operation.cxx b/build2/install/operation.cxx
index 5405c63..5279b3d 100644
--- a/build2/install/operation.cxx
+++ b/build2/install/operation.cxx
@@ -28,7 +28,7 @@ namespace build2
// those things get racy. Also, since all we do here is creating/removing
// files, there is not going to be much speedup from doing it in parallel.
- const operation_info install {
+ const operation_info op_install {
install_id,
"install",
"install",
@@ -50,7 +50,7 @@ namespace build2
// link.exe only creates a DLL's import library if there are any exported
// symbols).
//
- const operation_info uninstall {
+ const operation_info op_uninstall {
uninstall_id,
"uninstall",
"uninstall",
diff --git a/build2/install/operation.hxx b/build2/install/operation.hxx
index 1529621..0d96faf 100644
--- a/build2/install/operation.hxx
+++ b/build2/install/operation.hxx
@@ -14,8 +14,8 @@ namespace build2
{
namespace install
{
- extern const operation_info install;
- extern const operation_info uninstall;
+ extern const operation_info op_install;
+ extern const operation_info op_uninstall;
}
}
diff --git a/build2/name.cxx b/build2/name.cxx
index fe2955a..d1f3bd7 100644
--- a/build2/name.cxx
+++ b/build2/name.cxx
@@ -12,6 +12,9 @@
namespace build2
{
+ const name empty_name;
+ const names empty_names;
+
string
to_string (const name& n)
{
diff --git a/build2/name.hxx b/build2/name.hxx
index 6f329ef..4394236 100644
--- a/build2/name.hxx
+++ b/build2/name.hxx
@@ -90,6 +90,8 @@ namespace build2
compare (const name&) const;
};
+ extern const name empty_name;
+
inline bool
operator== (const name& x, const name& y) {return x.compare (y) == 0;}
@@ -140,9 +142,10 @@ namespace build2
// (names) and typed ones (vector<name>).
//
using names = small_vector<name, 1>;
-
using names_view = vector_view<const name>;
+ extern const names empty_names;
+
// The same semantics as to_stream(name).
//
ostream&
diff --git a/build2/operation.cxx b/build2/operation.cxx
index eb96559..d917f1e 100644
--- a/build2/operation.cxx
+++ b/build2/operation.cxx
@@ -4,6 +4,8 @@
#include <build2/operation.hxx>
+#include <iostream> // cout
+
#include <build2/file.hxx>
#include <build2/dump.hxx>
#include <build2/scope.hxx>
@@ -41,6 +43,25 @@ namespace build2
return os;
}
+ // noop
+ //
+ const meta_operation_info mo_noop {
+ noop_id,
+ "noop",
+ "", // Presumably we will never need these since we are not going
+ "", // to do anything.
+ "",
+ "",
+ nullptr, // meta-operation pre
+ nullptr, // operation pre
+ &load,
+ nullptr, // search
+ nullptr, // match
+ nullptr, // execute
+ nullptr, // operation post
+ nullptr // meta-operation post
+ };
+
// perform
//
void
@@ -395,43 +416,117 @@ namespace build2
assert (dependency_count.load (memory_order_relaxed) == 0);
}
- const meta_operation_info noop {
- noop_id,
- "noop",
- "", // Presumably we will never need these since we are not going
- "", // to do anything.
+ const meta_operation_info mo_perform {
+ perform_id,
+ "perform",
+ "",
+ "",
"",
"",
nullptr, // meta-operation pre
nullptr, // operation pre
&load,
- nullptr, // search
- nullptr, // match
- nullptr, // execute
+ &search,
+ &match,
+ &execute,
nullptr, // operation post
nullptr // meta-operation post
};
- const meta_operation_info perform {
- perform_id,
- "perform",
+ // info
+ //
+ static operation_id
+ info_operation_pre (const values&, operation_id o)
+ {
+ if (o != default_id)
+ fail << "explicit operation specified for meta-operation info";
+
+ return o;
+ }
+
+ void
+ info_load (const values&,
+ scope& rs,
+ const path&,
+ const dir_path& out_base,
+ const dir_path& src_base,
+ const location& l)
+ {
+ // For info we don't want to go any further than bootstrap so that it can
+ // be used in pretty much any situation (unresolved imports, etc). We do
+ // need to setup root as base though.
+
+ if (rs.out_path () != out_base || rs.src_path () != src_base)
+ fail (l) << "meta-operation info target must be project root directory";
+
+ setup_base (scopes.rw (rs).insert (out_base, false), out_base, src_base);
+ }
+
+ void
+ info_search (const values&,
+ const scope& rs,
+ const scope&,
+ const target_key& tk,
+ const location& l,
+ action_targets& ts)
+ {
+ // Collect all the projects we need to print information about.
+
+ // We've already verified the target is in the project root. Now verify
+ // it is dir{}.
+ //
+ if (!tk.type->is_a<dir> ())
+ fail (l) << "meta-operation info target must be project root directory";
+
+ ts.push_back (&rs);
+ }
+
+ static void
+ info_execute (const values&, action, action_targets& ts, bool)
+ {
+ for (size_t i (0); i != ts.size (); ++i)
+ {
+ // Separate projects with blank lines.
+ //
+ if (i != 0)
+ cout << endl;
+
+ const scope& s (*static_cast<const scope*> (ts[i]));
+
+ // This could be a simple project that doesn't set project name.
+ //
+ cout
+ << "project: " << cast_empty<string> (s[var_project]) << endl
+ << "version: " << cast_empty<string> (s[var_version]) << endl
+ << "summary: " << cast_empty<string> (s[var_project_summary]) << endl
+ << "url: " << cast_empty<string> (s[var_project_url]) << endl
+ << "src_root: " << cast<dir_path> (s[var_src_root]) << endl
+ << "out_root: " << cast<dir_path> (s[var_out_root]) << endl
+ << "amalgamation: " << cast_empty<dir_path> (s[var_amalgamation]) << endl
+ << "subprojects: " << cast_empty<subprojects> (s[var_subprojects]) << endl;
+ }
+ }
+
+ const meta_operation_info mo_info {
+ info_id,
+ "info",
"",
"",
"",
"",
nullptr, // meta-operation pre
- nullptr, // operation pre
- &load,
- &search,
- &match,
- &execute,
+ &info_operation_pre,
+ &info_load,
+ &info_search,
+ nullptr, // match
+ &info_execute,
nullptr, // operation post
nullptr // meta-operation post
};
// operations
//
- const operation_info default_ {
+ const operation_info op_default {
default_id,
"<default>",
"",
@@ -444,7 +539,7 @@ namespace build2
nullptr
};
- const operation_info update {
+ const operation_info op_update {
update_id,
"update",
"update",
@@ -457,7 +552,7 @@ namespace build2
nullptr
};
- const operation_info clean {
+ const operation_info op_clean {
clean_id,
"clean",
"clean",
diff --git a/build2/operation.hxx b/build2/operation.hxx
index 24340dd..abd85c0 100644
--- a/build2/operation.hxx
+++ b/build2/operation.hxx
@@ -111,6 +111,7 @@ namespace build2
const meta_operation_id disfigure_id = 4;
const meta_operation_id create_id = 5;
const meta_operation_id dist_id = 6;
+ const meta_operation_id info_id = 7;
// The default operation is a special marker that can be used to indicate
// that no operation was explicitly specified by the user. If adding
@@ -279,8 +280,9 @@ namespace build2
void
execute (const values&, action, const action_targets&, bool quiet);
- extern const meta_operation_info noop;
- extern const meta_operation_info perform;
+ extern const meta_operation_info mo_noop;
+ extern const meta_operation_info mo_perform;
+ extern const meta_operation_info mo_info;
// Operation info.
//
@@ -323,9 +325,9 @@ namespace build2
// Built-in operations.
//
- extern const operation_info default_;
- extern const operation_info update;
- extern const operation_info clean;
+ extern const operation_info op_default;
+ extern const operation_info op_update;
+ extern const operation_info op_clean;
// Global meta/operation tables. Each registered meta/operation
// is assigned an id which is used as an index in the per-project
diff --git a/build2/test/init.cxx b/build2/test/init.cxx
index 93ca1e4..1c7a2b4 100644
--- a/build2/test/init.cxx
+++ b/build2/test/init.cxx
@@ -31,7 +31,7 @@ namespace build2
// Register the test operation.
//
- rs.operations.insert (test_id, test);
+ rs.operations.insert (test_id, op_test);
// Enter module variables. Do it during boot in case they get assigned
// in bootstrap.build.
diff --git a/build2/test/operation.cxx b/build2/test/operation.cxx
index 46b9366..e4591e4 100644
--- a/build2/test/operation.cxx
+++ b/build2/test/operation.cxx
@@ -22,7 +22,7 @@ namespace build2
return mo != disfigure_id ? update_id : 0;
}
- const operation_info test {
+ const operation_info op_test {
test_id,
"test",
"test",
diff --git a/build2/test/operation.hxx b/build2/test/operation.hxx
index d834edf..774e8d0 100644
--- a/build2/test/operation.hxx
+++ b/build2/test/operation.hxx
@@ -14,7 +14,7 @@ namespace build2
{
namespace test
{
- extern const operation_info test;
+ extern const operation_info op_test;
}
}
diff --git a/build2/variable.cxx b/build2/variable.cxx
index ed9527e..d8b48d0 100644
--- a/build2/variable.cxx
+++ b/build2/variable.cxx
@@ -406,6 +406,10 @@ namespace build2
throw invalid_argument (m);
}
+ // names
+ //
+ const names& value_traits<names>::empty_instance = empty_names;
+
// bool value
//
bool value_traits<bool>::
diff --git a/build2/variable.hxx b/build2/variable.hxx
index bba2208..51cc350 100644
--- a/build2/variable.hxx
+++ b/build2/variable.hxx
@@ -546,6 +546,14 @@ namespace build2
static int
simple_compare (const value&, const value&);
+ // names
+ //
+ template <>
+ struct value_traits<names>
+ {
+ static const names& empty_instance;
+ };
+
// bool
//
template <>
@@ -783,6 +791,8 @@ namespace build2
static void prepend (value&, vector<T>&&);
static bool empty (const vector<T>& x) {return x.empty ();}
+ static const vector<T> empty_instance;
+
// Make sure these are static-initialized together. Failed that VC will
// make sure it's done in the wrong order.
//
@@ -809,6 +819,8 @@ namespace build2
return append (v, move (x));}
static bool empty (const map<K, V>& x) {return x.empty ();}
+ static const map<K, V> empty_instance;
+
// Make sure these are static-initialized together. Failed that VC will
// make sure it's done in the wrong order.
//
diff --git a/build2/variable.txx b/build2/variable.txx
index e374f22..c2dbea9 100644
--- a/build2/variable.txx
+++ b/build2/variable.txx
@@ -389,6 +389,9 @@ namespace build2
}
template <typename T>
+ const vector<T> value_traits<vector<T>>::empty_instance;
+
+ template <typename T>
const typename value_traits<vector<T>>::value_type_ex
value_traits<vector<T>>::value_type = build2::value_type // VC14 wants =.
{
@@ -558,6 +561,9 @@ namespace build2
}
template <typename K, typename V>
+ const std::map<K,V> value_traits<std::map<K, V>>::empty_instance;
+
+ template <typename K, typename V>
const typename value_traits<std::map<K, V>>::value_type_ex
value_traits<std::map<K, V>>::value_type = build2::value_type // VC14 wants =
{