From fac576a331d6587e4343d09d6caf959d9a776118 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 11 Jul 2016 05:56:17 +0200 Subject: Add bin.ld sub-module --- build2/bin/guess.cxx | 120 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 116 insertions(+), 4 deletions(-) (limited to 'build2/bin/guess.cxx') 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 (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 (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 (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)}; + } } } -- cgit v1.1