From ea24f530048cbce0c5335ca3fd3632c8ce34315a Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Sat, 24 Aug 2019 16:37:29 +0300 Subject: Move bin build system module to separate library --- build2/bin/init.cxx | 940 ---------------------------------------------------- 1 file changed, 940 deletions(-) delete mode 100644 build2/bin/init.cxx (limited to 'build2/bin/init.cxx') diff --git a/build2/bin/init.cxx b/build2/bin/init.cxx deleted file mode 100644 index 54bd84a..0000000 --- a/build2/bin/init.cxx +++ /dev/null @@ -1,940 +0,0 @@ -// file : build2/bin/init.cxx -*- C++ -*- -// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd -// license : MIT; see accompanying LICENSE file - -#include - -#include - -#include -#include -#include - -#include - -#include - -#include -#include - -#include -#include -#include - -using namespace std; -using namespace butl; - -namespace build2 -{ - namespace bin - { - static const fail_rule fail_; - static const lib_rule lib_; - - // Default config.bin.*.lib values. - // - static const strings exe_lib {"shared", "static"}; - static const strings liba_lib {"static", "shared"}; - static const strings libs_lib {"shared", "static"}; - - bool - vars_init (scope& rs, - scope&, - const location&, - unique_ptr&, - bool first, - bool, - const variable_map&) - { - tracer trace ("bin::vars_init"); - l5 ([&]{trace << "for " << rs;}); - - assert (first); - - // Enter variables. Note: some overridable, some not. - // - // Target is a string and not target_triplet because it can be - // specified by the user. - // - auto& vp (rs.ctx.var_pool.rw (rs)); - - vp.insert ("config.bin.target", true); - vp.insert ("config.bin.pattern", true); - - // Library types to build. - // - vp.insert ("config.bin.lib", true); - - // Library types to use (in priority order). - // - vp.insert ("config.bin.exe.lib", true); - vp.insert ("config.bin.liba.lib", true); - vp.insert ("config.bin.libs.lib", true); - - // The rpath[_link].auto flag controls automatic rpath behavior, for - // example, addition of rpaths for prerequisite libraries (see the cc - // module for an example). Default is true. - // - vp.insert ("config.bin.rpath", true); - vp.insert ("config.bin.rpath.auto", true); - - vp.insert ("config.bin.rpath_link", true); - vp.insert ("config.bin.rpath_link.auto", true); - - vp.insert ("config.bin.prefix", true); - vp.insert ("config.bin.suffix", true); - vp.insert ("config.bin.lib.prefix", true); - vp.insert ("config.bin.lib.suffix", true); - vp.insert ("config.bin.exe.prefix", true); - vp.insert ("config.bin.exe.suffix", true); - - vp.insert ("bin.lib"); - - vp.insert ("bin.exe.lib"); - vp.insert ("bin.liba.lib"); - vp.insert ("bin.libs.lib"); - - vp.insert ("bin.rpath"); - vp.insert ("bin.rpath.auto"); - - vp.insert ("bin.rpath_link"); - vp.insert ("bin.rpath_link.auto"); - - // Link whole archive. Note: non-overridable 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: - // - // exe{test}: liba{foo} - // liba{foo}: libua{foo1 foo2} - // liba{foo}: bin.whole = false # Affects test but not foo1 and foo2. - // - // If unspecified, defaults to false for liba{} and to true for libu*{}. - // - vp.insert ("bin.whole", false, variable_visibility::target); - - vp.insert ("bin.exe.prefix"); - vp.insert ("bin.exe.suffix"); - vp.insert ("bin.lib.prefix"); - vp.insert ("bin.lib.suffix"); - - vp.insert ("bin.lib.load_suffix", - variable_visibility::project); - - vp.insert> ("bin.lib.version", - variable_visibility::project); - - return true; - } - - bool - config_init (scope& rs, - scope& bs, - const location& loc, - unique_ptr&, - bool first, - bool, - const variable_map& hints) - { - tracer trace ("bin::config_init"); - l5 ([&]{trace << "for " << bs;}); - - // We only support root loading (which means there can only be one). - // - if (&rs != &bs) - fail (loc) << "bin.config module must be loaded in project root"; - - // Load bin.vars. - // - if (!cast_false (rs["bin.vars.loaded"])) - load_module (rs, rs, "bin.vars", loc); - - // Configure. - // - using config::required; - using config::optional; - using config::omitted; - - // Adjust module priority (binutils). - // - config::save_module (rs, "bin", 350); - - // 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 - // corresponding config.bin.* variable. - // - //@@ 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 - // - { - value& v (rs.assign ("bin.lib")); - if (!v) - v = *required (rs, "config.bin.lib", "both").first; - } - - // config.bin.exe.lib - // - { - value& v (rs.assign ("bin.exe.lib")); - if (!v) - v = *required (rs, "config.bin.exe.lib", exe_lib).first; - } - - // config.bin.liba.lib - // - { - value& v (rs.assign ("bin.liba.lib")); - if (!v) - v = *required (rs, "config.bin.liba.lib", liba_lib).first; - } - - // config.bin.libs.lib - // - { - value& v (rs.assign ("bin.libs.lib")); - if (!v) - v = *required (rs, "config.bin.libs.lib", libs_lib).first; - } - - // config.bin.rpath[_link] - // - // These ones are optional and we merge them into bin.rpath[_link], if - // any. - // - rs.assign ("bin.rpath") += cast_null ( - optional (rs, "config.bin.rpath")); - - rs.assign ("bin.rpath_link") += cast_null ( - optional (rs, "config.bin.rpath_link")); - - // config.bin.rpath[_link].auto - // - { - lookup l; - - rs.assign ("bin.rpath.auto") = - (l = omitted (rs, "config.bin.rpath.auto").first) - ? cast (l) - : true; - - rs.assign ("bin.rpath_link.auto") = - (l = omitted (rs, "config.bin.rpath_link.auto").first) - ? cast (l) - : true; - } - - // config.bin.{lib,exe}.{prefix,suffix} - // - // These ones are not used very often so we will omit them from the - // config.build if not specified. We also override any existing value - // that might have been specified before loading the module. - // - { - lookup p (omitted (rs, "config.bin.prefix").first); - lookup s (omitted (rs, "config.bin.suffix").first); - - auto set = [&rs] (const char* bv, const char* cv, lookup l) - { - if (lookup o = omitted (rs, cv).first) - l = o; - - if (l) - rs.assign (bv) = *l; - }; - - set ("bin.lib.prefix", "config.bin.lib.prefix", p); - set ("bin.lib.suffix", "config.bin.lib.suffix", s); - - set ("bin.exe.prefix", "config.bin.exe.prefix", p); - set ("bin.exe.suffix", "config.bin.exe.suffix", s); - } - - if (first) - { - bool new_val (false); // Set any new values? - - // config.bin.target - // - { - const variable& var (rs.ctx.var_pool["config.bin.target"]); - - // We first see if the value was specified via the configuration - // mechanism. - // - auto p (omitted (rs, var)); - lookup l (p.first); - - // Then see if there is a config hint (e.g., from the cc module). - // - bool hint (false); - if (!l) - { - if (auto hl = 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 (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 (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.string ()); - - // Also enter as bin.target.{cpu,vendor,system,version,class} - // for convenience of access. - // - rs.assign ("bin.target.cpu") = t.cpu; - rs.assign ("bin.target.vendor") = t.vendor; - rs.assign ("bin.target.system") = t.system; - rs.assign ("bin.target.version") = t.version; - rs.assign ("bin.target.class") = t.class_; - - rs.assign ("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"; - } - - new_val = new_val || p.second; // False for a hinted value. - } - - // config.bin.pattern - // - { - const variable& var (rs.ctx.var_pool["config.bin.pattern"]); - - // We first see if the value was specified via the configuration - // mechanism. - // - auto p (omitted (rs, var)); - lookup l (p.first); - - // Then see if there is a config hint (e.g., from the C++ module). - // - if (!l) - { - if (auto hl = 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 (l)); - - if (s.empty () || - (!path::traits_type::is_separator (s.back ()) && - s.find ('*') == string::npos)) - { - fail << "missing '*' in binutils pattern '" << s << "'"; - } - - rs.assign ("bin.pattern") = s; - new_val = new_val || p.second; // False for a hinted value. - } - } - - // If we set any new values (e.g., we are configuring), then print the - // report at verbosity level 2 and up (-v). - // - if (verb >= (new_val ? 2 : 3)) - { - diag_record dr (text); - - dr << "bin " << project (rs) << '@' << rs << '\n' - << " target " << cast (rs["bin.target"]); - - if (auto l = rs["bin.pattern"]) - dr << '\n' - << " pattern " << cast (l); - } - } - - return true; - } - - bool - init (scope& rs, - scope& bs, - const location& loc, - unique_ptr&, - bool first, - bool, - const variable_map& hints) - { - tracer trace ("bin::init"); - l5 ([&]{trace << "for " << bs;}); - - // Load bin.config. - // - if (!cast_false (rs["bin.config.loaded"])) - load_module (rs, rs, "bin.config", loc, false, hints); - - // Cache some config values we will be needing below. - // - const string& tclass (cast (rs["bin.target.class"])); - - // Register target types and configure their default "installability". - // - bool install_loaded (cast_false (rs["install.loaded"])); - { - using namespace install; - - if (first) - { - rs.insert_target_type (); - rs.insert_target_type (); - rs.insert_target_type (); - rs.insert_target_type (); - - rs.insert_target_type (); - rs.insert_target_type (); - rs.insert_target_type (); - rs.insert_target_type (); - - rs.insert_target_type (); - rs.insert_target_type (); - rs.insert_target_type (); - rs.insert_target_type (); - - rs.insert_target_type (); - rs.insert_target_type (); - rs.insert_target_type (); - rs.insert_target_type (); - - rs.insert_target_type (); - rs.insert_target_type (); - rs.insert_target_type (); - - // 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 (); - } - - // Note: libu*{} members are not installable. - // - if (install_loaded) - { - install_path (bs, dir_path ("lib")); // Install in install.lib. - install_mode (bs, "644"); - } - - // Should shared libraries have the executable bit? That depends on - // who you ask. In Debian, for example, it should not unless, it - // really is executable (i.e., has main()). On the other hand, on - // some systems, this may be required in order for the dynamic - // linker to be able to load the library. So, by default, we will - // keep it executable, especially seeing that this is also the - // behavior of autotools. At the same time, it is easy to override - // this, for example: - // - // config.install.lib.mode=644 - // - // And a library that wants to override any such overrides (e.g., - // because it does have main()) can do: - // - // libs{foo}: install.mode=755 - // - // Everyone is happy then? On Windows libs{} is the DLL and goes to - // bin/, not lib/. - // - if (install_loaded) - install_path (bs, - dir_path (tclass == "windows" ? "bin" : "lib")); - - // Create additional target types for certain targets. - // - if (tclass == "windows") - { - // Import library. - // - if (first) - rs.insert_target_type (); - - if (install_loaded) - { - install_path (bs, dir_path ("lib")); - install_mode (bs, "644"); - } - } - } - - // Register rules. - // - { - auto& r (bs.rules); - - r.insert (perform_update_id, "bin.obj", fail_); - r.insert (perform_clean_id, "bin.obj", fail_); - - r.insert (perform_update_id, "bin.bmi", fail_); - r.insert (perform_clean_id, "bin.bmi", fail_); - - r.insert (perform_update_id, "bin.hbmi", fail_); - r.insert (perform_clean_id, "bin.hbmi", fail_); - - r.insert (perform_update_id, "bin.libul", fail_); - r.insert (perform_clean_id, "bin.libul", fail_); - - // Similar to alias. - // - - //@@ outer - r.insert (perform_id, 0, "bin.lib", lib_); - r.insert (configure_id, 0, "bin.lib", lib_); - - // Treat as a see through group for install and test. - // - if (install_loaded) - { - auto& gr (install::group_rule::instance); - - r.insert (perform_install_id, "bin.lib", gr); - r.insert (perform_uninstall_id, "bin.lib", gr); - } - - if (const test::module* m = rs.lookup_module ("test")) - { - r.insert (perform_test_id, "bin.lib", m->group_rule ()); - } - } - - return true; - } - - bool - ar_config_init (scope& rs, - scope& bs, - const location& loc, - unique_ptr&, - bool first, - bool, - const variable_map& hints) - { - tracer trace ("bin::ar_config_init"); - l5 ([&]{trace << "for " << bs;}); - - // Make sure bin.config is loaded. - // - if (!cast_false (rs["bin.config.loaded"])) - load_module (rs, bs, "bin.config", loc, false, hints); - - // Enter configuration variables. - // - if (first) - { - auto& v (rs.ctx.var_pool.rw (rs)); - - v.insert ("bin.ar.path"); - v.insert ("bin.ranlib.path"); - - v.insert ("config.bin.ar", true); - v.insert ("config.bin.ranlib", true); - } - - // Configure. - // - if (first) - { - // config.bin.ar - // config.bin.ranlib - // - // For config.bin.ar we have the default (plus the pattern) while - // ranlib should be explicitly specified by the user in order for us - // to use it (all targets that we currently care to support have the - // ar -s option but if that changes we can always force the use of - // ranlib for certain targets). - // - // Another idea is to refuse to use default 'ar' (without the pattern) - // if the host/build targets don't match. On the other hand, a cross- - // toolchain can be target-unprefixed. Also, without canonicalization, - // comparing targets will be unreliable. - // - - // Use the target to decide on the default binutils program names. - // - const string& tsys (cast (rs["bin.target.system"])); - const char* ar_d (tsys == "win32-msvc" ? "lib" : "ar"); - - // This can be either a pattern or a fallback search directory. - // - const string* pat (cast_null (rs["bin.pattern"])); - - bool fb (pat != nullptr && - path::traits_type::is_separator (pat->back ())); - - // Don't save the default value to config.build so that if the user - // changes, say, the C++ compiler (which hinted the pattern), then - // ar will automatically change as well. - // - auto ap ( - config::required ( - rs, - "config.bin.ar", - path (apply_pattern (ar_d, fb ? nullptr : pat)), - false, - config::save_commented)); - - auto rp ( - config::required ( - rs, - "config.bin.ranlib", - nullptr, - false, - config::save_commented)); - - const path& ar (cast (ap.first)); - const path* ranlib (cast_null (rp.first)); - - ar_info ari ( - guess_ar (ar, ranlib, fb ? dir_path (*pat) : dir_path ())); - - // If this is a new value (e.g., we are configuring), then print the - // report at verbosity level 2 and up (-v). - // - if (verb >= (ap.second || rp.second ? 2 : 3)) - { - diag_record dr (text); - - { - dr << "bin.ar " << project (rs) << '@' << rs << '\n' - << " ar " << ari.ar_path << '\n' - << " id " << ari.ar_id << '\n' - << " version " << ari.ar_version.string () << '\n' - << " major " << ari.ar_version.major << '\n' - << " minor " << ari.ar_version.minor << '\n' - << " patch " << ari.ar_version.patch << '\n'; - } - - if (!ari.ar_version.build.empty ()) - { - dr << " build " << ari.ar_version.build << '\n'; - } - - { - dr << " signature " << ari.ar_signature << '\n' - << " checksum " << ari.ar_checksum; - } - - if (ranlib != nullptr) - { - dr << '\n' - << " ranlib " << ari.ranlib_path << '\n' - << " id " << ari.ranlib_id << '\n' - << " signature " << ari.ranlib_signature << '\n' - << " checksum " << ari.ranlib_checksum; - } - } - - rs.assign ("bin.ar.path") = move (ari.ar_path); - rs.assign ("bin.ar.id") = move (ari.ar_id); - rs.assign ("bin.ar.signature") = move (ari.ar_signature); - rs.assign ("bin.ar.checksum") = move (ari.ar_checksum); - - { - semantic_version& v (ari.ar_version); - - rs.assign ("bin.ar.version") = v.string (); - rs.assign ("bin.ar.version.major") = v.major; - rs.assign ("bin.ar.version.minor") = v.minor; - rs.assign ("bin.ar.version.patch") = v.patch; - rs.assign ("bin.ar.version.build") = move (v.build); - } - - if (ranlib != nullptr) - { - rs.assign ("bin.ranlib.path") = move (ari.ranlib_path); - rs.assign ("bin.ranlib.id") = move (ari.ranlib_id); - rs.assign ("bin.ranlib.signature") = - move (ari.ranlib_signature); - rs.assign ("bin.ranlib.checksum") = - move (ari.ranlib_checksum); - } - } - - return true; - } - - bool - ar_init (scope& rs, - scope& bs, - const location& loc, - unique_ptr&, - bool, - bool, - const variable_map& hints) - { - tracer trace ("bin::ar_init"); - l5 ([&]{trace << "for " << bs;}); - - // Make sure the bin core and ar.config are loaded. - // - if (!cast_false (bs["bin.loaded"])) - load_module (rs, bs, "bin", loc, false, hints); - - if (!cast_false (bs["bin.ar.config.loaded"])) - load_module (rs, bs, "bin.ar.config", loc, false, hints); - - return true; - } - - bool - ld_config_init (scope& rs, - scope& bs, - const location& loc, - unique_ptr&, - bool first, - bool, - const variable_map& hints) - { - tracer trace ("bin::ld_config_init"); - l5 ([&]{trace << "for " << bs;}); - - // Make sure bin.config is loaded. - // - if (!cast_false (rs["bin.config.loaded"])) - load_module (rs, rs, "bin.config", loc, false, hints); - - // Enter configuration variables. - // - if (first) - { - auto& v (rs.ctx.var_pool.rw (rs)); - - v.insert ("bin.ld.path"); - v.insert ("config.bin.ld", true); - } - - // Configure. - // - if (first) - { - // config.bin.ld - // - // Use the target to decide on the default ld name. - // - const string& tsys (cast (rs["bin.target.system"])); - const char* ld_d (tsys == "win32-msvc" ? "link" : "ld"); - - // This can be either a pattern or a fallback search directory. - // - const string* pat (cast_null (rs["bin.pattern"])); - - bool fb (pat != nullptr && - path::traits_type::is_separator (pat->back ())); - - auto p ( - config::required ( - rs, - "config.bin.ld", - path (apply_pattern (ld_d, fb ? nullptr : pat)), - false, - config::save_commented)); - - const path& ld (cast (p.first)); - ld_info ldi (guess_ld (ld, fb ? dir_path (*pat) : dir_path ())); - - // 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.ld " << project (rs) << '@' << rs << '\n' - << " ld " << ldi.path << '\n' - << " id " << ldi.id << '\n' - << " signature " << ldi.signature << '\n' - << " checksum " << ldi.checksum; - } - - rs.assign ("bin.ld.path") = move (ldi.path); - rs.assign ("bin.ld.id") = move (ldi.id); - rs.assign ("bin.ld.signature") = move (ldi.signature); - rs.assign ("bin.ld.checksum") = move (ldi.checksum); - } - - return true; - } - - bool - ld_init (scope& rs, - scope& bs, - const location& loc, - unique_ptr&, - bool, - bool, - const variable_map& hints) - { - tracer trace ("bin::ld_init"); - l5 ([&]{trace << "for " << bs;}); - - // Make sure the bin core and ld.config are loaded. - // - if (!cast_false (bs["bin.loaded"])) - load_module (rs, bs, "bin", loc, false, hints); - - if (!cast_false (bs["bin.ld.config.loaded"])) - load_module (rs, bs, "bin.ld.config", loc, false, hints); - - const string& lid (cast (rs["bin.ld.id"])); - - // Register the pdb{} target if using the VC toolchain. - // - using namespace install; - - if (lid == "msvc") - { - const target_type& pdb (bs.derive_target_type ("pdb").first); - install_path (bs, pdb, dir_path ("bin")); // Goes to install.bin - install_mode (bs, pdb, "644"); // But not executable. - } - - return true; - } - - bool - rc_config_init (scope& rs, - scope& bs, - const location& loc, - unique_ptr&, - bool first, - bool, - const variable_map& hints) - { - tracer trace ("bin::rc_config_init"); - l5 ([&]{trace << "for " << bs;}); - - // Make sure bin.config is loaded. - // - if (!cast_false (bs["bin.config.loaded"])) - load_module (rs, bs, "bin.config", loc, false, hints); - - // Enter configuration variables. - // - if (first) - { - auto& v (rs.ctx.var_pool.rw (rs)); - - v.insert ("bin.rc.path"); - 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 (rs["bin.target.system"])); - const char* rc_d (tsys == "win32-msvc" ? "rc" : "windres"); - - // This can be either a pattern or a fallback search directory. - // - const string* pat (cast_null (rs["bin.pattern"])); - - bool fb (pat != nullptr && - path::traits_type::is_separator (pat->back ())); - - auto p ( - config::required ( - rs, - "config.bin.rc", - path (apply_pattern (rc_d, fb ? nullptr : pat)), - false, - config::save_commented)); - - const path& rc (cast (p.first)); - rc_info rci (guess_rc (rc, fb ? dir_path (*pat) : dir_path ())); - - // 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 " << project (rs) << '@' << rs << '\n' - << " rc " << rci.path << '\n' - << " id " << rci.id << '\n' - << " signature " << rci.signature << '\n' - << " checksum " << rci.checksum; - } - - rs.assign ("bin.rc.path") = move (rci.path); - rs.assign ("bin.rc.id") = move (rci.id); - rs.assign ("bin.rc.signature") = move (rci.signature); - rs.assign ("bin.rc.checksum") = move (rci.checksum); - } - - return true; - } - - bool - rc_init (scope& rs, - scope& bs, - const location& loc, - unique_ptr&, - bool, - bool, - const variable_map& hints) - { - tracer trace ("bin::rc_init"); - l5 ([&]{trace << "for " << bs;}); - - // Make sure the bin core and rc.config are loaded. - // - if (!cast_false (bs["bin.loaded"])) - load_module (rs, bs, "bin", loc, false, hints); - - if (!cast_false (bs["bin.rc.config.loaded"])) - load_module (rs, bs, "bin.rc.config", loc, false, hints); - - return true; - } - } -} -- cgit v1.1