diff options
Diffstat (limited to 'libbuild2/cc/module.cxx')
-rw-r--r-- | libbuild2/cc/module.cxx | 629 |
1 files changed, 434 insertions, 195 deletions
diff --git a/libbuild2/cc/module.cxx b/libbuild2/cc/module.cxx index 1aa1e01..cf6c6e4 100644 --- a/libbuild2/cc/module.cxx +++ b/libbuild2/cc/module.cxx @@ -6,14 +6,12 @@ #include <iomanip> // left, setw() #include <libbuild2/scope.hxx> +#include <libbuild2/function.hxx> #include <libbuild2/diagnostics.hxx> #include <libbuild2/bin/target.hxx> -#include <libbuild2/cc/target.hxx> // pc* - #include <libbuild2/config/utility.hxx> -#include <libbuild2/install/utility.hxx> #include <libbuild2/cc/guess.hxx> @@ -29,6 +27,8 @@ namespace build2 { tracer trace (x, "guess_init"); + context& ctx (rs.ctx); + bool cc_loaded (cast_false<bool> (rs["cc.core.guess.loaded"])); // Adjust module priority (compiler). Also order cc module before us @@ -40,7 +40,10 @@ namespace build2 config::save_module (rs, x, 250); - 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 */)); // Must already exist. // @@ -54,7 +57,7 @@ namespace build2 // config.x // - strings mode; + strings omode; // Original mode. { // Normally we will have a persistent configuration and computing the // default value every time will be a waste. So try without a default @@ -138,22 +141,37 @@ namespace build2 fail << "invalid path '" << s << "' in " << config_x; } - mode.assign (++v.begin (), v.end ()); + omode.assign (++v.begin (), v.end ()); // Save original path/mode in *.config.path/mode. // rs.assign (x_c_path) = xc; - rs.assign (x_c_mode) = mode; + rs.assign (x_c_mode) = omode; + + // Merge the configured mode options into user-specified (which must + // be done before loading the *.guess module). + // + // In particular, this ability to specify the compiler mode in a + // buildfile is useful in embedded development where the project may + // need to hardcode things like -target, -nostdinc, etc. + // + const strings& mode (cast<strings> (rs.assign (x_mode) += omode)); // Figure out which compiler we are dealing with, its target, etc. // // Note that we could allow guess() to modify mode to support // imaginary options (such as /MACHINE for cl.exe). Though it's not // clear what cc.mode would contain (original or modified). Note that - // we are now folding *.std options into mode options. + // we are now adding *.std options into mode options. + // + // @@ But can't the language standard options alter things like search + // directories? // x_info = &build2::cc::guess ( - x, x_lang, move (xc), + ctx, + x, x_lang, + rs.root_extra->environment_checksum, + move (xc), cast_null<string> (lookup_config (rs, config_x_id)), cast_null<string> (lookup_config (rs, config_x_version)), cast_null<string> (lookup_config (rs, config_x_target)), @@ -177,7 +195,8 @@ namespace build2 if (config_sub) { - ct = run<string> (3, + ct = run<string> (ctx, + 3, *config_sub, xi.target.c_str (), [] (string& l, bool) {return move (l);}); @@ -201,10 +220,24 @@ namespace build2 } } + // Hash the environment (used for change detection). + // + // Note that for simplicity we use the combined checksum for both + // compilation and linking (which may compile, think LTO). + // + { + sha256 cs; + hash_environment (cs, xi.compiler_environment); + hash_environment (cs, xi.platform_environment); + env_checksum = cs.string (); + } + // Assign values to variables that describe the compiler. // - rs.assign (x_path) = process_path_ex (xi.path, x_name, xi.checksum); - const strings& xm (cast<strings> (rs.assign (x_mode) = move (mode))); + // Note: x_mode is dealt with above. + // + rs.assign (x_path) = process_path_ex ( + xi.path, x_name, xi.checksum, env_checksum); rs.assign (x_id) = xi.id.string (); rs.assign (x_id_type) = to_string (xi.id.type); @@ -249,9 +282,9 @@ namespace build2 // if (!cc_loaded) { - // Prepare configuration hints. + // Prepare configuration hints (pretend it belongs to root scope). // - variable_map h (rs.ctx); + variable_map h (rs); // Note that all these variables have already been registered. // @@ -262,8 +295,8 @@ namespace build2 if (!xi.pattern.empty ()) h.assign ("config.cc.pattern") = xi.pattern; - if (!xm.empty ()) - h.assign ("config.cc.mode") = xm; + if (!omode.empty ()) + h.assign ("config.cc.mode") = move (omode); h.assign (c_runtime) = xi.runtime; h.assign (c_stdlib) = xi.c_stdlib; @@ -334,9 +367,22 @@ namespace build2 # ifdef __APPLE__ static const dir_path a_usr_inc ( "/Library/Developer/CommandLineTools/SDKs/MacOSX*.sdk/usr/include"); + static const dir_path a_usr_lib ( + "/Library/Developer/CommandLineTools/SDKs/MacOSX*.sdk/usr/lib"); # endif #endif + // Extracting search dirs can be expensive (we may need to run the + // compiler several times) so we cache the result. + // + struct search_dirs + { + pair<dir_paths, size_t> lib; + pair<dir_paths, size_t> hdr; + }; + + static global_cache<search_dirs> dirs_cache; + void config_module:: init (scope& rs, const location& loc, const variable_map&) { @@ -345,6 +391,20 @@ namespace build2 const compiler_info& xi (*x_info); const target_triplet& tt (cast<target_triplet> (rs[x_target])); + // Load cc.core.config. + // + if (!cast_false<bool> (rs["cc.core.config.loaded"])) + { + // Prepare configuration hints (pretend it belongs to root scope). + // + variable_map h (rs); + + if (!xi.bin_pattern.empty ()) + h.assign ("config.bin.pattern") = xi.bin_pattern; + + init_module (rs, rs, "cc.core.config", loc, false, h); + } + // Configuration. // using config::lookup_config; @@ -414,20 +474,114 @@ namespace build2 translate_std (xi, tt, rs, mode, v); } - // config.x.translatable_header + // config.x.internal.scope + // + // Note: save omitted. + // + // The effective internal_scope value is chosen based on the following + // priority list: + // + // 1. config.x.internal.scope + // + // 2. config.cc.internal.scope + // + // 3. effective value from bundle amalgamation + // + // 4. x.internal.scope + // + // 5. cc.internal.scope + // + // Note also that we only update x.internal.scope (and not cc.*) to + // reflect the effective value. + // + const string* iscope_str (nullptr); + { + if (lookup l = lookup_config (rs, config_x_internal_scope)) // 1 + { + iscope_str = &cast<string> (l); + + if (*iscope_str == "current") + fail << "'current' value in " << config_x_internal_scope; + } + else if (lookup l = rs["config.cc.internal.scope"]) // 2 + { + iscope_str = &cast<string> (l); + } + else // 3 + { + const scope& as (*rs.bundle_scope ()); + + if (as != rs) + { + // Only use the value if the corresponding module is loaded. + // + bool xl (cast_false<bool> (as[string (x) + ".config.loaded"])); + if (xl) + iscope_str = cast_null<string> (as[x_internal_scope]); + + if (iscope_str == nullptr) + { + if (xl || cast_false<bool> (as["cc.core.config.loaded"])) + iscope_str = cast_null<string> (as["cc.internal.scope"]); + } + + if (iscope_str != nullptr && *iscope_str == "current") + iscope_current = &as; + } + } + + lookup l; + if (iscope_str == nullptr) + { + iscope_str = cast_null<string> (l = rs[x_internal_scope]); // 4 + + if (iscope_str == nullptr) + iscope_str = cast_null<string> (rs["cc.internal.scope"]); // 5 + } + + if (iscope_str != nullptr) + { + const string& s (*iscope_str); + + // Assign effective. + // + if (!l) + rs.assign (x_internal_scope) = s; + + if (s == "current") + { + iscope = internal_scope::current; + + if (iscope_current == nullptr) + iscope_current = &rs; + } + else if (s == "base") iscope = internal_scope::base; + else if (s == "root") iscope = internal_scope::root; + else if (s == "bundle") iscope = internal_scope::bundle; + else if (s == "strong") iscope = internal_scope::strong; + else if (s == "weak") iscope = internal_scope::weak; + else if (s == "global") + ; // Nothing to translate; + else + fail << "invalid " << x_internal_scope << " value '" << s << "'"; + } + } + + // config.x.translate_include // // It's still fuzzy whether specifying (or maybe tweaking) this list in // the configuration will be a common thing to do so for now we use - // omitted. It's also probably too early to think whether we should have - // the cc.* version and what the semantics should be. + // omitted. // - if (x_translatable_headers != nullptr) + if (x_translate_include != nullptr) { - lookup l (lookup_config (rs, *config_x_translatable_headers)); - - // @@ MODHDR: if(modules) ? - // - rs.assign (x_translatable_headers) += cast_null<strings> (l); + if (lookup l = lookup_config (rs, *config_x_translate_include)) + { + // @@ MODHDR: if(modules) ? Yes. + // + rs.assign (x_translate_include).prepend ( + cast<translatable_headers> (l)); + } } // Extract system header/library search paths from the compiler and @@ -436,45 +590,79 @@ namespace build2 // Note that for now module search paths only come from compiler_info. // pair<dir_paths, size_t> lib_dirs; - pair<dir_paths, size_t> inc_dirs; + pair<dir_paths, size_t> hdr_dirs; const optional<pair<dir_paths, size_t>>& mod_dirs (xi.sys_mod_dirs); - if (xi.sys_lib_dirs) + if (xi.sys_lib_dirs && xi.sys_hdr_dirs) + { lib_dirs = *xi.sys_lib_dirs; + hdr_dirs = *xi.sys_hdr_dirs; + } else { - switch (xi.class_) + string key; { - case compiler_class::gcc: - lib_dirs = gcc_library_search_dirs (xi.path, rs); - break; - case compiler_class::msvc: - lib_dirs = msvc_library_search_dirs (xi.path, rs); - break; + sha256 cs; + cs.append (static_cast<size_t> (x_lang)); + cs.append (xi.path.effect_string ()); + append_options (cs, mode); + key = cs.string (); } - } - if (xi.sys_inc_dirs) - inc_dirs = *xi.sys_inc_dirs; - else - { - switch (xi.class_) + // Because the compiler info (xi) is also cached, we can assume that + // if dirs come from there, then they do so consistently. + // + const search_dirs* sd (dirs_cache.find (key)); + + if (xi.sys_lib_dirs) + lib_dirs = *xi.sys_lib_dirs; + else if (sd != nullptr) + lib_dirs = sd->lib; + else + { + switch (xi.class_) + { + case compiler_class::gcc: + lib_dirs = gcc_library_search_dirs (xi, rs); + break; + case compiler_class::msvc: + lib_dirs = msvc_library_search_dirs (xi, rs); + break; + } + } + + if (xi.sys_hdr_dirs) + hdr_dirs = *xi.sys_hdr_dirs; + else if (sd != nullptr) + hdr_dirs = sd->hdr; + else + { + switch (xi.class_) + { + case compiler_class::gcc: + hdr_dirs = gcc_header_search_dirs (xi, rs); + break; + case compiler_class::msvc: + hdr_dirs = msvc_header_search_dirs (xi, rs); + break; + } + } + + if (sd == nullptr) { - case compiler_class::gcc: - inc_dirs = gcc_header_search_dirs (xi.path, rs); - break; - case compiler_class::msvc: - inc_dirs = msvc_header_search_dirs (xi.path, rs); - break; + search_dirs sd; + if (!xi.sys_lib_dirs) sd.lib = lib_dirs; + if (!xi.sys_hdr_dirs) sd.hdr = hdr_dirs; + dirs_cache.insert (move (key), move (sd)); } } sys_lib_dirs_mode = lib_dirs.second; - sys_inc_dirs_mode = inc_dirs.second; + sys_hdr_dirs_mode = hdr_dirs.second; sys_mod_dirs_mode = mod_dirs ? mod_dirs->second : 0; - sys_lib_dirs_extra = lib_dirs.first.size (); - sys_inc_dirs_extra = inc_dirs.first.size (); + sys_lib_dirs_extra = 0; + sys_hdr_dirs_extra = 0; #ifndef _WIN32 // Add /usr/local/{include,lib}. We definitely shouldn't do this if we @@ -490,11 +678,11 @@ namespace build2 // on the next invocation. // { - auto& is (inc_dirs.first); + auto& hs (hdr_dirs.first); auto& ls (lib_dirs.first); - bool ui (find (is.begin (), is.end (), usr_inc) != is.end ()); - bool uli (find (is.begin (), is.end (), usr_loc_inc) != is.end ()); + bool ui (find (hs.begin (), hs.end (), usr_inc) != hs.end ()); + bool uli (find (hs.begin (), hs.end (), usr_loc_inc) != hs.end ()); #ifdef __APPLE__ // On Mac OS starting from 10.14 there is no longer /usr/include. @@ -517,15 +705,28 @@ namespace build2 // // Is Apple's /usr/include. // - if (!ui && !uli) + // Also, it appears neither Clang nor GCC report MacOSX*.sdk/usr/lib + // with -print-search-dirs but they do search in there. So we add it + // to our list if we see MacOSX*.sdk/usr/include. + // + auto aui (find_if (hs.begin (), hs.end (), + [] (const dir_path& d) + { + return path_match (d, a_usr_inc); + })); + + if (aui != hs.end ()) { - for (const dir_path& d: is) + if (!ui) + ui = true; + + if (find_if (ls.begin (), ls.end (), + [] (const dir_path& d) + { + return path_match (d, a_usr_lib); + }) == ls.end ()) { - if (path_match (d, a_usr_inc)) - { - ui = true; - break; - } + ls.push_back (aui->directory () /= "lib"); } } #endif @@ -533,18 +734,29 @@ namespace build2 { bool ull (find (ls.begin (), ls.end (), usr_loc_lib) != ls.end ()); - // Many platforms don't search in /usr/local/lib by default (but do - // for headers in /usr/local/include). So add it as the last option. + // Many platforms don't search in /usr/local/lib by default but do + // for headers in /usr/local/include. + // + // Note that customarily /usr/local/include is searched before + // /usr/include so we add /usr/local/lib before built-in entries + // (there isn't really a way to add it after since all we can do is + // specify it with -L). // if (!ull && exists (usr_loc_lib, true /* ignore_error */)) - ls.push_back (usr_loc_lib); + { + ls.insert (ls.begin () + sys_lib_dirs_mode, usr_loc_lib); + ++sys_lib_dirs_extra; + } // FreeBSD is at least consistent: it searches in neither. Quoting // its wiki: "FreeBSD can't even find libraries that it installed." // So let's help it a bit. // if (!uli && exists (usr_loc_inc, true /* ignore_error */)) - is.push_back (usr_loc_inc); + { + hs.insert (hs.begin () + sys_hdr_dirs_mode, usr_loc_inc); + ++sys_hdr_dirs_extra; + } } } #endif @@ -586,7 +798,7 @@ namespace build2 if (xi.variant_version) { - dr << " variant: " << '\n' + dr << " variant:" << '\n' << " version " << xi.variant_version->string << '\n' << " major " << xi.variant_version->major << '\n' << " minor " << xi.variant_version->minor << '\n' @@ -621,9 +833,19 @@ namespace build2 } auto& mods (mod_dirs ? mod_dirs->first : dir_paths ()); - auto& incs (inc_dirs.first); + auto& incs (hdr_dirs.first); auto& libs (lib_dirs.first); + if (verb >= 3 && iscope) + { + dr << "\n int scope "; + + if (*iscope == internal_scope::current) + dr << iscope_current->out_path (); + else + dr << *iscope_str; + } + if (verb >= 3 && !mods.empty ()) { dr << "\n mod dirs"; @@ -635,11 +857,14 @@ namespace build2 if (verb >= 3 && !incs.empty ()) { - dr << "\n inc dirs"; + dr << "\n hdr dirs"; for (size_t i (0); i != incs.size (); ++i) { - if (i == sys_inc_dirs_extra) + if ((sys_hdr_dirs_mode != 0 && i == sys_hdr_dirs_mode) || + (sys_hdr_dirs_extra != 0 && + i == sys_hdr_dirs_extra + sys_hdr_dirs_mode)) dr << "\n --"; + dr << "\n " << incs[i]; } } @@ -649,157 +874,150 @@ namespace build2 dr << "\n lib dirs"; for (size_t i (0); i != libs.size (); ++i) { - if (i == sys_lib_dirs_extra) + if ((sys_lib_dirs_mode != 0 && i == sys_lib_dirs_mode) || + (sys_lib_dirs_extra != 0 && + i == sys_lib_dirs_extra + sys_lib_dirs_mode)) dr << "\n --"; + dr << "\n " << libs[i]; } } } rs.assign (x_sys_lib_dirs) = move (lib_dirs.first); - rs.assign (x_sys_inc_dirs) = move (inc_dirs.first); + rs.assign (x_sys_hdr_dirs) = move (hdr_dirs.first); - // Load cc.core.config. - // - if (!cast_false<bool> (rs["cc.core.config.loaded"])) - { - variable_map h (rs.ctx); - - if (!xi.bin_pattern.empty ()) - h.assign ("config.bin.pattern") = xi.bin_pattern; - - init_module (rs, rs, "cc.core.config", loc, false, h); - } + config::save_environment (rs, xi.compiler_environment); + config::save_environment (rs, xi.platform_environment); } + // Global cache of ad hoc importable headers. + // + // The key is a hash of the system header search directories + // (sys_hdr_dirs) where we search for the headers. + // + static map<string, importable_headers> importable_headers_cache; + static mutex importable_headers_mutex; + void module:: - init (scope& rs, const location& loc, const variable_map&) + init (scope& rs, + const location& loc, + const variable_map&, + const compiler_info& xi) { tracer trace (x, "init"); + context& ctx (rs.ctx); + + // Register the module function family if this is the first instance of + // this modules. + // + if (!function_family::defined (ctx.functions, x)) + { + function_family f (ctx.functions, x); + compile_rule::functions (f, x); + link_rule::functions (f, x); + } + // Load cc.core. Besides other things, this will load bin (core) plus // extra bin.* modules we may need. // load_module (rs, rs, "cc.core", loc); - // Process, sort, and cache (in this->xlate_hdr) translatable headers. - // Keep the cache NULL if unused or empty. - // - // @@ MODHDR TODO: support exclusions entries (e.g., -<stdio.h>)? + // Search include translation headers and groups. // - if (modules && x_translatable_headers != nullptr) + if (modules) { - strings* ih (cast_null<strings> (rs.assign (x_translatable_headers))); + { + sha256 k; + for (const dir_path& d: sys_hdr_dirs) + k.append (d.string ()); + + mlock l (importable_headers_mutex); + importable_headers = &importable_headers_cache[k.string ()]; + } - if (ih != nullptr && !ih->empty ()) + auto& hs (*importable_headers); + + ulock ul (hs.mutex); + + if (hs.group_map.find (header_group_std) == hs.group_map.end ()) + guess_std_importable_headers (xi, sys_hdr_dirs, hs); + + // Process x.translate_include. + // + const variable& var (*x_translate_include); + if (auto* v = cast_null<translatable_headers> (rs[var])) { - // Translate <>-style header names to absolute paths using the - // compiler's include search paths. Otherwise complete and normalize - // since when searching in this list we always use the absolute and - // normalized header target path. - // - for (string& h: *ih) + for (const auto& p: *v) { - if (h.empty ()) - continue; + const string& k (p.first); - path f; - if (h.front () == '<' && h.back () == '>') + if (k.front () == '<' && k.back () == '>') { - h.pop_back (); - h.erase (0, 1); + if (path_pattern (k)) + { + size_t n (hs.insert_angle_pattern (sys_hdr_dirs, k)); - for (const dir_path& d: sys_inc_dirs) + l5 ([&]{trace << "pattern " << k << " searched to " << n + << " headers";}); + } + else { - if (file_exists ((f = d, f /= h), - true /* follow_symlinks */, - true /* ignore_errors */)) - goto found; + // What should we do if not found? While we can fail, this + // could be too drastic if, for example, the header is + // "optional" and may or may not be present/used. So for now + // let's ignore (we could have also removed it from the map as + // an indication). + // + const auto* r (hs.insert_angle (sys_hdr_dirs, k)); + + l5 ([&]{trace << "header " << k << " searched to " + << (r ? r->first.string ().c_str () : "<none>");}); } - - // What should we do if not found? While we can fail, this could - // be too drastic if, for example, the header is "optional" and - // may or may not be present/used. So for now let's restore the - // original form to aid debugging (it can't possibly match any - // absolute path). + } + else if (path_traits::find_separator (k) == string::npos) + { + // Group name. // - h.insert (0, 1, '<'); - h.push_back ('>'); - continue; - - found: - ; // Fall through. + if (k != header_group_all_importable && + k != header_group_std_importable && + k != header_group_all && + k != header_group_std) + fail (loc) << "unknown header group '" << k << "' in " << var; } else { - f = path (move (h)); - - if (f.relative ()) - f.complete (); + // Absolute and normalized header path. + // + if (!path_traits::absolute (k)) + fail (loc) << "relative header path '" << k << "' in " << var; } - - // @@ MODHDR: should we use the more elaborate but robust - // normalize/realize scheme so the we get the same - // path? Feels right. - f.normalize (); - h = move (f).string (); } - - sort (ih->begin (), ih->end ()); - xlate_hdr = ih; } } // Register target types and configure their "installability". // - bool install_loaded (cast_false<bool> (rs["install.loaded"])); - - { - using namespace install; - - rs.insert_target_type (x_src); - - auto insert_hdr = [&rs, install_loaded] (const target_type& tt) - { - rs.insert_target_type (tt); - - // Install headers into install.include. - // - if (install_loaded) - install_path (rs, tt, dir_path ("include")); - }; - - // Note: module (x_mod) is in x_hdr. - // - for (const target_type* const* ht (x_hdr); *ht != nullptr; ++ht) - insert_hdr (**ht); - - // Also register the C header for C-derived languages. - // - if (*x_hdr != &h::static_type) - insert_hdr (h::static_type); - - rs.insert_target_type<pc> (); - rs.insert_target_type<pca> (); - rs.insert_target_type<pcs> (); - - if (install_loaded) - install_path<pc> (rs, dir_path ("pkgconfig")); - } + load_module (rs, rs, (string (x) += ".types"), loc); // Register rules. // { using namespace bin; + // If the target doesn't support shared libraries, then don't register + // the corresponding rules. + // + bool s (tsys != "emscripten"); + auto& r (rs.rules); + const compile_rule& cr (*this); + const link_rule& lr (*this); // We register for configure so that we detect unresolved imports // during configuration rather that later, e.g., during update. // - const compile_rule& cr (*this); - const link_rule& lr (*this); - r.insert<obje> (perform_update_id, x_compile, cr); r.insert<obje> (perform_clean_id, x_compile, cr); r.insert<obje> (configure_update_id, x_compile, cr); @@ -808,9 +1026,12 @@ namespace build2 r.insert<obja> (perform_clean_id, x_compile, cr); r.insert<obja> (configure_update_id, x_compile, cr); - r.insert<objs> (perform_update_id, x_compile, cr); - r.insert<objs> (perform_clean_id, x_compile, cr); - r.insert<objs> (configure_update_id, x_compile, cr); + if (s) + { + r.insert<objs> (perform_update_id, x_compile, cr); + r.insert<objs> (perform_clean_id, x_compile, cr); + r.insert<objs> (configure_update_id, x_compile, cr); + } if (modules) { @@ -830,13 +1051,16 @@ namespace build2 r.insert<hbmia> (perform_clean_id, x_compile, cr); r.insert<hbmia> (configure_update_id, x_compile, cr); - r.insert<bmis> (perform_update_id, x_compile, cr); - r.insert<bmis> (perform_clean_id, x_compile, cr); - r.insert<bmis> (configure_update_id, x_compile, cr); + if (s) + { + r.insert<bmis> (perform_update_id, x_compile, cr); + r.insert<bmis> (perform_clean_id, x_compile, cr); + r.insert<bmis> (configure_update_id, x_compile, cr); - r.insert<hbmis> (perform_update_id, x_compile, cr); - r.insert<hbmis> (perform_clean_id, x_compile, cr); - r.insert<hbmis> (configure_update_id, x_compile, cr); + r.insert<hbmis> (perform_update_id, x_compile, cr); + r.insert<hbmis> (perform_clean_id, x_compile, cr); + r.insert<hbmis> (configure_update_id, x_compile, cr); + } } r.insert<libue> (perform_update_id, x_link, lr); @@ -847,9 +1071,12 @@ namespace build2 r.insert<libua> (perform_clean_id, x_link, lr); r.insert<libua> (configure_update_id, x_link, lr); - r.insert<libus> (perform_update_id, x_link, lr); - r.insert<libus> (perform_clean_id, x_link, lr); - r.insert<libus> (configure_update_id, x_link, lr); + if (s) + { + r.insert<libus> (perform_update_id, x_link, lr); + r.insert<libus> (perform_clean_id, x_link, lr); + r.insert<libus> (configure_update_id, x_link, lr); + } r.insert<exe> (perform_update_id, x_link, lr); r.insert<exe> (perform_clean_id, x_link, lr); @@ -859,37 +1086,49 @@ namespace build2 r.insert<liba> (perform_clean_id, x_link, lr); r.insert<liba> (configure_update_id, x_link, lr); - r.insert<libs> (perform_update_id, x_link, lr); - r.insert<libs> (perform_clean_id, x_link, lr); - r.insert<libs> (configure_update_id, x_link, lr); + if (s) + { + r.insert<libs> (perform_update_id, x_link, lr); + r.insert<libs> (perform_clean_id, x_link, lr); + r.insert<libs> (configure_update_id, x_link, lr); + } // Note that while libu*{} are not installable, we need to see through // them in case they depend on stuff that we need to install (see the // install rule implementations for details). // - if (install_loaded) + if (cast_false<bool> (rs["install.loaded"])) { + // Note: we rely quite heavily in these rule implementations that + // these are the only target types they are registered for. + const install_rule& ir (*this); - r.insert<exe> (perform_install_id, x_install, ir); - r.insert<exe> (perform_uninstall_id, x_uninstall, ir); + r.insert<exe> (perform_install_id, x_install, ir); + r.insert<exe> (perform_uninstall_id, x_install, ir); - r.insert<liba> (perform_install_id, x_install, ir); - r.insert<liba> (perform_uninstall_id, x_uninstall, ir); + r.insert<liba> (perform_install_id, x_install, ir); + r.insert<liba> (perform_uninstall_id, x_install, ir); - r.insert<libs> (perform_install_id, x_install, ir); - r.insert<libs> (perform_uninstall_id, x_uninstall, ir); + if (s) + { + r.insert<libs> (perform_install_id, x_install, ir); + r.insert<libs> (perform_uninstall_id, x_install, ir); + } const libux_install_rule& lr (*this); - r.insert<libue> (perform_install_id, x_install, lr); - r.insert<libue> (perform_uninstall_id, x_uninstall, lr); + r.insert<libue> (perform_install_id, x_install, lr); + r.insert<libue> (perform_uninstall_id, x_install, lr); - r.insert<libua> (perform_install_id, x_install, lr); - r.insert<libua> (perform_uninstall_id, x_uninstall, lr); + r.insert<libua> (perform_install_id, x_install, lr); + r.insert<libua> (perform_uninstall_id, x_install, lr); - r.insert<libus> (perform_install_id, x_install, lr); - r.insert<libus> (perform_uninstall_id, x_uninstall, lr); + if (s) + { + r.insert<libus> (perform_install_id, x_install, lr); + r.insert<libus> (perform_uninstall_id, x_install, lr); + } } } } |