aboutsummaryrefslogtreecommitdiff
path: root/build2/bin
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2016-03-14 13:30:47 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2016-03-14 13:30:47 +0200
commitbbff2b69459a370afd6c74b6b0d3bb080ff22b89 (patch)
treee0528ae3ffd46bdaa0b76063edb918bf1dc93de6 /build2/bin
parent10dfd69f4a714f8df2ea98e8cd2ff9359a63016a (diff)
Add support for guessing ar/ranlib signatures
Diffstat (limited to 'build2/bin')
-rw-r--r--build2/bin/guess41
-rw-r--r--build2/bin/guess.cxx154
-rw-r--r--build2/bin/module.cxx46
3 files changed, 231 insertions, 10 deletions
diff --git a/build2/bin/guess b/build2/bin/guess
new file mode 100644
index 0000000..005235d
--- /dev/null
+++ b/build2/bin/guess
@@ -0,0 +1,41 @@
+// file : build2/bin/guess -*- C++ -*-
+// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BUILD2_BIN_GUESS
+#define BUILD2_BIN_GUESS
+
+#include <build2/types>
+#include <build2/utility>
+
+namespace build2
+{
+ namespace bin
+ {
+ // ar/ranlib information.
+ //
+ // The signature is normally the --version/-V line.
+ //
+ // The checksum is used to detect ar/ranlib changes. It is calculated in
+ // a toolchain-specific manner (usually the output of --version/-V) and
+ // is not bulletproof.
+ //
+ struct bin_info
+ {
+ string ar_signature;
+ string ar_checksum;
+
+ string ranlib_signature;
+ string ranlib_checksum;
+ };
+
+ // The ranlib path can be empty, in which case no ranlib guessing will be
+ // attemplated and the returned ranlib_* members will be left empty as
+ // well.
+ //
+ bin_info
+ guess (const path& ar, const path& ranlib);
+ }
+}
+
+#endif // BUILD2_BIN_GUESS
diff --git a/build2/bin/guess.cxx b/build2/bin/guess.cxx
new file mode 100644
index 0000000..1cdb40d
--- /dev/null
+++ b/build2/bin/guess.cxx
@@ -0,0 +1,154 @@
+// file : build2/bin/guess.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <build2/bin/guess>
+
+#include <build2/diagnostics>
+
+using namespace std;
+
+namespace build2
+{
+ namespace bin
+ {
+ bin_info
+ guess (const path& ar, const path& ranlib)
+ {
+ tracer trace ("bin::guess");
+
+ bin_info r;
+ string& as (r.ar_signature);
+
+ // Binutils, LLVM, and FreeBSD ar/ranlib all recognize the --version
+ // option, so start with that.
+ //
+ {
+ auto f = [] (string& l) -> string
+ {
+ // Binutils ar --version output has a line that starts with
+ // "GNU ar ".
+ //
+ if (l.compare (0, 7, "GNU ar ") == 0)
+ return move (l);
+
+ // LLVM ar --version output has a line that starts with
+ // "LLVM version ".
+ //
+ if (l.compare (0, 13, "LLVM version ") == 0)
+ return move (l);
+
+ // FreeBSD ar --verison output starts with "BSD ar ".
+ //
+ if (l.compare (0, 7, "BSD ar ") == 0)
+ return move (l);
+
+ return string ();
+ };
+
+ // Suppress all the errors because we may be trying an unsupported
+ // option.
+ //
+ sha256 cs;
+ as = run<string> (ar, "--version", f, false, false, &cs);
+
+ if (!as.empty ())
+ r.ar_checksum = cs.string ();
+ }
+
+ // On Mac OS X (and probably also older BSDs) ar/ranlib doesn't have an
+ // option to display version or help. If we run it without any arguments
+ // it dumps usage and exist with an error status. So we will have to use
+ // that.
+ //
+ if (as.empty ())
+ {
+ auto f = [] (string& l) -> string
+ {
+ return l.find (" ar ") == string::npos ? string () : move (l);
+ };
+
+ // Redirect STDERR to STDOUT and ignore exit status.
+ //
+ sha256 cs;
+ as = run<string> (ar, f, false, true, &cs);
+
+ if (!as.empty ())
+ {
+ l4 ([&]{trace << "generic ar signature '" << as << "'";});
+
+ r.ar_signature = "Generic ar";
+ r.ar_checksum = cs.string ();
+ }
+ }
+
+ if (as.empty ())
+ fail << "unable to guess " << ar << " signature";
+
+ // Now repeat pretty much the same steps for ranlib if requested.
+ //
+ if (ranlib.empty ())
+ return r;
+
+ string& rs (r.ranlib_signature);
+
+ // Binutils, LLVM, and FreeBSD.
+ //
+ {
+ auto f = [] (string& l) -> string
+ {
+ // "GNU ranlib ".
+ //
+ if (l.compare (0, 11, "GNU ranlib ") == 0)
+ return move (l);
+
+ // "LLVM version ".
+ //
+ if (l.compare (0, 13, "LLVM version ") == 0)
+ return move (l);
+
+ // "ranlib " (note: not "BSD ranlib " for some reason).
+ //
+ if (l.compare (0, 7, "ranlib ") == 0)
+ return move (l);
+
+ return string ();
+ };
+
+ sha256 cs;
+ rs = run<string> (ranlib, "--version", f, false, false, &cs);
+
+ if (!rs.empty ())
+ r.ranlib_checksum = cs.string ();
+ }
+
+ // Mac OS X (and probably also older BSDs).
+ //
+ if (rs.empty ())
+ {
+ auto f = [] (string& l) -> string
+ {
+ return l.find ("ranlib") == string::npos ? string () : move (l);
+ };
+
+ // Redirect STDERR to STDOUT and ignore exit status.
+ //
+ sha256 cs;
+ rs = run<string> (ranlib, f, false, true, &cs);
+
+ if (!rs.empty ())
+ {
+ l4 ([&]{trace << "generic ranlib signature '" << rs << "'";});
+
+ r.ranlib_signature = "Generic ranlib";
+ r.ranlib_checksum = cs.string ();
+ }
+ }
+
+ if (rs.empty ())
+ fail << "unable to guess " << ranlib << " signature";
+
+ return r;
+ }
+ }
+}
diff --git a/build2/bin/module.cxx b/build2/bin/module.cxx
index c5ba25a..2b89eeb 100644
--- a/build2/bin/module.cxx
+++ b/build2/bin/module.cxx
@@ -12,6 +12,7 @@
#include <build2/install/utility>
#include <build2/bin/rule>
+#include <build2/bin/guess>
#include <build2/bin/target>
using namespace std;
@@ -164,20 +165,45 @@ namespace build2
// specified by the user in order for us to use it (most targets support
// the -s option to ar).
//
-
- // @@ Maybe, if explicitly specified by the user, we should try to run
- // them?
- //
if (first)
{
- config::required (r, "config.bin.ar", "ar");
- r.assign ("bin.ar.signature", string_type) = "Some ar";
- r.assign ("bin.ar.checksum", string_type) = "123";
+ auto p (config::required (r, "config.bin.ar", "ar"));
+ auto& v (config::optional (r, "config.bin.ranlib"));
+
+ const path& ar (path (as<string> (p.first))); // @@ VAR
+ const path& ranlib (v ? path (as<string> (v)) : path ()); // @@ VAR
+
+ bin_info bi (guess (ar, ranlib));
+
+ // If this is a new value (e.g., we are configuring), then print the
+ // report at verbosity level 2 and up (-v).
+ //
+ if (verb >= (p.second ? 2 : 3))
+ {
+ //@@ Print project out root or name? See cxx.
+
+ text << ar << ":\n"
+ << " signature " << bi.ar_signature << "\n"
+ << " checksum " << bi.ar_checksum;
+
+ if (!ranlib.empty ())
+ {
+ text << ranlib << ":\n"
+ << " signature " << bi.ranlib_signature << "\n"
+ << " checksum " << bi.ranlib_checksum;
+ }
+ }
- if (auto& v = config::optional (r, "config.bin.ranlib"))
+ r.assign ("bin.ar.signature", string_type) = move (bi.ar_signature);
+ r.assign ("bin.ar.checksum", string_type) = move (bi.ar_checksum);
+
+ if (!ranlib.empty ())
{
- r.assign ("bin.ranlib.signature", string_type) = "Some ranlib";
- r.assign ("bin.ranlib.checksum", string_type) = "234";
+ r.assign ("bin.ranlib.signature", string_type) =
+ move (bi.ranlib_signature);
+
+ r.assign ("bin.ranlib.checksum", string_type) =
+ move (bi.ranlib_checksum);
}
}