From 0760742386e8e6034bbd619487ef156bc574e408 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 11 Jul 2016 07:23:37 +0200 Subject: Add bin.rc module (resource compiler) --- build2/b.cxx | 1 + build2/bin/guess | 31 +++++++++++++-- build2/bin/guess.cxx | 57 +++++++++++++++++++++++++++ build2/bin/module | 9 +++++ build2/bin/module.cxx | 105 ++++++++++++++++++++++++++++++++++++++++---------- 5 files changed, 179 insertions(+), 24 deletions(-) diff --git a/build2/b.cxx b/build2/b.cxx index f272926..6138f6c 100644 --- a/build2/b.cxx +++ b/build2/b.cxx @@ -190,6 +190,7 @@ main (int argc, char* argv[]) builtin_modules["bin"] = module_functions {nullptr, &bin::init}; builtin_modules["bin.ld"] = module_functions {nullptr, &bin::ld_init}; + builtin_modules["bin.rc"] = module_functions {nullptr, &bin::rc_init}; builtin_modules["cxx"] = module_functions {nullptr, &cxx::init}; builtin_modules["cli"] = module_functions {nullptr, &cli::init}; diff --git a/build2/bin/guess b/build2/bin/guess index d6ff76d..10f337a 100644 --- a/build2/bin/guess +++ b/build2/bin/guess @@ -48,7 +48,7 @@ namespace build2 // ld information. // - // Currently recognized ld and their ids: + // Currently recognized linkers and their ids: // // gnu GNU binutils ld.bfd // gold GNU binutils ld.gold @@ -68,13 +68,36 @@ namespace build2 // struct ld_info { - string ld_id; - string ld_signature; - string ld_checksum; + string id; + string signature; + string checksum; }; ld_info guess_ld (const path& ld); + + // rc information. + // + // Currently recognized resource compilers and their ids: + // + // gnu GNU binutils windres + // msvc Microsoft's rc.exe + // + // The signature is normally the --version line. + // + // The checksum is used to detect rc changes. It is calculated in a + // toolchain-specific manner (usually the output of --version) and is not + // bulletproof. + // + struct rc_info + { + string id; + string signature; + string checksum; + }; + + rc_info + guess_rc (const path& rc); } } diff --git a/build2/bin/guess.cxx b/build2/bin/guess.cxx index ea4ac49..8a91015 100644 --- a/build2/bin/guess.cxx +++ b/build2/bin/guess.cxx @@ -282,5 +282,62 @@ namespace build2 return ld_info {move (r.id), move (r.signature), move (r.checksum)}; } + + rc_info + guess_rc (const path& rc) + { + tracer trace ("bin::guess_rc"); + + guess_result r; + + // Binutils windres recognizes the --version option. + // + { + auto f = [] (string& l) -> guess_result + { + // Binutils windres --version output has a line that starts with + // "GNU windres ". + // + if (l.compare (0, 12, "GNU windres ") == 0) + return guess_result {"gnu", move (l), ""}; + + return guess_result (); + }; + + // Suppress all the errors because we may be trying an unsupported + // option. + // + sha256 cs; + r = run (rc, "--version", f, false, false, &cs); + + if (!r.empty ()) + r.checksum = cs.string (); + } + + // Microsoft rc.exe /? prints its standard banner and exits with zero + // status. + // + if (r.empty ()) + { + auto f = [] (string& l) -> guess_result + { + if (l.compare (0, 14, "Microsoft (R) ") == 0) + return guess_result {"msvc", move (l), ""}; + + return guess_result (); + }; + + sha256 cs; + r = run (rc, "/?", f, false, false, &cs); + + if (!r.empty ()) + r.checksum = cs.string (); + } + + if (r.empty ()) + fail << "unable to guess " << rc << " signature"; + + return rc_info {move (r.id), move (r.signature), move (r.checksum)}; + } } } diff --git a/build2/bin/module b/build2/bin/module index fa592cf..668e4d8 100644 --- a/build2/bin/module +++ b/build2/bin/module @@ -31,6 +31,15 @@ namespace build2 bool, bool, const variable_map&); + + bool + rc_init (scope&, + scope&, + const location&, + unique_ptr&, + bool, + bool, + const variable_map&); } } diff --git a/build2/bin/module.cxx b/build2/bin/module.cxx index f5e44db..306d8de 100644 --- a/build2/bin/module.cxx +++ b/build2/bin/module.cxx @@ -305,7 +305,7 @@ namespace build2 const path& ar (cast (p.first)); const path& ranlib (v ? cast (v) : path ()); - ar_info ai (guess_ar (ar, ranlib)); + ar_info ari (guess_ar (ar, ranlib)); // If this is a new value (e.g., we are configuring), then print the // report at verbosity level 2 and up (-v). @@ -316,30 +316,31 @@ namespace build2 text << "bin.ar\n" << " exe " << ar << '\n' - << " id " << ai.ar_id << '\n' - << " signature " << ai.ar_signature << '\n' - << " checksum " << ai.ar_checksum; + << " id " << ari.ar_id << '\n' + << " signature " << ari.ar_signature << '\n' + << " checksum " << ari.ar_checksum; if (!ranlib.empty ()) { text << "bin.ranlib\n" << " exe " << ranlib << '\n' - << " id " << ai.ranlib_id << '\n' - << " signature " << ai.ranlib_signature << '\n' - << " checksum " << ai.ranlib_checksum; + << " id " << ari.ranlib_id << '\n' + << " signature " << ari.ranlib_signature << '\n' + << " checksum " << ari.ranlib_checksum; } } - r.assign ("bin.ar.id") = move (ai.ar_id); - r.assign ("bin.ar.signature") = move (ai.ar_signature); - r.assign ("bin.ar.checksum") = move (ai.ar_checksum); + r.assign ("bin.ar.id") = move (ari.ar_id); + r.assign ("bin.ar.signature") = move (ari.ar_signature); + r.assign ("bin.ar.checksum") = move (ari.ar_checksum); if (!ranlib.empty ()) { - r.assign ("bin.ranlib.id") = move (ai.ranlib_id); + r.assign ("bin.ranlib.id") = move (ari.ranlib_id); r.assign ("bin.ranlib.signature") = - move (ai.ranlib_signature); - r.assign ("bin.ranlib.checksum") = move (ai.ranlib_checksum); + move (ari.ranlib_signature); + r.assign ("bin.ranlib.checksum") = + move (ari.ranlib_checksum); } } @@ -464,7 +465,7 @@ namespace build2 path (apply (r["bin.pattern"], ld_d)))); const path& ld (cast (p.first)); - ld_info li (guess_ld (ld)); + ld_info ldi (guess_ld (ld)); // If this is a new value (e.g., we are configuring), then print the // report at verbosity level 2 and up (-v). @@ -473,14 +474,78 @@ namespace build2 { text << "bin.ld\n" << " exe " << ld << '\n' - << " id " << li.ld_id << '\n' - << " signature " << li.ld_signature << '\n' - << " checksum " << li.ld_checksum; + << " id " << ldi.id << '\n' + << " signature " << ldi.signature << '\n' + << " checksum " << ldi.checksum; } - r.assign ("bin.ld.id") = move (li.ld_id); - r.assign ("bin.ld.signature") = move (li.ld_signature); - r.assign ("bin.ld.checksum") = move (li.ld_checksum); + r.assign ("bin.ld.id") = move (ldi.id); + r.assign ("bin.ld.signature") = move (ldi.signature); + r.assign ("bin.ld.checksum") = move (ldi.checksum); + } + + return true; + } + + bool + rc_init (scope& r, + scope& b, + const location& loc, + unique_ptr&, + bool first, + bool, + const variable_map& config_hints) + { + tracer trace ("bin::rc_init"); + l5 ([&]{trace << "for " << b.out_path ();}); + + // Make sure the bin core is loaded. + // + if (!cast_false (b["bin.loaded"])) + load_module ("bin", r, b, loc, false, config_hints); + + // Enter module variables. + // + if (first) + { + auto& v (var_pool); + + v.insert ("config.bin.rc", true); + } + + // Configure. + // + if (first) + { + // config.bin.rc + // + // Use the target to decide on the default rc name. + // + const string& tsys (cast (r["bin.target.system"])); + const char* rc_d (tsys == "win32-msvc" ? "rc" : "windres"); + + auto p (config::required (r, + "config.bin.rc", + path (apply (r["bin.pattern"], rc_d)))); + + const path& rc (cast (p.first)); + rc_info rci (guess_rc (rc)); + + // 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)) + { + text << "bin.rc\n" + << " exe " << rc << '\n' + << " id " << rci.id << '\n' + << " signature " << rci.signature << '\n' + << " checksum " << rci.checksum; + } + + r.assign ("bin.rc.id") = move (rci.id); + r.assign ("bin.rc.signature") = move (rci.signature); + r.assign ("bin.rc.checksum") = move (rci.checksum); } return true; -- cgit v1.1