From 41cad5bba8a718a0403c0578660c60e81c9f46e4 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 27 Jun 2016 16:59:09 +0200 Subject: Add config.bin.target var/hint, use to decide libso{} install mode Normally the user doesn't need to specify config.bin.target explicitly since the cxx module will hint it. We now also have the whole set of target's components: bin.target.{cpu,vendor,system,version,class} --- build2/bin/module.cxx | 209 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 152 insertions(+), 57 deletions(-) (limited to 'build2/bin') diff --git a/build2/bin/module.cxx b/build2/bin/module.cxx index 70a2b98..5e668df 100644 --- a/build2/bin/module.cxx +++ b/build2/bin/module.cxx @@ -4,6 +4,8 @@ #include +#include + #include #include #include @@ -16,6 +18,7 @@ #include using namespace std; +using namespace butl; namespace build2 { @@ -33,7 +36,7 @@ namespace build2 bool init (scope& r, scope& b, - const location&, + const location& loc, unique_ptr&, bool first, bool, @@ -42,8 +45,6 @@ namespace build2 tracer trace ("bin::init"); l5 ([&]{trace << "for " << b.out_path ();}); - assert (config_hints.empty ()); // We don't known any hints. - // Enter module variables. // if (first) @@ -52,6 +53,8 @@ namespace build2 // Note: some overridable, some not. // + v.insert ("config.bin.target", true); + v.insert ("config.bin.ar", true); v.insert ("config.bin.ranlib", true); @@ -70,45 +73,6 @@ namespace build2 v.insert ("bin.libprefix", true); } - // Register target types. - // - { - auto& t (b.target_types); - - t.insert (); - t.insert (); - t.insert (); - t.insert (); - t.insert (); - t.insert (); - t.insert (); - } - - // Register rules. - // - { - auto& r (b.rules); - - r.insert (perform_update_id, "bin.obj", obj_); - r.insert (perform_clean_id, "bin.obj", obj_); - - r.insert (perform_update_id, "bin.lib", lib_); - r.insert (perform_clean_id, "bin.lib", lib_); - - // Configure member. - // - r.insert (configure_update_id, "bin.lib", lib_); - - //@@ Should we check if the install module was loaded - // (by checking if install operation is registered - // for this project)? If we do that, then install - // will have to be loaded before bin. Perhaps we - // should enforce loading of all operation-defining - // modules before all others? - // - r.insert (perform_install_id, "bin.lib", lib_); - } - // Configure. // using config::required; @@ -163,15 +127,99 @@ namespace build2 b.assign ("bin.rpath") += cast_null ( config::optional (r, "config.bin.rpath")); - // config.bin.ar - // config.bin.ranlib - // - // For config.bin.ar we default to 'ar' while ranlib should be explicitly - // specified by the user in order for us to use it (most targets support - // the -s option to ar). - // if (first) { + // config.bin.target + // + { + const variable& cbt (var_pool.find ("config.bin.target")); + + // We first see if the value was specified via the configuration + // mechanism. + // + auto p (config::required (r, cbt)); + const value* v (p.first); + + // Then see if there is a config hint (e.g., from the C++ module). + // + bool hint (false); + if (v == nullptr) + { + if (auto l = config_hints[cbt]) + { + v = l.value; + hint = true; + } + } + + if (v == nullptr) + fail (loc) << "unable to determine binutils target" << + info << "consider specifying it with config.bin.target" << + info << "or first load a module that can provide it as a hint, " + << "such as c or cxx"; + + // Split/canonicalize the target. + // + string s (cast (*v)); + + // Did the user ask us to use config.sub? If this is a hinted value, + // then we assume it has already been passed through config.sub. + // + if (!hint && ops.config_sub_specified ()) + { + s = run (ops.config_sub (), + s.c_str (), + [] (string& l) {return move (l);}); + l5 ([&]{trace << "config.sub target: '" << s << "'";}); + } + + try + { + string canon; + triplet t (s, canon); + + l5 ([&]{trace << "canonical target: '" << canon << "'; " + << "class: " << t.class_;}); + + assert (!hint || s == canon); + + // Enter as bin.target.{cpu,vendor,system,version,class}. + // + r.assign ("bin.target") = move (canon); + r.assign ("bin.target.cpu") = move (t.cpu); + r.assign ("bin.target.vendor") = move (t.vendor); + r.assign ("bin.target.system") = move (t.system); + r.assign ("bin.target.version") = move (t.version); + r.assign ("bin.target.class") = move (t.class_); + } + catch (const invalid_argument& e) + { + // This is where we suggest that the user specifies --config-sub + // to help us out. + // + fail << "unable to parse binutils target '" << s << "': " + << e.what () << + info << "consider using the --config-sub option"; + } + + // If this is a new value (e.g., we are configuring), then print the + // report at verbosity level 2 and up (-v). Note that a hinted value + // will automatically only be printed at level 3 and up. + // + if (verb >= (p.second ? 2 : 3)) + { + text << "bin\n" + << " target " << cast (r["bin.target"]); + } + } + + // config.bin.ar + // config.bin.ranlib + // + // For config.bin.ar we default to 'ar' while ranlib should be + // explicitly specified by the user in order for us to use it (most + // targets support the -s option to ar). + // auto p (config::required (r, "config.bin.ar", path ("ar"))); auto& v (config::optional (r, "config.bin.ranlib")); @@ -187,16 +235,18 @@ namespace build2 { //@@ Print project out root or name? See cxx. - text << ar << ":\n" - << " id " << bi.ar_id << "\n" - << " signature " << bi.ar_signature << "\n" + text << "bin.ar\n" + << " exe " << ar << '\n' + << " id " << bi.ar_id << '\n' + << " signature " << bi.ar_signature << '\n' << " checksum " << bi.ar_checksum; if (!ranlib.empty ()) { - text << ranlib << ":\n" - << " id " << bi.ranlib_id << "\n" - << " signature " << bi.ranlib_signature << "\n" + text << "bin.ranlib\n" + << " exe " << ranlib << '\n' + << " id " << bi.ranlib_id << '\n' + << " signature " << bi.ranlib_signature << '\n' << " checksum " << bi.ranlib_checksum; } } @@ -214,6 +264,49 @@ namespace build2 } } + // Cache some config values we will be needing below. + // + const string& tclass (cast (r["bin.target.class"])); + + // Register target types. + // + { + auto& t (b.target_types); + + t.insert (); + t.insert (); + t.insert (); + t.insert (); + t.insert (); + t.insert (); + t.insert (); + } + + // Register rules. + // + { + auto& r (b.rules); + + r.insert (perform_update_id, "bin.obj", obj_); + r.insert (perform_clean_id, "bin.obj", obj_); + + r.insert (perform_update_id, "bin.lib", lib_); + r.insert (perform_clean_id, "bin.lib", lib_); + + // Configure member. + // + r.insert (configure_update_id, "bin.lib", lib_); + + //@@ Should we check if the install module was loaded + // (by checking if install operation is registered + // for this project)? If we do that, then install + // will have to be loaded before bin. Perhaps we + // should enforce loading of all operation-defining + // modules before all others? + // + r.insert (perform_install_id, "bin.lib", lib_); + } + // Configure "installability" of our target types. // using namespace install; @@ -236,11 +329,13 @@ namespace build2 // // libso{foo}: install.mode=755 // - // Everyone is happy then? + // Everyone is happy then? Not Windows users. When targeting Windows + // libso{} is an import library and shouldn't be exec. // install_path (b, dir_path ("lib")); // Install into install.lib. - //@@ For Windows, libso{} is an import library and shouldn't be exec. + if (tclass == "windows") + install_mode (b, "644"); install_path (b, dir_path ("lib")); // Install into install.lib. install_mode (b, "644"); -- cgit v1.1