aboutsummaryrefslogtreecommitdiff
path: root/build2/bin/guess.cxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2016-07-11 05:56:17 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2016-07-11 05:56:17 +0200
commitfac576a331d6587e4343d09d6caf959d9a776118 (patch)
tree93057af1757ca47cf603ebba895bdd2416cf6c05 /build2/bin/guess.cxx
parent80f55f5857d340c31fcd951f645d3f337ed66a6b (diff)
Add bin.ld sub-module
Diffstat (limited to 'build2/bin/guess.cxx')
-rw-r--r--build2/bin/guess.cxx120
1 files changed, 116 insertions, 4 deletions
diff --git a/build2/bin/guess.cxx b/build2/bin/guess.cxx
index d036f81..ea4ac49 100644
--- a/build2/bin/guess.cxx
+++ b/build2/bin/guess.cxx
@@ -22,10 +22,10 @@ namespace build2
empty () const {return id.empty ();}
};
- bin_info
- guess (const path& ar, const path& rl)
+ ar_info
+ guess_ar (const path& ar, const path& rl)
{
- tracer trace ("bin::guess");
+ tracer trace ("bin::guess_ar");
guess_result arr, rlr;
@@ -166,9 +166,121 @@ namespace build2
fail << "unable to guess " << rl << " signature";
}
- return bin_info {
+ return ar_info {
move (arr.id), move (arr.signature), move (arr.checksum),
move (rlr.id), move (rlr.signature), move (rlr.checksum)};
}
+
+ ld_info
+ guess_ld (const path& ld)
+ {
+ tracer trace ("bin::guess_ld");
+
+ guess_result r;
+
+ // Binutils ld recognizes the --version option. Microsoft's link.exe
+ // doesn't support --version (nor any other way to get the version
+ // without the error exist status) but it will still print its banner.
+ // We also want to recognize link.exe as fast as possible since it will
+ // be the most commonly configured linker (for other platoforms the
+ // linker will normally be used indirectly via the compiler and the
+ // bin.ld module won't be loaded). So we are going to ignore the error
+ // exit status. Our signatures are fairly specific to avoid any kind
+ // of false positives.
+ //
+ {
+ auto f = [] (string& l) -> guess_result
+ {
+ // Microsoft link.exe output starts with "Microsoft (R) ".
+ //
+ if (l.compare (0, 14, "Microsoft (R) ") == 0)
+ return guess_result {"msvc", move (l), ""};
+
+ // Binutils ld.bfd --version output has a line that starts with
+ // "GNU ld " while ld.gold -- "GNU gold".
+ //
+ if (l.compare (0, 7, "GNU ld ") == 0)
+ return guess_result {"gnu", move (l), ""};
+
+ if (l.compare (0, 9, "GNU gold ") == 0)
+ return guess_result {"gold", move (l), ""};
+
+ return guess_result ();
+ };
+
+ // Redirect STDERR to STDOUT and ignore exit status. Note that in case
+ // of link.exe we will hash the diagnostics (yes, it goes to stdout)
+ // but that seems harmless.
+ //
+ sha256 cs;
+ r = run<guess_result> (ld, "--version", f, false, true, &cs);
+
+ if (!r.empty ())
+ r.checksum = cs.string ();
+ }
+
+ // Next try -v which will cover Apple's linkers.
+ //
+ if (r.empty ())
+ {
+ auto f = [] (string& l) -> guess_result
+ {
+ // New ld64 has "PROJECT:ld64" in the first line (output to stderr),
+ // for example:
+ //
+ // @(#)PROGRAM:ld PROJECT:ld64-242.2
+ //
+ if (l.find ("PROJECT:ld64") != string::npos)
+ return guess_result {"ld64", move (l), ""};
+
+ // Old ld has "cctools" in the first line, for example:
+ //
+ // Apple Computer, Inc. version cctools-622.9~2
+ //
+ if (l.find ("cctools") != string::npos)
+ return guess_result {"cctools", move (l), ""};
+
+ return guess_result ();
+ };
+
+ sha256 cs;
+ r = run<guess_result> (ld, "-v", f, false, false, &cs);
+
+ if (!r.empty ())
+ r.checksum = cs.string ();
+ }
+
+ // Finally try -version which will take care of LLVM's lld.
+ //
+ if (r.empty ())
+ {
+ auto f = [] (string& l) -> guess_result
+ {
+ // Unlike other LLVM tools (e.g., ar), the lld's version is printed
+ // (to stderr) as:
+ //
+ // LLVM Linker Version: 3.7
+ //
+ if (l.compare (0, 19, "LLVM Linker Version") == 0)
+ return guess_result {"llvm", move (l), ""};
+
+ return guess_result ();
+ };
+
+ // Suppress all the errors because we may be trying an unsupported
+ // option.
+ //
+ sha256 cs;
+ r = run<guess_result> (ld, "-version", f, false, false, &cs);
+
+ if (!r.empty ())
+ r.checksum = cs.string ();
+ }
+
+ if (r.empty ())
+ fail << "unable to guess " << ld << " signature";
+
+ return ld_info {move (r.id), move (r.signature), move (r.checksum)};
+ }
}
}