diff options
Diffstat (limited to 'libbuild2/bin/init.cxx')
-rw-r--r-- | libbuild2/bin/init.cxx | 768 |
1 files changed, 526 insertions, 242 deletions
diff --git a/libbuild2/bin/init.cxx b/libbuild2/bin/init.cxx index 2f1e6db..610082e 100644 --- a/libbuild2/bin/init.cxx +++ b/libbuild2/bin/init.cxx @@ -3,8 +3,6 @@ #include <libbuild2/bin/init.hxx> -#include <map> - #include <libbuild2/scope.hxx> #include <libbuild2/function.hxx> #include <libbuild2/variable.hxx> @@ -18,6 +16,7 @@ #include <libbuild2/install/utility.hxx> #include <libbuild2/bin/rule.hxx> +#include <libbuild2/bin/def-rule.hxx> #include <libbuild2/bin/guess.hxx> #include <libbuild2/bin/target.hxx> #include <libbuild2/bin/utility.hxx> @@ -29,8 +28,10 @@ namespace build2 { namespace bin { - static const fail_rule fail_; + static const obj_rule obj_; + static const libul_rule libul_; static const lib_rule lib_; + static const def_rule def_; // Default config.bin.*.lib values. // @@ -40,24 +41,30 @@ namespace build2 bool vars_init (scope& rs, - scope&, - const location&, - bool first, + scope& bs, + const location& loc, + bool, bool, module_init_extra&) { tracer trace ("bin::vars_init"); l5 ([&]{trace << "for " << rs;}); - assert (first); + // We only support root loading (which means there can only be one). + // + if (rs != bs) + fail (loc) << "bin.vars module must be loaded in project root"; // Enter variables. // + // All the variables we enter are qualified so go straight for the + // public variable pool. + // + auto& vp (rs.var_pool (true /* public */)); + // Target is a string and not target_triplet because it can be // specified by the user. // - auto& vp (rs.var_pool ()); - vp.insert<string> ("config.bin.target"); vp.insert<string> ("config.bin.pattern"); @@ -75,6 +82,9 @@ namespace build2 // example, addition of rpaths for prerequisite libraries (see the cc // module for an example). Default is true. // + // Note also that a rule may need to make rpath relative if + // install.relocatable is true. + // vp.insert<dir_paths> ("config.bin.rpath"); vp.insert<bool> ("config.bin.rpath.auto"); @@ -103,12 +113,12 @@ namespace build2 // Link whole archive. Note: with target visibility. // // The lookup semantics is as follows: we first look for a prerequisite- - // specific value, then for a target-specific value in the library being - // linked, and then for target type/pattern-specific value starting from - // the scope of the target being linked-to. In that final lookup we do - // not look in the target being linked-to itself since that is used to - // indicate how this target should be linked to other targets. For - // example: + // specific value, then for a target-specific value in the prerequisite + // library, and then for target type/pattern-specific value starting + // from the scope of the target being linked. In that final lookup we do + // not look in the target being linked itself since that is used to + // indicate how this target should be used as a prerequisite of other + // targets. For example: // // exe{test}: liba{foo} // liba{foo}: libua{foo1 foo2} @@ -116,12 +126,23 @@ namespace build2 // // If unspecified, defaults to false for liba{} and to true for libu*{}. // - vp.insert<bool> ("bin.whole", variable_visibility::target); + vp.insert<bool> ("bin.whole", variable_visibility::target); + + // Mark library as binless. + // + // For example, the user can mark a C++ library consisting of only + // module interfaces as binless so it becomes a modules equivalent to + // header-only library (which we will call a module interface-only + // library). + // + vp.insert<bool> ("bin.binless", variable_visibility::target); - vp.insert<string> ("bin.exe.prefix"); - vp.insert<string> ("bin.exe.suffix"); - vp.insert<string> ("bin.lib.prefix"); - vp.insert<string> ("bin.lib.suffix"); + // Executable and library name prefixes and suffixes. + // + vp.insert<string> ("bin.exe.prefix"); + vp.insert<string> ("bin.exe.suffix"); + vp.insert<string> ("bin.lib.prefix"); + vp.insert<string> ("bin.lib.suffix"); // The optional custom clean patterns should be just the pattern stem, // without the library prefix/name or extension. For example, `-[A-Z]` @@ -132,8 +153,70 @@ namespace build2 vp.insert<string> ("bin.lib.load_suffix"); vp.insert<string> ("bin.lib.load_suffix_pattern"); - vp.insert<map<string, string>> ("bin.lib.version"); - vp.insert<string> ("bin.lib.version_pattern"); + vp.insert<map<optional<string>, string>> ("bin.lib.version"); + vp.insert<string> ("bin.lib.version_pattern"); + + return true; + } + + bool + types_init (scope& rs, + scope& bs, + const location& loc, + bool, + bool, + module_init_extra&) + { + tracer trace ("bin::types_init"); + l5 ([&]{trace << "for " << rs;}); + + // We only support root loading (which means there can only be one). + // + if (rs != bs) + fail (loc) << "bin.types module must be loaded in project root"; + + // Register target types. + // + // Note that certain platform-specific and toolchain-specific types are + // registered in bin and bin.ld. + // + // Note also that it would make sense to configure their default + // "installability" here but that requires the knowledge of the platform + // in some cases. So we do it all in bin for now. One way to support + // both use-cases would be to detect if we are loaded after bin.guess + // and then decide whether to do it here or delay to bin. + // + // NOTE: remember to update the documentation if changing anything here! + // + rs.insert_target_type<obj> (); + rs.insert_target_type<obje> (); + rs.insert_target_type<obja> (); + rs.insert_target_type<objs> (); + + rs.insert_target_type<bmi> (); + rs.insert_target_type<bmie> (); + rs.insert_target_type<bmia> (); + rs.insert_target_type<bmis> (); + + rs.insert_target_type<hbmi> (); + rs.insert_target_type<hbmie> (); + rs.insert_target_type<hbmia> (); + rs.insert_target_type<hbmis> (); + + rs.insert_target_type<libul> (); + rs.insert_target_type<libue> (); + rs.insert_target_type<libua> (); + rs.insert_target_type<libus> (); + + rs.insert_target_type<lib> (); + rs.insert_target_type<liba> (); + rs.insert_target_type<libs> (); + + // Register the def{} target type. Note that we do it here since it is + // input and can be specified unconditionally (i.e., not only when + // building for Windows). + // + rs.insert_target_type<def> (); return true; } @@ -145,7 +228,7 @@ namespace build2 config_init (scope& rs, scope& bs, const location& loc, - bool first, + bool, bool, module_init_extra& extra) { @@ -177,6 +260,130 @@ namespace build2 // config::save_module (rs, "bin", 350); + bool new_cfg (false); // Any new configuration values? + + // config.bin.target + // + const target_triplet* tgt (nullptr); + { + // Note: go straight for the public variable pool. + // + const variable& var (ctx.var_pool["config.bin.target"]); + + // We first see if the value was specified via the configuration + // mechanism. + // + lookup l (lookup_config (new_cfg, rs, var)); + + // Then see if there is a config hint (e.g., from the cc module). + // + bool hint (false); + if (!l) + { + // Note: new_cfg is false for a hinted value. + // + if (auto hl = extra.hints[var]) + { + l = hl; + hint = true; + } + } + + if (!l) + fail (loc) << "unable to determine binutils target" << + info << "consider specifying it with " << var << + 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<string> (l)); + + // 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 && config_sub) + { + s = run<string> (ctx, + 3, + *config_sub, s.c_str (), + [] (string& l, bool) {return move (l);}); + l5 ([&]{trace << "config.sub target: '" << s << "'";}); + } + + try + { + target_triplet t (s); + + l5 ([&]{trace << "canonical target: '" << t.string () << "'; " + << "class: " << t.class_;}); + + assert (!hint || s == t.representation ()); + + // Also enter as bin.target.{cpu,vendor,system,version,class} + // for convenience of access. + // + rs.assign<string> ("bin.target.cpu") = t.cpu; + rs.assign<string> ("bin.target.vendor") = t.vendor; + rs.assign<string> ("bin.target.system") = t.system; + rs.assign<string> ("bin.target.version") = t.version; + rs.assign<string> ("bin.target.class") = t.class_; + + tgt = &rs.assign<target_triplet> ("bin.target", move (t)); + } + 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 << + info << "consider using the --config-sub option"; + } + } + + // config.bin.pattern + // + const string* pat (nullptr); + { + // Note: go straight for the public variable pool. + // + const variable& var (ctx.var_pool["config.bin.pattern"]); + + // We first see if the value was specified via the configuration + // mechanism. + // + lookup l (lookup_config (new_cfg, rs, var)); + + // Then see if there is a config hint (e.g., from the C++ module). + // + if (!l) + { + // Note: new_cfg is false for a hinted value. + // + if (auto hl = extra.hints[var]) + l = hl; + } + + // For ease of use enter it as bin.pattern (since it can come from + // different places). + // + if (l) + { + const string& s (cast<string> (l)); + + if (s.empty () || + (!path::traits_type::is_separator (s.back ()) && + s.find ('*') == string::npos)) + { + fail << "missing '*' or trailing '" + << char (path::traits_type::directory_separator) + << "' in binutils pattern '" << s << "'"; + } + + pat = &rs.assign<string> ("bin.pattern", s); + } + } + // The idea here is as follows: if we already have one of // the bin.* variables set, then we assume this is static // project configuration and don't bother setting the @@ -184,15 +391,20 @@ namespace build2 // //@@ Need to validate the values. Would be more efficient // to do it once on assignment than every time on query. - // Custom var type? // // config.bin.lib // + // By default it's both unless the target doesn't support one of the + // variants. + // { value& v (rs.assign ("bin.lib")); if (!v) - v = *lookup_config (rs, "config.bin.lib", "both"); + v = *lookup_config (rs, + "config.bin.lib", + tgt->system == "emscripten" ? "static" : + "both"); } // config.bin.exe.lib @@ -272,145 +484,26 @@ namespace build2 set ("bin.exe.suffix", "config.bin.exe.suffix", s); } - if (first) + // If this is a configuration with new values, then print the report + // at verbosity level 2 and up (-v). + // + if (verb >= (new_cfg ? 2 : 3)) { - bool new_cfg (false); // Any new configuration values? + diag_record dr (text); - // config.bin.target - // - { - const variable& var (ctx.var_pool["config.bin.target"]); - - // We first see if the value was specified via the configuration - // mechanism. - // - lookup l (lookup_config (new_cfg, rs, var)); + dr << "bin " << project (rs) << '@' << rs << '\n' + << " target " << *tgt; - // Then see if there is a config hint (e.g., from the cc module). - // - bool hint (false); - if (!l) - { - // Note: new_cfg is false for a hinted value. - // - if (auto hl = extra.hints[var]) - { - l = hl; - hint = true; - } - } - - if (!l) - fail (loc) << "unable to determine binutils target" << - info << "consider specifying it with " << var << - 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<string> (l)); - - // 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 && config_sub) - { - s = run<string> (3, - *config_sub, - s.c_str (), - [] (string& l, bool) {return move (l);}); - l5 ([&]{trace << "config.sub target: '" << s << "'";}); - } - - try - { - target_triplet t (s); - - l5 ([&]{trace << "canonical target: '" << t.string () << "'; " - << "class: " << t.class_;}); - - assert (!hint || s == t.representation ()); - - // Also enter as bin.target.{cpu,vendor,system,version,class} - // for convenience of access. - // - rs.assign<string> ("bin.target.cpu") = t.cpu; - rs.assign<string> ("bin.target.vendor") = t.vendor; - rs.assign<string> ("bin.target.system") = t.system; - rs.assign<string> ("bin.target.version") = t.version; - rs.assign<string> ("bin.target.class") = t.class_; - - rs.assign<target_triplet> ("bin.target") = move (t); - } - 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 << - info << "consider using the --config-sub option"; - } - } - - // config.bin.pattern - // - { - const variable& var (ctx.var_pool["config.bin.pattern"]); - - // We first see if the value was specified via the configuration - // mechanism. - // - lookup l (lookup_config (new_cfg, rs, var)); - - // Then see if there is a config hint (e.g., from the C++ module). - // - if (!l) - { - // Note: new_cfg is false for a hinted value. - // - if (auto hl = extra.hints[var]) - l = hl; - } - - // For ease of use enter it as bin.pattern (since it can come from - // different places). - // - if (l) - { - const string& s (cast<string> (l)); - - if (s.empty () || - (!path::traits_type::is_separator (s.back ()) && - s.find ('*') == string::npos)) - { - fail << "missing '*' or trailing '" - << char (path::traits_type::directory_separator) - << "' in binutils pattern '" << s << "'"; - } - - rs.assign<string> ("bin.pattern") = s; - } - } - - // If this is a configuration with new values, then print the report - // at verbosity level 2 and up (-v). - // - if (verb >= (new_cfg ? 2 : 3)) - { - diag_record dr (text); - - dr << "bin " << project (rs) << '@' << rs << '\n' - << " target " << cast<target_triplet> (rs["bin.target"]); - - if (auto l = rs["bin.pattern"]) - dr << '\n' - << " pattern " << cast<string> (l); - } + if (pat != nullptr) + dr << '\n' + << " pattern " << *pat; } return true; } + extern const char wasm_ext[] = "wasm"; // VC14 rejects constexpr. + bool init (scope& rs, scope& bs, @@ -422,53 +515,22 @@ namespace build2 tracer trace ("bin::init"); l5 ([&]{trace << "for " << bs;}); - // Load bin.config. + // Load bin.{config,types}. // load_module (rs, rs, "bin.config", loc, extra.hints); + load_module (rs, rs, "bin.types", loc); // Cache some config values we will be needing below. // - const string& tclass (cast<string> (rs["bin.target.class"])); + const target_triplet& tgt (cast<target_triplet> (rs["bin.target"])); - // Register target types and configure their default "installability". + // Configure target type default "installability". Also register + // additional platform-specific types. // bool install_loaded (cast_false<bool> (rs["install.loaded"])); { using namespace install; - if (first) - { - rs.insert_target_type<obj> (); - rs.insert_target_type<obje> (); - rs.insert_target_type<obja> (); - rs.insert_target_type<objs> (); - - rs.insert_target_type<bmi> (); - rs.insert_target_type<bmie> (); - rs.insert_target_type<bmia> (); - rs.insert_target_type<bmis> (); - - rs.insert_target_type<hbmi> (); - rs.insert_target_type<hbmie> (); - rs.insert_target_type<hbmia> (); - rs.insert_target_type<hbmis> (); - - rs.insert_target_type<libul> (); - rs.insert_target_type<libue> (); - rs.insert_target_type<libua> (); - rs.insert_target_type<libus> (); - - rs.insert_target_type<lib> (); - rs.insert_target_type<liba> (); - rs.insert_target_type<libs> (); - - // Register the def{} target type. Note that we do it here since it - // is input and can be specified unconditionally (i.e., not only - // when building for Windows). - // - rs.insert_target_type<def> (); - } - // Note: libu*{} members are not installable. // if (install_loaded) @@ -497,12 +559,12 @@ namespace build2 // bin/, not lib/. // if (install_loaded) - install_path<libs> (bs, - dir_path (tclass == "windows" ? "bin" : "lib")); + install_path<libs> ( + bs, dir_path (tgt.class_ == "windows" ? "bin" : "lib")); // Create additional target types for certain targets. // - if (tclass == "windows") + if (tgt.class_ == "windows") { // Import library. // @@ -515,6 +577,32 @@ namespace build2 install_mode<libi> (bs, "644"); } } + + if (tgt.cpu == "wasm32" || tgt.cpu == "wasm64") + { + // @@ TODO: shouldn't this be wrapped in if(first) somehow? + + const target_type& wasm ( + rs.derive_target_type( + target_type { + "wasm", + &file::static_type, + nullptr, /* factory */ + &target_extension_fix<wasm_ext>, + nullptr, /* default_extension */ + &target_pattern_fix<wasm_ext>, + &target_print_0_ext_verb, // Fixed extension, no use printing. + &target_search, // Note: don't look for an existing file. + target_type::flag::none})); + + if (install_loaded) + { + // Note that we keep the executable bit on the .wasm file, see + // Emscripten issue 12707 for background. + // + install_path (bs, wasm, dir_path ("bin")); + } + } } // Register rules. @@ -522,22 +610,20 @@ namespace build2 { auto& r (bs.rules); - r.insert<obj> (perform_update_id, "bin.obj", fail_); - r.insert<obj> (perform_clean_id, "bin.obj", fail_); + r.insert<obj> (perform_update_id, "bin.obj", obj_); + r.insert<obj> (perform_clean_id, "bin.obj", obj_); - r.insert<bmi> (perform_update_id, "bin.bmi", fail_); - r.insert<bmi> (perform_clean_id, "bin.bmi", fail_); + r.insert<bmi> (perform_update_id, "bin.bmi", obj_); + r.insert<bmi> (perform_clean_id, "bin.bmi", obj_); - r.insert<hbmi> (perform_update_id, "bin.hbmi", fail_); - r.insert<hbmi> (perform_clean_id, "bin.hbmi", fail_); + r.insert<hbmi> (perform_update_id, "bin.hbmi", obj_); + r.insert<hbmi> (perform_clean_id, "bin.hbmi", obj_); - r.insert<libul> (perform_update_id, "bin.libul", fail_); - r.insert<libul> (perform_clean_id, "bin.libul", fail_); + r.insert<libul> (perform_update_id, "bin.libul", libul_); + r.insert<libul> (perform_clean_id, "bin.libul", libul_); // Similar to alias. // - - //@@ outer r.insert<lib> (perform_id, 0, "bin.lib", lib_); r.insert<lib> (configure_id, 0, "bin.lib", lib_); @@ -558,6 +644,18 @@ namespace build2 if (rs.find_module ("dist")) { + // Note that without custom dist rules in setups along the follwing + // lines the source file will be unreachable by dist: + // + // lib{foo}: obj{foo} + // obja{foo}: cxx{foo} + // objs{foo}: cxx{foo} + // + r.insert<obj> (dist_id, 0, "bin.obj", obj_); + r.insert<bmi> (dist_id, 0, "bin.bmi", obj_); + r.insert<hbmi> (dist_id, 0, "bin.hbmi", obj_); + r.insert<libul> (dist_id, 0, "bin.libul", libul_); + r.insert<lib> (dist_id, 0, "bin.lib", lib_); } } @@ -584,7 +682,10 @@ namespace build2 // if (first) { - auto& vp (rs.var_pool ()); + // All the variables we enter are qualified so go straight for the + // public variable pool. + // + auto& vp (rs.var_pool (true /* public */)); vp.insert<path> ("config.bin.ar"); vp.insert<path> ("config.bin.ranlib"); @@ -642,7 +743,7 @@ namespace build2 nullptr, config::save_default_commented))); - ar_info ari (guess_ar (ar, ranlib, pat.paths)); + const ar_info& ari (guess_ar (rs.ctx, ar, ranlib, pat.paths)); // If this is a configuration with new values, then print the report // at verbosity level 2 and up (-v). @@ -681,34 +782,39 @@ namespace build2 } } - rs.assign<process_path_ex> ("bin.ar.path") = - process_path_ex (move (ari.ar_path), "ar", ari.ar_checksum); - rs.assign<string> ("bin.ar.id") = move (ari.ar_id); - rs.assign<string> ("bin.ar.signature") = move (ari.ar_signature); - rs.assign<string> ("bin.ar.checksum") = move (ari.ar_checksum); + rs.assign<process_path_ex> ("bin.ar.path") = process_path_ex ( + ari.ar_path, + "ar", + ari.ar_checksum, + hash_environment (ari.ar_environment)); + rs.assign<string> ("bin.ar.id") = ari.ar_id; + rs.assign<string> ("bin.ar.signature") = ari.ar_signature; + rs.assign<string> ("bin.ar.checksum") = ari.ar_checksum; { - semantic_version& v (ari.ar_version); + const semantic_version& v (ari.ar_version); rs.assign<string> ("bin.ar.version") = v.string (); rs.assign<uint64_t> ("bin.ar.version.major") = v.major; rs.assign<uint64_t> ("bin.ar.version.minor") = v.minor; rs.assign<uint64_t> ("bin.ar.version.patch") = v.patch; - rs.assign<string> ("bin.ar.version.build") = move (v.build); + rs.assign<string> ("bin.ar.version.build") = v.build; } + config::save_environment (rs, ari.ar_environment); + if (ranlib != nullptr) { - rs.assign<process_path_ex> ("bin.ranlib.path") = - process_path_ex (move (ari.ranlib_path), - "ranlib", - ari.ranlib_checksum); - rs.assign<string> ("bin.ranlib.id") = - move (ari.ranlib_id); - rs.assign<string> ("bin.ranlib.signature") = - move (ari.ranlib_signature); - rs.assign<string> ("bin.ranlib.checksum") = - move (ari.ranlib_checksum); + rs.assign<process_path_ex> ("bin.ranlib.path") = process_path_ex ( + ari.ranlib_path, + "ranlib", + ari.ranlib_checksum, + hash_environment (ari.ranlib_environment)); + rs.assign<string> ("bin.ranlib.id") = ari.ranlib_id; + rs.assign<string> ("bin.ranlib.signature") = ari.ranlib_signature; + rs.assign<string> ("bin.ranlib.checksum") = ari.ranlib_checksum; + + config::save_environment (rs, ari.ranlib_environment); } } @@ -753,7 +859,10 @@ namespace build2 // if (first) { - auto& vp (rs.var_pool ()); + // All the variables we enter are qualified so go straight for the + // public variable pool. + // + auto& vp (rs.var_pool (true /* public */)); vp.insert<path> ("config.bin.ld"); } @@ -785,7 +894,7 @@ namespace build2 path (apply_pattern (ld_d, pat.pattern)), config::save_default_commented))); - ld_info ldi (guess_ld (ld, pat.paths)); + const ld_info& ldi (guess_ld (rs.ctx, ld, pat.paths)); // If this is a configuration with new values, then print the report // at verbosity level 2 and up (-v). @@ -817,27 +926,34 @@ namespace build2 << " checksum " << ldi.checksum; } - rs.assign<process_path_ex> ("bin.ld.path") = - process_path_ex (move (ldi.path), "ld", ldi.checksum); - rs.assign<string> ("bin.ld.id") = move (ldi.id); - rs.assign<string> ("bin.ld.signature") = move (ldi.signature); - rs.assign<string> ("bin.ld.checksum") = move (ldi.checksum); + rs.assign<process_path_ex> ("bin.ld.path") = process_path_ex ( + ldi.path, + "ld", + ldi.checksum, + hash_environment (ldi.environment)); + rs.assign<string> ("bin.ld.id") = ldi.id; + rs.assign<string> ("bin.ld.signature") = ldi.signature; + rs.assign<string> ("bin.ld.checksum") = ldi.checksum; if (ldi.version) { - semantic_version& v (*ldi.version); + const semantic_version& v (*ldi.version); rs.assign<string> ("bin.ld.version") = v.string (); rs.assign<uint64_t> ("bin.ld.version.major") = v.major; rs.assign<uint64_t> ("bin.ld.version.minor") = v.minor; rs.assign<uint64_t> ("bin.ld.version.patch") = v.patch; - rs.assign<string> ("bin.ld.version.build") = move (v.build); + rs.assign<string> ("bin.ld.version.build") = v.build; } + + config::save_environment (rs, ldi.environment); } return true; } + extern const char pdb_ext[] = "pdb"; // VC14 rejects constexpr. + bool ld_init (scope& rs, scope& bs, @@ -862,7 +978,20 @@ namespace build2 if (lid == "msvc") { - const target_type& pdb (bs.derive_target_type<file> ("pdb").first); + // @@ TODO: shouldn't this be wrapped in if(first) somehow? + + const target_type& pdb ( + rs.derive_target_type( + target_type { + "pdb", + &file::static_type, + nullptr, /* factory */ + &target_extension_fix<pdb_ext>, + nullptr, /* default_extension */ + &target_pattern_fix<pdb_ext>, + &target_print_0_ext_verb, // Fixed extension, no use printing. + &target_search, // Note: don't look for an existing file. + target_type::flag::none})); if (cast_false<bool> (rs["install.loaded"])) { @@ -893,7 +1022,10 @@ namespace build2 // if (first) { - auto& vp (rs.var_pool ()); + // All the variables we enter are qualified so go straight for the + // public variable pool. + // + auto& vp (rs.var_pool (true /* public */)); vp.insert<path> ("config.bin.rc"); } @@ -925,7 +1057,7 @@ namespace build2 path (apply_pattern (rc_d, pat.pattern)), config::save_default_commented))); - rc_info rci (guess_rc (rc, pat.paths)); + const rc_info& rci (guess_rc (rs.ctx, rc, pat.paths)); // If this is a configuration with new values, then print the report // at verbosity level 2 and up (-v). @@ -939,11 +1071,16 @@ namespace build2 << " checksum " << rci.checksum; } - rs.assign<process_path_ex> ("bin.rc.path") = - process_path_ex (move (rci.path), "rc", rci.checksum); - rs.assign<string> ("bin.rc.id") = move (rci.id); - rs.assign<string> ("bin.rc.signature") = move (rci.signature); - rs.assign<string> ("bin.rc.checksum") = move (rci.checksum); + rs.assign<process_path_ex> ("bin.rc.path") = process_path_ex ( + rci.path, + "rc", + rci.checksum, + hash_environment (rci.environment)); + rs.assign<string> ("bin.rc.id") = rci.id; + rs.assign<string> ("bin.rc.signature") = rci.signature; + rs.assign<string> ("bin.rc.checksum") = rci.checksum; + + config::save_environment (rs, rci.environment); } return true; @@ -968,20 +1105,167 @@ namespace build2 return true; } + bool + nm_config_init (scope& rs, + scope& bs, + const location& loc, + bool first, + bool, + module_init_extra& extra) + { + tracer trace ("bin::nm_config_init"); + l5 ([&]{trace << "for " << bs;}); + + // Make sure bin.config is loaded. + // + load_module (rs, bs, "bin.config", loc, extra.hints); + + // Enter configuration variables. + // + if (first) + { + // All the variables we enter are qualified so go straight for the + // public variable pool. + // + auto& vp (rs.var_pool (true /* public */)); + + vp.insert<path> ("config.bin.nm"); + } + + // Configuration. + // + if (first) + { + using config::lookup_config; + + bool new_cfg (false); // Any new configuration values? + + // config.bin.nm + // + // Use the target to decide on the default nm name. Note that in case + // of win32-msvc this is insufficient and we fallback to the linker + // type (if available) to decide between dumpbin and llvm-nm (with + // fallback to dumpbin). + // + // Finally note that the dumpbin.exe functionality is available via + // link.exe /DUMP. + // + const string& tsys (cast<string> (rs["bin.target.system"])); + const char* nm_d (tsys == "win32-msvc" + ? (cast_empty<string> (rs["bin.ld.id"]) == "msvc-lld" + ? "llvm-nm" + : "dumpbin") + : "nm"); + + // This can be either a pattern or search path(s). + // + pattern_paths pat (lookup_pattern (rs)); + + const path& nm ( + cast<path> ( + lookup_config (new_cfg, + rs, + "config.bin.nm", + path (apply_pattern (nm_d, pat.pattern)), + config::save_default_commented))); + + const nm_info& nmi (guess_nm (rs.ctx, nm, pat.paths)); + + // If this is a configuration with new values, then print the report + // at verbosity level 2 and up (-v). + // + if (verb >= (new_cfg ? 2 : 3)) + { + text << "bin.nm " << project (rs) << '@' << rs << '\n' + << " nm " << nmi.path << '\n' + << " id " << nmi.id << '\n' + << " signature " << nmi.signature << '\n' + << " checksum " << nmi.checksum; + } + + rs.assign<process_path_ex> ("bin.nm.path") = process_path_ex ( + nmi.path, + "nm", + nmi.checksum, + hash_environment (nmi.environment)); + rs.assign<string> ("bin.nm.id") = nmi.id; + rs.assign<string> ("bin.nm.signature") = nmi.signature; + rs.assign<string> ("bin.nm.checksum") = nmi.checksum; + + config::save_environment (rs, nmi.environment); + } + + return true; + } + + bool + nm_init (scope& rs, + scope& bs, + const location& loc, + bool, + bool, + module_init_extra& extra) + { + tracer trace ("bin::nm_init"); + l5 ([&]{trace << "for " << bs;}); + + // Make sure the bin core and nm.config are loaded. + // + load_module (rs, bs, "bin", loc, extra.hints); + load_module (rs, bs, "bin.nm.config", loc, extra.hints); + + return true; + } + + bool + def_init (scope& rs, + scope& bs, + const location& loc, + bool, + bool, + module_init_extra& extra) + { + tracer trace ("bin::def_init"); + l5 ([&]{trace << "for " << bs;}); + + // Make sure the bin core is loaded (def{} target type). We also load + // nm.config unless we are using MSVC link.exe and can access dumpbin + // via its /DUMP option. + // + const string* lid (cast_null<string> (rs["bin.ld.id"])); + + load_module (rs, bs, "bin", loc, extra.hints); + + if (lid == nullptr || *lid != "msvc") + load_module (rs, bs, "bin.nm.config", loc, extra.hints); + + // Register the def{} rule. + // + bs.insert_rule<def> (perform_update_id, "bin.def", def_); + bs.insert_rule<def> (perform_clean_id, "bin.def", def_); + bs.insert_rule<def> (configure_update_id, "bin.def", def_); + + return true; + } + static const module_functions mod_functions[] = { // NOTE: don't forget to also update the documentation in init.hxx if // changing anything here. {"bin.vars", nullptr, vars_init}, + {"bin.types", nullptr, types_init}, {"bin.config", nullptr, config_init}, - {"bin", nullptr, init}, {"bin.ar.config", nullptr, ar_config_init}, {"bin.ar", nullptr, ar_init}, {"bin.ld.config", nullptr, ld_config_init}, {"bin.ld", nullptr, ld_init}, {"bin.rc.config", nullptr, rc_config_init}, {"bin.rc", nullptr, rc_init}, + {"bin.nm.config", nullptr, nm_config_init}, + {"bin.nm", nullptr, nm_init}, + {"bin.def", nullptr, def_init}, + {"bin", nullptr, init}, {nullptr, nullptr, nullptr} }; |