aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2022-11-16 07:52:11 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2022-11-16 07:52:11 +0200
commitf80c8ff7ff3b1eef22a3c90943f324d45d855b97 (patch)
treef44a25aa71de05e11c417dcc01cc3f6b9eca97ee
parent44b0a5989f76570fc19dc41314f31c4fa9c2039b (diff)
Initial low verbosity diagnostics rework
-rw-r--r--libbuild2/adhoc-rule-buildscript.cxx8
-rw-r--r--libbuild2/adhoc-rule-cxx.cxx20
-rw-r--r--libbuild2/algorithm.cxx63
-rw-r--r--libbuild2/algorithm.hxx6
-rw-r--r--libbuild2/bash/rule.hxx2
-rw-r--r--libbuild2/bin/def-rule.cxx6
-rw-r--r--libbuild2/cc/compile-rule.cxx2
-rw-r--r--libbuild2/cc/install-rule.cxx14
-rw-r--r--libbuild2/cc/link-rule.cxx2
-rw-r--r--libbuild2/cc/pkgconfig.cxx6
-rw-r--r--libbuild2/config/operation.cxx17
-rw-r--r--libbuild2/diagnostics.cxx132
-rw-r--r--libbuild2/diagnostics.hxx167
-rw-r--r--libbuild2/diagnostics.ixx44
-rw-r--r--libbuild2/dist/operation.cxx16
-rw-r--r--libbuild2/file.cxx23
-rw-r--r--libbuild2/file.hxx2
-rw-r--r--libbuild2/filesystem.cxx59
-rw-r--r--libbuild2/filesystem.hxx6
-rw-r--r--libbuild2/filesystem.txx8
-rw-r--r--libbuild2/in/rule.cxx2
-rw-r--r--libbuild2/install/rule.cxx142
-rw-r--r--libbuild2/install/rule.hxx13
-rw-r--r--libbuild2/rule.cxx2
-rw-r--r--libbuild2/test/rule.cxx20
-rw-r--r--libbuild2/version/rule.hxx2
-rw-r--r--tests/cc/modules/modules.testscript2
-rw-r--r--tests/test/simple/generated/testscript2
28 files changed, 664 insertions, 124 deletions
diff --git a/libbuild2/adhoc-rule-buildscript.cxx b/libbuild2/adhoc-rule-buildscript.cxx
index 8208ab7..e4960c9 100644
--- a/libbuild2/adhoc-rule-buildscript.cxx
+++ b/libbuild2/adhoc-rule-buildscript.cxx
@@ -1496,7 +1496,7 @@ namespace build2
{
if (verb == 1)
{
- // @@ TODO (and in default_action() below):
+ // @@ DIAG (and in default_action() below):
//
// - we are printing target, not source (like in most other places)
//
@@ -1521,7 +1521,7 @@ namespace build2
false /* leave */));
if (verb == 1)
- text << diag;
+ text << diag; // @@ DIAG
}
if (exec_body)
@@ -1625,7 +1625,7 @@ namespace build2
{
if (verb == 1)
{
- // @@ TODO: as above (execute_update_file()).
+ // @@ DIAG: as above (execute_update_file()).
//
text << *script.diag_name << ' ' << t;
}
@@ -1643,7 +1643,7 @@ namespace build2
!exec_body /* leave */));
if (verb == 1)
- text << diag;
+ text << diag; // @@ DIAG
}
if (exec_body)
diff --git a/libbuild2/adhoc-rule-cxx.cxx b/libbuild2/adhoc-rule-cxx.cxx
index 8230fd8..5c08a09 100644
--- a/libbuild2/adhoc-rule-cxx.cxx
+++ b/libbuild2/adhoc-rule-cxx.cxx
@@ -326,6 +326,17 @@ namespace build2
if (!create && (create = !check_sig (bf, psig)))
rmdir_r (ctx, pd, false, verbosity); // Never dry-run.
+ auto diag = [verbosity] (const path& f)
+ {
+ if (verb >= verbosity)
+ {
+ if (verb >= 2)
+ text << "cat >" << f;
+ else if (verb)
+ print_diag ("save", f);
+ }
+ };
+
path of;
ofdstream ofs;
@@ -356,8 +367,7 @@ namespace build2
//
of = path (pd / "rule.cxx");
- if (verb >= verbosity)
- text << (verb >= 2 ? "cat >" : "save ") << of;
+ diag (of);
ofs.open (of);
@@ -487,8 +497,7 @@ namespace build2
//
of = bf;
- if (verb >= verbosity)
- text << (verb >= 2 ? "cat >" : "save ") << of;
+ diag (of);
ofs.open (of);
@@ -560,8 +569,7 @@ namespace build2
entry_time et (file_time (of));
- if (verb >= verbosity)
- text << (verb >= 2 ? "cat >" : "save ") << of;
+ diag (of);
ofs.open (of);
diff --git a/libbuild2/algorithm.cxx b/libbuild2/algorithm.cxx
index 8f399dd..045024b 100644
--- a/libbuild2/algorithm.cxx
+++ b/libbuild2/algorithm.cxx
@@ -1637,12 +1637,12 @@ namespace build2
case mode::overwrite: c = l.to_directory () ? "cp -r" : "cp"; break;
}
- // Note: 'ln foo/ bar/' means a different thing.
+ // Note: 'ln foo/ bar/' means a different thing (and below).
//
if (verb >= 2)
text << c << ' ' << p.string () << ' ' << l.string ();
else
- text << c << ' ' << f << " -> " << d;
+ print_diag (c, f, d);
}
}
@@ -1682,10 +1682,15 @@ namespace build2
case mode::overwrite: c = l.to_directory () ? "cp -r" : "cp"; break;
}
+ // Note: 'ln foo/ bar/' means a different thing (and above) so strip
+ // trailing directory separator (but keep as path for relative).
+ //
if (verb >= 2)
text << c << ' ' << p.string () << ' ' << l.string ();
else
- text << c << ' ' << p.string () << " -> " << d;
+ print_diag (c,
+ p.to_directory () ? path (p.string ()) : p,
+ d);
}
}
@@ -1737,6 +1742,8 @@ namespace build2
const path& p, const path& l, backlink_mode om,
uint16_t verbosity)
{
+ assert (verbosity >= 2);
+
using mode = backlink_mode;
bool d (l.to_directory ());
@@ -1872,6 +1879,11 @@ namespace build2
//
// Note that here the dry-run mode is handled by the filesystem functions.
+ // Note that if we ever need to support level 1 for some reason, maybe
+ // consider showing the target, for example, `unlink exe{hello} <- dir/`?
+ //
+ assert (v >= 2);
+
using mode = backlink_mode;
if (l.to_directory ())
@@ -2898,7 +2910,7 @@ namespace build2
target_state
noop_action (action a, const target& t)
{
- text << "noop action triggered for " << diag_doing (a, t);
+ error << "noop action triggered for " << diag_doing (a, t);
assert (false); // We shouldn't be called (see set_recipe()).
return target_state::unchanged;
}
@@ -2998,7 +3010,7 @@ namespace build2
case rmdir_status::not_empty:
{
if (verb >= 3)
- text << dp << " is current working directory, not removing";
+ info << dp << " is current working directory, not removing";
break;
}
case rmdir_status::not_exist:
@@ -3108,6 +3120,9 @@ namespace build2
// Now clean the primary target and its prerequisited in the reverse order
// of update: first remove the file, then clean the prerequisites.
//
+ // @@ DIAG: we print removal of individual ad hoc members above instead
+ // of as group at once ({hxx, cxx}{...}).
+ //
if (clean && !fp.empty () && rmfile (fp, ft))
tr = target_state::changed;
@@ -3129,10 +3144,20 @@ namespace build2
{
if (verb > (ctx.current_diag_noise ? 0 : 1) && verb < 3)
{
- if (ed)
- text << "rm -r " << path_cast<dir_path> (ep);
- else
- text << "rm " << ep;
+ if (verb >= 2)
+ {
+ if (ed)
+ text << "rm -r " << path_cast<dir_path> (ep);
+ else
+ text << "rm " << ep;
+ }
+ else if (verb)
+ {
+ if (ed)
+ print_diag ("rm -r", path_cast<dir_path> (ep));
+ else
+ print_diag ("rm", ep);
+ }
}
}
@@ -3165,6 +3190,8 @@ namespace build2
{
if (const target* m = gv.members[gv.count - 1])
{
+ // @@ DIAG: do we want to show removal of group or each member?
+ //
if (rmfile (m->as<file> ().path (), *m))
tr |= target_state::changed;
}
@@ -3177,10 +3204,20 @@ namespace build2
{
if (verb > (ctx.current_diag_noise ? 0 : 1) && verb < 3)
{
- if (ed)
- text << "rm -r " << path_cast<dir_path> (ep);
- else
- text << "rm " << ep;
+ if (verb >= 2)
+ {
+ if (ed)
+ text << "rm -r " << path_cast<dir_path> (ep);
+ else
+ text << "rm " << ep;
+ }
+ else if (verb)
+ {
+ if (ed)
+ print_diag ("rm -r", path_cast<dir_path> (ep));
+ else
+ print_diag ("rm", ep);
+ }
}
}
diff --git a/libbuild2/algorithm.hxx b/libbuild2/algorithm.hxx
index 756c3fe..e9245f4 100644
--- a/libbuild2/algorithm.hxx
+++ b/libbuild2/algorithm.hxx
@@ -930,6 +930,8 @@ namespace build2
// Update/clean a backlink issuing appropriate diagnostics at appropriate
// levels depending on the overload and the changed argument.
//
+ // Note that these functions assume (target.leaf() == link.leaf ()).
+ //
enum class backlink_mode
{
link, // Make a symbolic link if possible, hard otherwise.
@@ -952,6 +954,8 @@ namespace build2
bool changed,
backlink_mode = backlink_mode::link);
+ // Note: verbosite should be 2 or greater.
+ //
LIBBUILD2_SYMEXPORT void
update_backlink (context&,
const path& target,
@@ -959,6 +963,8 @@ namespace build2
backlink_mode = backlink_mode::link,
uint16_t verbosity = 3);
+ // Note: verbosite should be 2 or greater.
+ //
LIBBUILD2_SYMEXPORT void
clean_backlink (context&,
const path& link,
diff --git a/libbuild2/bash/rule.hxx b/libbuild2/bash/rule.hxx
index 5bd7fa7..444d176 100644
--- a/libbuild2/bash/rule.hxx
+++ b/libbuild2/bash/rule.hxx
@@ -29,7 +29,7 @@ namespace build2
class LIBBUILD2_BASH_SYMEXPORT in_rule: public in::rule
{
public:
- in_rule (): rule ("bash.in 1", "bash.in", '@', false /* strict */) {}
+ in_rule (): rule ("bash.in 1", "bash", '@', false /* strict */) {}
virtual bool
match (action, target&, const string&, match_extra&) const override;
diff --git a/libbuild2/bin/def-rule.cxx b/libbuild2/bin/def-rule.cxx
index b4fbe0f..2879ca9 100644
--- a/libbuild2/bin/def-rule.cxx
+++ b/libbuild2/bin/def-rule.cxx
@@ -720,8 +720,12 @@ namespace build2
const char*& arg (*(args.end () - 2));
+ // We could print the prerequisite if it's a single obj{}/libu{} (with
+ // the latter being the common case). But it doesn't feel like that's
+ // worth the variability and the associated possibility of confusion.
+ //
if (verb == 1)
- text << "def " << t;
+ print_diag ("def", t);
diag_buffer dbuf (ctx);
diff --git a/libbuild2/cc/compile-rule.cxx b/libbuild2/cc/compile-rule.cxx
index 2534058..5693334 100644
--- a/libbuild2/cc/compile-rule.cxx
+++ b/libbuild2/cc/compile-rule.cxx
@@ -7247,7 +7247,7 @@ namespace build2
// @@ TODO: why don't we print env (here and/or below)? Also link rule.
//
if (verb == 1)
- text << x_name << ' ' << s;
+ print_diag (x_name, s, t);
else if (verb == 2)
print_process (args);
diff --git a/libbuild2/cc/install-rule.cxx b/libbuild2/cc/install-rule.cxx
index 0b4d1e1..5118332 100644
--- a/libbuild2/cc/install-rule.cxx
+++ b/libbuild2/cc/install-rule.cxx
@@ -271,9 +271,9 @@ namespace build2
const scope& rs (t.root_scope ());
auto& lp (t.data<install_match_data> (perform_uninstall_id).libs_paths);
- auto rm = [&rs, &id] (const path& l)
+ auto rm = [&rs, &id] (const path& f, const path& l)
{
- return uninstall_f (rs, id, nullptr, l.leaf (), 2 /* verbosity */);
+ return uninstall_l (rs, id, f.leaf (), l.leaf (), 2 /* verbosity */);
};
const path& lk (lp.link);
@@ -281,10 +281,12 @@ namespace build2
const path& so (lp.soname);
const path& in (lp.interm);
- if (!lk.empty ()) r = rm (lk) || r;
- if (!ld.empty ()) r = rm (ld) || r;
- if (!so.empty ()) r = rm (so) || r;
- if (!in.empty ()) r = rm (in) || r;
+ const path* f (lp.real);
+
+ if (!in.empty ()) {r = rm (*f, in) || r; f = &in;}
+ if (!so.empty ()) {r = rm (*f, so) || r; f = &so;}
+ if (!ld.empty ()) {r = rm (*f, ld) || r; f = &ld;}
+ if (!lk.empty ()) {r = rm (*f, lk) || r; }
}
return r;
diff --git a/libbuild2/cc/link-rule.cxx b/libbuild2/cc/link-rule.cxx
index c2ba8e7..24dc373 100644
--- a/libbuild2/cc/link-rule.cxx
+++ b/libbuild2/cc/link-rule.cxx
@@ -3825,7 +3825,7 @@ namespace build2
}
if (verb == 1)
- text << (lt.static_library () ? "ar " : "ld ") << t;
+ print_diag (lt.static_library () ? "ar" : "ld", t);
else if (verb == 2)
print_process (args);
diff --git a/libbuild2/cc/pkgconfig.cxx b/libbuild2/cc/pkgconfig.cxx
index 87515e3..eae328e 100644
--- a/libbuild2/cc/pkgconfig.cxx
+++ b/libbuild2/cc/pkgconfig.cxx
@@ -1399,10 +1399,10 @@ namespace build2
// Note that generation can take some time if we have a large number of
// prerequisite libraries.
//
- if (verb)
- text << "pc " << *t;
- else if (verb >= 2)
+ if (verb >= 2)
text << "cat >" << p;
+ else if (verb)
+ print_diag ("pc", g, *t);
if (ctx.dry_run)
return;
diff --git a/libbuild2/config/operation.cxx b/libbuild2/config/operation.cxx
index 3dd8729..34ed402 100644
--- a/libbuild2/config/operation.cxx
+++ b/libbuild2/config/operation.cxx
@@ -61,8 +61,10 @@ namespace build2
path f (src_root / rs.root_extra->out_root_file);
- if (verb)
- text << (verb >= 2 ? "cat >" : "save ") << f;
+ if (verb >= 2)
+ text << "cat >" << f;
+ else if (verb)
+ print_diag ("save", f);
try
{
@@ -566,8 +568,10 @@ namespace build2
if (f.string () == "-")
fn.name = "<stdout>";
- if (verb)
- text << (verb >= 2 ? "cat >" : "save ") << fn;
+ if (verb >= 2)
+ text << "cat >" << fn;
+ else if (verb)
+ print_diag ("save", fn);
try
{
@@ -678,7 +682,7 @@ namespace build2
//
if (out_root != src_root)
{
- mkdir_p (out_root / rs.root_extra->build_dir);
+ mkdir_p (out_root / rs.root_extra->build_dir, 1);
mkdir (out_root / rs.root_extra->bootstrap_dir, 2);
}
@@ -1402,7 +1406,8 @@ namespace build2
string ("config"), /* config_module */
nullopt, /* config_file */
true, /* buildfile */
- "the create meta-operation");
+ "the create meta-operation",
+ 1 /* verbosity */);
save_config (ctx, d);
}
diff --git a/libbuild2/diagnostics.cxx b/libbuild2/diagnostics.cxx
index 110641a..fda24f7 100644
--- a/libbuild2/diagnostics.cxx
+++ b/libbuild2/diagnostics.cxx
@@ -47,6 +47,138 @@ namespace build2
//
const int stream_verb_index = ostream::xalloc ();
+ // print_{do,undo}()
+ //
+ void
+ print_diag_impl (const char* p, target_key* l, target_key&& r, const char* c)
+ {
+ // @@ Print directly to diag_stream (and below)? Won't we be holding
+ // the lock longer?
+
+ diag_record dr (text);
+
+ dr << p << ' ';
+
+ if (l != nullptr)
+ {
+ // Omit the @.../ qualification in either lhs or rhs if it's implied by
+ // the other.
+ //
+ // @@ Shouldn't we, strictly speaking, also check that they belong to
+ // the same project? Though it would be far-fetched to use another
+ // project's target from src. Or maybe not.
+ //
+ if (!l->out->empty ())
+ {
+ if (r.out->empty ())
+ l->out = &empty_dir_path;
+ }
+ else if (!r.out->empty ())
+ r.out = &empty_dir_path;
+
+ dr << *l << ' ' << (c == nullptr ? "->" : c) << ' ';
+ }
+
+ dr << r;
+ }
+
+ // Note: these can't be inline since need the target class definition.
+ //
+ void
+ print_diag (const char* p, const target& l, const target& r, const char* c)
+ {
+ target_key lk (l.key ());
+ print_diag_impl (p, &lk, r.key (), c);
+ }
+
+ void
+ print_diag (const char* p, target_key&& l, const target& r, const char* c)
+ {
+ print_diag_impl (p, &l, r.key (), c);
+ }
+
+ void
+ print_diag (const char* p, const target& l, target_key&& r, const char* c)
+ {
+ target_key lk (l.key ());
+ print_diag_impl (p, &lk, move (r), c);
+ }
+
+ void
+ print_diag (const char* p, const string& l, const target& r, const char* c)
+ {
+ return print_diag (p, l, r.key (), c);
+ }
+
+ void
+ print_diag (const char* p, const string& l, target_key&& r, const char* c)
+ {
+ text << p << ' '
+ << l << (l.empty () ? "" : " ")
+ << (c == nullptr ? "->" : c) << ' '
+ << r;
+ }
+
+ void
+ print_diag (const char* p, const target& r)
+ {
+ print_diag_impl (p, nullptr, r.key (), nullptr);
+ }
+
+ void
+ print_diag (const char* p, const dir_path& r)
+ {
+ text << p << ' ' << r;
+ }
+
+ void
+ print_diag (const char* p, const path_name_view& r)
+ {
+ text << p << ' ' << r;
+ }
+
+ void
+ print_diag (const char* p, const target& l, const dir_path& r, const char* c)
+ {
+ // @@ TODO: out qualification stripping: only do if p.out is subdir of t
+ // (also below)?
+
+ text << p << ' ' << l << ' ' << (c == nullptr ? "->" : c) << ' ' << r;
+ }
+
+ void
+ print_diag (const char* p,
+ const target& l, const path_name_view& r,
+ const char* c)
+ {
+ text << p << ' ' << l << ' ' << (c == nullptr ? "->" : c) << ' ' << r;
+ }
+
+ void
+ print_diag (const char* p, const path& l, const dir_path& r, const char* c)
+ {
+ text << p << ' ' << l << ' ' << (c == nullptr ? "->" : c) << ' ' << r;
+ }
+
+ void
+ print_diag (const char* p,
+ const path& l, const path_name_view& r,
+ const char* c)
+ {
+ text << p << ' ' << l << ' ' << (c == nullptr ? "->" : c) << ' ' << r;
+ }
+
+ void
+ print_diag (const char* p,
+ const string& l, const path_name_view& r,
+ const char* c)
+ {
+ text << p << ' '
+ << l << (l.empty () ? "" : " ")
+ << (c == nullptr ? "->" : c) << ' '
+ << r;
+ }
+
// print_process()
//
void
diff --git a/libbuild2/diagnostics.hxx b/libbuild2/diagnostics.hxx
index 2505e2d..a4509e4 100644
--- a/libbuild2/diagnostics.hxx
+++ b/libbuild2/diagnostics.hxx
@@ -21,6 +21,171 @@ namespace build2
//
class failed: public std::exception {};
+ // Print low-verbosity recipe diagnostics in the forms:
+ //
+ // <prog> <l-target> <comb> <r-target>
+ // <prog> <r-target>
+ //
+ // Where <prog> is an abbreviated/generalized program name, such as c++
+ // (rather than g++ or clang++) or yacc (rather than bison or byacc),
+ // <l-target> is typically the "main" prerequisite target, such as the C++
+ // source file to compile, <r-target> is typically the target being
+ // produced, and <comb> is the combiner, typically "->".
+ //
+ // The second form (without <l-target> and <comb>) should be used when there
+ // is no natural "main" prerequisite, for example, for linking as well as
+ // for programs that act upon the target, such as mkdir, rm, test, etc.
+ //
+ // Note also that these functions omit the @.../ qualification in either
+ // <l-target> or <r-target> if it's implied by the other.
+ //
+ // For example:
+ //
+ // mkdir fsdir{details/}
+ // c++ cxx{hello} -> obje{hello}
+ // ld exe{hello}
+ //
+ // test exe{hello} + testscript
+ //
+ // install exe{hello} -> /usr/bin/
+ // uninstall exe{hello} <- /usr/bin/
+ //
+ // rm exe{hello}
+ // rm obje{hello}
+ // rmdir fsdir{details/}
+ //
+ // Examples of target groups:
+ //
+ // cli cli{foo} -> {hxx cxx}{foo}
+ //
+ // thrift thrift{foo} -> {hxx cxx}{foo-types}
+ // -> {hxx cxx}{foo-stubs}
+ //
+ // Potentially we could also support target groups for <l-target>:
+ //
+ // tool {hxx cxx}{foo} -> {hxx cxx}{foo-types}
+ //
+ // tool {hxx cxx}{foo-types}
+ // {hxx cxx}{foo-stubs} -> {hxx cxx}{foo-insts}
+ // {hxx cxx}{foo-impls}
+ //
+ // Note: see GH issue #40 for additional background and rationale.
+ //
+ // If <comb> is not specified, then "->" is used by default.
+
+ // prog target -> target
+ //
+ LIBBUILD2_SYMEXPORT void
+ print_diag (const char* prog,
+ const target& l, const target& r,
+ const char* comb = nullptr);
+
+ LIBBUILD2_SYMEXPORT void
+ print_diag (const char* prog,
+ target_key&& l, const target& r,
+ const char* comb = nullptr);
+
+ LIBBUILD2_SYMEXPORT void
+ print_diag (const char* prog,
+ const target& l, target_key&& r,
+ const char* comb = nullptr);
+
+ void
+ print_diag (const char* prog,
+ target_key&& l, target_key&& r,
+ const char* comb = nullptr);
+
+ // prog string -> target
+ //
+ // Use these versions if, for example, input information is passed as an
+ // argument.
+ //
+ LIBBUILD2_SYMEXPORT void
+ print_diag (const char* prog,
+ const string& l, const target& r,
+ const char* comb = nullptr);
+
+ LIBBUILD2_SYMEXPORT void
+ print_diag (const char* prog,
+ const string& l, target_key&& r,
+ const char* comb = nullptr);
+
+ // prog target
+ //
+ LIBBUILD2_SYMEXPORT void
+ print_diag (const char* prog, const target&);
+
+ void
+ print_diag (const char* prog, target_key&&);
+
+ // prog path
+ //
+ // Special versions for cases like mkdir/rmdir, save, etc.
+ //
+ // Note: use path_name("-") if the result is written to stdout.
+ //
+ void
+ print_diag (const char* prog, const path&);
+
+ LIBBUILD2_SYMEXPORT void
+ print_diag (const char* prog, const dir_path&);
+
+ LIBBUILD2_SYMEXPORT void
+ print_diag (const char* prog, const path_name_view&);
+
+ // Special versions for ln, cp, rm, install/unistall, dist, etc.
+ //
+ // Note: use path_name ("-") if the result is written to stdout.
+
+ // target -> path
+ //
+ void
+ print_diag (const char* prog,
+ const target& l, const path& r,
+ const char* comb = nullptr);
+
+ LIBBUILD2_SYMEXPORT void
+ print_diag (const char* prog,
+ const target& l, const dir_path& r,
+ const char* comb = nullptr);
+
+ LIBBUILD2_SYMEXPORT void
+ print_diag (const char* prog,
+ const target& l, const path_name_view& r,
+ const char* comb = nullptr);
+
+ // path -> path
+ //
+ void
+ print_diag (const char* prog,
+ const path& l, const path& r,
+ const char* comb = nullptr);
+
+ LIBBUILD2_SYMEXPORT void
+ print_diag (const char* prog,
+ const path& l, const dir_path& r,
+ const char* comb = nullptr);
+
+ LIBBUILD2_SYMEXPORT void
+ print_diag (const char* prog,
+ const path& l, const path_name_view& r,
+ const char* comb = nullptr);
+
+ // string -> path
+ //
+ // Use this version if, for example, input information is passed as an
+ // argument.
+ //
+ void
+ print_diag (const char* prog,
+ const string& l, const path& r,
+ const char* comb = nullptr);
+
+ LIBBUILD2_SYMEXPORT void
+ print_diag (const char* prog,
+ const string& l, const path_name_view& r,
+ const char* comb = nullptr);
+
// Print process commmand line. If the number of elements is specified (or
// the const cstrings& version is used), then it will print the piped multi-
// process command line, if present. In this case, the expected format is as
@@ -770,4 +935,6 @@ namespace build2
}
}
+#include <libbuild2/diagnostics.ixx>
+
#endif // LIBBUILD2_DIAGNOSTICS_HXX
diff --git a/libbuild2/diagnostics.ixx b/libbuild2/diagnostics.ixx
new file mode 100644
index 0000000..7c1a432
--- /dev/null
+++ b/libbuild2/diagnostics.ixx
@@ -0,0 +1,44 @@
+// file : libbuild2/diagnostics.ixx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+namespace build2
+{
+ LIBBUILD2_SYMEXPORT void
+ print_diag_impl (const char*, target_key*, target_key&&, const char*);
+
+ inline void
+ print_diag (const char* p, target_key&& l, target_key&& r, const char* c)
+ {
+ print_diag_impl (p, &l, move (r), c);
+ }
+
+ inline void
+ print_diag (const char* p, target_key& r)
+ {
+ print_diag_impl (p, nullptr, move (r), nullptr);
+ }
+
+ inline void
+ print_diag (const char* p, const path& r)
+ {
+ print_diag (p, path_name (&r));
+ }
+
+ inline void
+ print_diag (const char* p, const target& l, const path& r, const char* c)
+ {
+ print_diag (p, l, path_name (&r), c);
+ }
+
+ inline void
+ print_diag (const char* p, const path& l, const path& r, const char* c)
+ {
+ print_diag (p, l, path_name (&r), c);
+ }
+
+ inline void
+ print_diag (const char* p, const string& l, const path& r, const char* c)
+ {
+ print_diag (p, l, path_name (&r), c);
+ }
+}
diff --git a/libbuild2/dist/operation.cxx b/libbuild2/dist/operation.cxx
index 078a8e2..c7ce7f2 100644
--- a/libbuild2/dist/operation.cxx
+++ b/libbuild2/dist/operation.cxx
@@ -239,6 +239,8 @@ namespace build2
const string& dist_package (cast<string> (l));
const process_path& dist_cmd (cast<process_path> (rs.vars["dist.cmd"]));
+ dir_path td (dist_root / dir_path (dist_package));
+
// We used to print 'dist <target>' at verbosity level 1 but that has
// proven to be just noise. Though we still want to print something
// since otherwise, once the progress line is cleared, we may end up
@@ -248,7 +250,7 @@ namespace build2
// (e.g., output directory creation) in all the operations below.
//
if (verb == 1)
- text << "dist " << dist_package;
+ print_diag ("dist", src_root, td);
// Get the list of files to distribute.
//
@@ -496,8 +498,6 @@ namespace build2
//
auto_project_env penv (rs);
- dir_path td (dist_root / dir_path (dist_package));
-
// Clean up the target directory.
//
if (rmdir_r (ctx, td, true, 2) == rmdir_status::not_empty)
@@ -802,7 +802,7 @@ namespace build2
//
path ap (dir / an);
if (exists (ap, false))
- rmfile (ctx, ap);
+ rmfile (ctx, ap, 3 /* verbosity */);
// Use zip for .zip archives. Also recognize and handle a few well-known
// tar.xx cases (in case tar doesn't support -a or has other issues like
@@ -932,7 +932,7 @@ namespace build2
if (verb >= 2)
print_process (args);
else if (verb)
- text << args[0] << ' ' << ap;
+ print_diag (args[0], dir / dir_path (pkg), ap);
process apr;
process cpr;
@@ -986,7 +986,7 @@ namespace build2
//
path cp (dir / cn);
if (exists (cp, false))
- rmfile (ctx, cp);
+ rmfile (ctx, cp, 3 /* verbosity */);
auto_rmfile c_rm; // Note: must come first.
auto_fd c_fd;
@@ -1025,7 +1025,7 @@ namespace build2
if (verb >= 2)
print_process (args);
else if (verb)
- text << args[0] << ' ' << cp;
+ print_diag (args[0], ap, cp);
// Note that to only get the archive name (without the directory) in
// the output we have to run from the archive's directory.
@@ -1058,7 +1058,7 @@ namespace build2
if (verb >= 2)
text << "cat >" << cp;
else if (verb)
- text << e << "sum " << cp;
+ print_diag ((e + "sum").c_str (), ap, cp);
string c;
try
diff --git a/libbuild2/file.cxx b/libbuild2/file.cxx
index 8666520..3ded45e 100644
--- a/libbuild2/file.cxx
+++ b/libbuild2/file.cxx
@@ -3299,13 +3299,23 @@ namespace build2
//
mkdir (d / std_build_dir, verbosity);
+ auto diag = [verbosity] (const path& f)
+ {
+ if (verb >= verbosity)
+ {
+ if (verb >= 2)
+ text << "cat >" << f;
+ else if (verb)
+ print_diag ("save", f);
+ }
+ };
+
// Write build/bootstrap.build.
//
{
path f (d / std_bootstrap_file);
- if (verb >= verbosity)
- text << (verb >= 2 ? "cat >" : "save ") << f;
+ diag (f);
try
{
@@ -3351,8 +3361,7 @@ namespace build2
{
path f (d / std_root_file);
- if (verb >= verbosity)
- text << (verb >= 2 ? "cat >" : "save ") << f;
+ diag (f);
try
{
@@ -3400,8 +3409,7 @@ namespace build2
{
path f (d / std_build_dir / "config.build"); // std_config_file
- if (verb >= verbosity)
- text << (verb >= 2 ? "cat >" : "save ") << f;
+ diag (f);
try
{
@@ -3426,8 +3434,7 @@ namespace build2
{
path f (d / std_buildfile_file);
- if (verb >= verbosity)
- text << (verb >= 2 ? "cat >" : "save ") << f;
+ diag (f);
try
{
diff --git a/libbuild2/file.hxx b/libbuild2/file.hxx
index be7ea81..f5eb3f9 100644
--- a/libbuild2/file.hxx
+++ b/libbuild2/file.hxx
@@ -493,7 +493,7 @@ namespace build2
const optional<string>& config_file, // Ad hoc config.build contents.
bool buildfile, // Create root buildfile.
const char* who, // Who is creating it.
- uint16_t verbosity = 1); // Diagnostic verbosity.
+ uint16_t verbosity); // Diagnostic verbosity.
}
#include <libbuild2/file.ixx>
diff --git a/libbuild2/filesystem.cxx b/libbuild2/filesystem.cxx
index 2e3309d..32895c4 100644
--- a/libbuild2/filesystem.cxx
+++ b/libbuild2/filesystem.cxx
@@ -15,7 +15,12 @@ namespace build2
touch (context& ctx, const path& p, bool create, uint16_t v)
{
if (verb >= v)
- text << "touch " << p;
+ {
+ if (verb >= 2)
+ text << "touch " << p;
+ else if (verb)
+ print_diag ("touch", p);
+ }
if (ctx.dry_run)
return;
@@ -59,7 +64,12 @@ namespace build2
catch (const system_error& e)
{
if (verb >= v)
- text << "mkdir " << d;
+ {
+ if (verb >= 2)
+ text << "mkdir " << d;
+ else if (verb)
+ print_diag ("mkdir", d);
+ }
fail << "unable to create directory " << d << ": " << e << endf;
}
@@ -67,7 +77,12 @@ namespace build2
if (ms == mkdir_status::success)
{
if (verb >= v)
- text << "mkdir " << d;
+ {
+ if (verb >= 2)
+ text << "mkdir " << d;
+ else if (verb)
+ print_diag ("mkdir", d);
+ }
}
return ms;
@@ -88,7 +103,12 @@ namespace build2
catch (const system_error& e)
{
if (verb >= v)
- text << "mkdir -p " << d;
+ {
+ if (verb >= 2)
+ text << "mkdir -p " << d;
+ else if (verb)
+ print_diag ("mkdir -p", d);
+ }
fail << "unable to create directory " << d << ": " << e << endf;
}
@@ -96,7 +116,12 @@ namespace build2
if (ms == mkdir_status::success)
{
if (verb >= v)
- text << "mkdir -p " << d;
+ {
+ if (verb >= 2)
+ text << "mkdir -p " << d;
+ else if (verb)
+ print_diag ("mkdir -p", d);
+ }
}
return ms;
@@ -106,7 +131,12 @@ namespace build2
mvfile (const path& f, const path& t, uint16_t v)
{
if (verb >= v)
- text << "mv " << f << ' ' << t;
+ {
+ if (verb >= 2)
+ text << "mv " << f << ' ' << t;
+ else if (verb)
+ print_diag ("mv", f, t);
+ }
try
{
@@ -129,7 +159,15 @@ namespace build2
auto print = [&p, v] ()
{
if (verb >= v)
- text << "rm " << p.string ();
+ {
+ // Note: strip trailing directory separator (but keep as path for
+ // relative).
+ //
+ if (verb >= 2)
+ text << "rm " << p.string ();
+ else if (verb)
+ print_diag ("rm", p.to_directory () ? path (p.string ()) : p);
+ }
};
rmfile_status rs;
@@ -166,7 +204,12 @@ namespace build2
return rmdir_status::not_exist;
if (verb >= v)
- text << "rmdir -r " << d;
+ {
+ if (verb >= 2)
+ text << "rmdir -r " << d;
+ else if (verb)
+ print_diag ("rmdir -r", d);
+ }
if (!ctx.dry_run)
{
diff --git a/libbuild2/filesystem.hxx b/libbuild2/filesystem.hxx
index 565e832..2998cec 100644
--- a/libbuild2/filesystem.hxx
+++ b/libbuild2/filesystem.hxx
@@ -73,10 +73,10 @@ namespace build2
using mkdir_status = butl::mkdir_status;
LIBBUILD2_SYMEXPORT fs_status<mkdir_status>
- mkdir (const dir_path&, uint16_t verbosity = 1);
+ mkdir (const dir_path&, uint16_t verbosity);
LIBBUILD2_SYMEXPORT fs_status<mkdir_status>
- mkdir_p (const dir_path&, uint16_t verbosity = 1);
+ mkdir_p (const dir_path&, uint16_t verbosity);
// Rename a file (or file symlink) overwriting the destination if exists.
//
@@ -166,7 +166,7 @@ namespace build2
//
LIBBUILD2_SYMEXPORT fs_status<mkdir_status>
mkdir_buildignore (context&,
- const dir_path&, const path&, uint16_t verbosity = 1);
+ const dir_path&, const path&, uint16_t verbosity);
// Return true if the directory is empty or only contains the .buildignore
// file. Fail if the directory doesn't exist.
diff --git a/libbuild2/filesystem.txx b/libbuild2/filesystem.txx
index 7404532..7e3a773 100644
--- a/libbuild2/filesystem.txx
+++ b/libbuild2/filesystem.txx
@@ -1,8 +1,6 @@
// file : libbuild2/filesystem.txx -*- C++ -*-
// license : MIT; see accompanying LICENSE file
-#include <type_traits> // is_base_of
-
#include <libbuild2/diagnostics.hxx>
namespace build2
@@ -24,7 +22,7 @@ namespace build2
if (verb >= 2)
text << "rm " << f;
else if (verb)
- text << "rm " << t;
+ print_diag ("rm", t); // T can be target or path.
}
};
@@ -65,7 +63,7 @@ namespace build2
if (verb >= 2)
text << "rmdir " << d;
else if (verb)
- text << (std::is_base_of<dir_path, T>::value ? "rmdir " : "rm ") << t;
+ print_diag ("rmdir", t); // T can be target or dir_path.
}
};
@@ -94,7 +92,7 @@ namespace build2
{
if (verb >= v && verb >= 2)
{
- text << d << " is "
+ info << d << " is "
<< (w ? "current working directory" : "not empty")
<< ", not removing";
}
diff --git a/libbuild2/in/rule.cxx b/libbuild2/in/rule.cxx
index 07c11c6..74bc2a7 100644
--- a/libbuild2/in/rule.cxx
+++ b/libbuild2/in/rule.cxx
@@ -326,7 +326,7 @@ namespace build2
}
}
- text << program_ << ' ' << ik;
+ print_diag (program_.c_str (), move (ik), t);
}
// Read and process the file, one line at a time, while updating depdb.
diff --git a/libbuild2/install/rule.cxx b/libbuild2/install/rule.cxx
index 8fd180c..36a06fa 100644
--- a/libbuild2/install/rule.cxx
+++ b/libbuild2/install/rule.cxx
@@ -845,7 +845,7 @@ namespace build2
if (verb >= 2)
print_process (args);
else if (verb)
- text << "install " << chd;
+ print_diag ("install -d", chd); // See also `install -l` below.
}
run (ctx,
@@ -901,7 +901,12 @@ namespace build2
if (verb >= 2)
print_process (args);
else if (verb)
- text << "install " << t;
+ {
+ if (name.empty ())
+ print_diag ("install", t, chd);
+ else
+ print_diag ("install", t, chd / name);
+ }
}
if (!ctx.dry_run)
@@ -919,7 +924,9 @@ namespace build2
{
context& ctx (rs.ctx);
- path rell (relative (chroot_path (rs, base.dir)));
+ dir_path chd (chroot_path (rs, base.dir));
+
+ path rell (relative (chd));
rell /= link;
// We can create a symlink directly without calling ln. This, however,
@@ -946,7 +953,13 @@ namespace build2
if (verb >= 2)
print_process (args);
else if (verb)
- text << "install " << rell << " -> " << target;
+ {
+ // Without a flag it's unclear (unlike with ln) that we are creating
+ // a link. FreeBSD install(1) has the -l flag with the appropriate
+ // semantics. For consistency, we also pass -d above.
+ //
+ print_diag ("install -l", target, chd / link);
+ }
}
if (!ctx.dry_run)
@@ -966,7 +979,7 @@ namespace build2
if (verb >= 2)
text << "ln -sf " << target.string () << ' ' << rell.string ();
else if (verb)
- text << "install " << rell << " -> " << target;
+ print_diag ("install -l", target, chd / link);
}
if (!ctx.dry_run)
@@ -1152,7 +1165,7 @@ namespace build2
if (verb >= 2)
text << "rmdir " << reld;
else if (verb)
- text << "uninstall " << reld;
+ print_diag ("uninstall -d", chd);
}
try
@@ -1182,7 +1195,7 @@ namespace build2
if (verb >= 2)
print_process (args);
else if (verb)
- text << "uninstall " << reld;
+ print_diag ("uninstall -d", chd);
}
diag_buffer dbuf (rs.ctx);
@@ -1218,42 +1231,16 @@ namespace build2
return r;
}
- bool file_rule::
- uninstall_f (const scope& rs,
- const install_dir& base,
- const file* t,
- const path& name,
- uint16_t verbosity)
+ static void
+ uninstall_f_impl (const scope& rs,
+ const install_dir& base,
+ const path& f,
+ uint16_t verbosity)
{
context& ctx (rs.ctx);
- assert (t != nullptr || !name.empty ());
- path f (chroot_path (rs, base.dir) /
- (name.empty () ? t->path ().leaf () : name));
-
- try
- {
- // Note: don't follow symlinks so if the target is a dangling symlinks
- // we will proceed to removing it.
- //
- if (!file_exists (f, false)) // May throw (e.g., EACCES).
- return false;
- }
- catch (const system_error& e)
- {
- fail << "invalid installation path " << f << ": " << e;
- }
-
path relf (relative (f));
- if (verb >= verbosity && verb == 1)
- {
- if (t != nullptr)
- text << "uninstall " << *t;
- else
- text << "uninstall " << relf;
- }
-
// The same story as with uninstall -d (on Windows rm is also from
// MSYS2/Cygwin).
//
@@ -1300,7 +1287,86 @@ namespace build2
pp, args,
verb >= verbosity ? 1 : verb_never /* finish_verbosity */);
}
+ }
+
+ bool file_rule::
+ uninstall_f (const scope& rs,
+ const install_dir& base,
+ const file* t,
+ const path& name,
+ uint16_t verbosity)
+ {
+ assert (t != nullptr || !name.empty ());
+
+ dir_path chd (chroot_path (rs, base.dir));
+ path f (chd / (name.empty () ? t->path ().leaf () : name));
+
+ try
+ {
+ // Note: don't follow symlinks so if the target is a dangling symlinks
+ // we will proceed to removing it.
+ //
+ if (!file_exists (f, false)) // May throw (e.g., EACCES).
+ return false;
+ }
+ catch (const system_error& e)
+ {
+ fail << "invalid installation path " << f << ": " << e;
+ }
+
+ if (verb >= verbosity && verb == 1)
+ {
+ if (t != nullptr)
+ {
+ if (name.empty ())
+ print_diag ("uninstall ", *t, chd, "<-");
+ else
+ print_diag ("uninstall ", *t, f, "<-");
+ }
+ else
+ print_diag ("uninstall ", f);
+ }
+
+ uninstall_f_impl (rs, base, f, verbosity);
+ return true;
+ }
+
+ bool file_rule::
+ uninstall_l (const scope& rs,
+ const install_dir& base,
+ const path& /*target*/,
+ const path& link,
+ uint16_t verbosity)
+ {
+ dir_path chd (chroot_path (rs, base.dir));
+ path f (chd / link);
+
+ try
+ {
+ // Note: don't follow symlinks so if the target is a dangling symlinks
+ // we will proceed to removing it.
+ //
+ if (!file_exists (f, false)) // May throw (e.g., EACCES).
+ return false;
+ }
+ catch (const system_error& e)
+ {
+ fail << "invalid installation path " << f << ": " << e;
+ }
+
+ if (verb >= verbosity && verb == 1)
+ {
+ // It's dubious showing the link target path adds anything useful
+ // here.
+ //
+#if 0
+ print_diag ("uninstall -l", target, f, "<-");
+#else
+ print_diag ("uninstall -l", f);
+#endif
+ }
+ uninstall_f_impl (rs, base, f, verbosity);
return true;
}
diff --git a/libbuild2/install/rule.hxx b/libbuild2/install/rule.hxx
index ad9d6e7..98d2d0d 100644
--- a/libbuild2/install/rule.hxx
+++ b/libbuild2/install/rule.hxx
@@ -233,6 +233,19 @@ namespace build2
const path& name,
uint16_t verbosity = 1);
+ // Uninstall (remove) a symlink.
+ //
+ // This is essentially unistall_f() but with better low-verbosity
+ // diagnostics.
+ //
+ static bool
+ uninstall_l (const scope& rs,
+ const install_dir& base,
+ const path& target,
+ const path& link,
+ uint16_t verbosity = 1);
+
+
// Uninstall (remove) an empty directory.
//
// uninstall -d <dir>
diff --git a/libbuild2/rule.cxx b/libbuild2/rule.cxx
index 210f1ef..e5d5248 100644
--- a/libbuild2/rule.cxx
+++ b/libbuild2/rule.cxx
@@ -240,7 +240,7 @@ namespace build2
if (verb >= 2)
text << "mkdir " << d;
else if (verb && t.ctx.current_diag_noise)
- text << "mkdir " << t;
+ print_diag ("mkdir", t);
};
// Note: ignoring the dry_run flag.
diff --git a/libbuild2/test/rule.cxx b/libbuild2/test/rule.cxx
index 8a754e5..5cdd8fb 100644
--- a/libbuild2/test/rule.cxx
+++ b/libbuild2/test/rule.cxx
@@ -540,11 +540,19 @@ namespace build2
if (verb)
{
- diag_record dr (text);
- dr << "test " << ts;
-
- if (!t.is_a<alias> ())
- dr << ' ' << t;
+ // If the target is an alias, then testscript itself is the
+ // target.
+ //
+ if (t.is_a<alias> ())
+ print_diag ("test", ts);
+ else
+ {
+ // In this case the test is really a combination of the target
+ // and testscript and using "->" feels off. Also, let's list the
+ // testscript after the target even though its a source.
+ //
+ print_diag ("test", t, ts, "+");
+ }
}
res.push_back (ctx.dry_run
@@ -1247,7 +1255,7 @@ namespace build2
if (verb >= 2)
print_process (args); // Note: prints the whole pipeline.
else if (verb)
- text << "test " << tt;
+ print_diag ("test", tt);
if (!ctx.dry_run)
{
diff --git a/libbuild2/version/rule.hxx b/libbuild2/version/rule.hxx
index 2903dbf..0bdc090 100644
--- a/libbuild2/version/rule.hxx
+++ b/libbuild2/version/rule.hxx
@@ -20,7 +20,7 @@ namespace build2
class in_rule: public in::rule
{
public:
- in_rule (): rule ("version.in 2", "version.in") {}
+ in_rule (): rule ("version.in 2", "version") {}
virtual bool
match (action, target&) const override;
diff --git a/tests/cc/modules/modules.testscript b/tests/cc/modules/modules.testscript
index 681238a..8762885 100644
--- a/tests/cc/modules/modules.testscript
+++ b/tests/cc/modules/modules.testscript
@@ -354,7 +354,7 @@ $* test --verbose 1 <<EOI 2>>EOE;
exe{test}: cxx{driver} {mxx}{foo-core}
exe{test}: test.arguments = two
EOI
- c++ cxx{driver}
+ c++ cxx{driver} -> obje{driver}
ld exe{test}
test exe{test}
EOE
diff --git a/tests/test/simple/generated/testscript b/tests/test/simple/generated/testscript
index 878120a..49ddbbd 100644
--- a/tests/test/simple/generated/testscript
+++ b/tests/test/simple/generated/testscript
@@ -193,7 +193,7 @@ EOI
file{input}: in{input} $src_root/manifest #@@ in module
file{output}: in{output} $src_root/manifest #@@ in module
EOI
- %version\.in in\{.+\}%{2}
+ %version in\{.+\} -> .+%{2}
test dir{./}
error: test dir{./} failed
% error: process .+driver.* terminated: execution timeout expired%