aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/bin/init.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/bin/init.cxx')
-rw-r--r--libbuild2/bin/init.cxx768
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}
};