From 4bdf53837e010073de802070d4e6087410662d3e Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Sat, 24 Aug 2019 17:41:30 +0300 Subject: Move cc build system module to separate library --- build2/cc/module.cxx | 781 --------------------------------------------------- 1 file changed, 781 deletions(-) delete mode 100644 build2/cc/module.cxx (limited to 'build2/cc/module.cxx') diff --git a/build2/cc/module.cxx b/build2/cc/module.cxx deleted file mode 100644 index 478cabe..0000000 --- a/build2/cc/module.cxx +++ /dev/null @@ -1,781 +0,0 @@ -// file : build2/cc/module.cxx -*- C++ -*- -// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd -// license : MIT; see accompanying LICENSE file - -#include - -#include // left, setw() - -#include -#include - -#include - -#include // pc* - -#include -#include - -#include - -using namespace std; -using namespace butl; - -namespace build2 -{ - namespace cc - { - void config_module:: - guess (scope& rs, const location& loc, const variable_map&) - { - tracer trace (x, "guess_init"); - - bool cc_loaded (cast_false (rs["cc.core.guess.loaded"])); - - // Adjust module priority (compiler). Also order cc module before us - // (we don't want to use priorities for that in case someone manages - // to slot in-between). - // - if (!cc_loaded) - config::save_module (rs, "cc", 250); - - config::save_module (rs, x, 250); - - auto& vp (rs.ctx.var_pool.rw (rs)); - - // Must already exist. - // - const variable& config_c_poptions (vp["config.cc.poptions"]); - const variable& config_c_coptions (vp["config.cc.coptions"]); - const variable& config_c_loptions (vp["config.cc.loptions"]); - - // config.x - // - - // Normally we will have a persistent configuration and computing the - // default value every time will be a waste. So try without a default - // first. - // - auto p (config::omitted (rs, config_x)); - - if (!p.first) - { - // If there is a config.x value for one of the modules that can hint - // us the toolchain, load it's .guess module. This makes sure that the - // order in which we load the modules is unimportant and that the user - // can specify the toolchain using any of the config.x values. - // - if (!cc_loaded) - { - for (const char* const* pm (x_hinters); *pm != nullptr; ++pm) - { - string m (*pm); - - // Must be the same as in module's init(). - // - const variable& v (vp.insert ("config." + m, true)); - - if (rs[v].defined ()) - { - load_module (rs, rs, m + ".guess", loc); - cc_loaded = true; - break; - } - } - } - - // If cc.core.config is already loaded then use its toolchain id and - // (optional) pattern to guess an appropriate default (e.g., for {gcc, - // *-4.9} we will get g++-4.9). - // - path d; - - if (cc_loaded) - d = guess_default (x_lang, - cast (rs["cc.id"]), - cast (rs["cc.pattern"])); - else - { - d = path (x_default); - - if (d.empty ()) - fail << "not built with default " << x_lang << " compiler" << - info << "use config." << x << " to specify"; - } - - // If this value was hinted, save it as commented out so that if the - // user changes the source of the pattern, this one will get updated - // as well. - // - p = config::required (rs, - config_x, - d, - false, - cc_loaded ? config::save_commented : 0); - } - - // Figure out which compiler we are dealing with, its target, etc. - // - ci_ = &build2::cc::guess ( - x, - x_lang, - cast (*p.first), - cast_null (config::omitted (rs, config_x_id).first), - cast_null (config::omitted (rs, config_x_version).first), - cast_null (config::omitted (rs, config_x_target).first), - cast_null (rs[config_c_poptions]), - cast_null (rs[config_x_poptions]), - cast_null (rs[config_c_coptions]), - cast_null (rs[config_x_coptions]), - cast_null (rs[config_c_loptions]), - cast_null (rs[config_x_loptions])); - - const compiler_info& ci (*ci_); - - // Split/canonicalize the target. First see if the user asked us to - // use config.sub. - // - target_triplet tt; - { - string ct; - - if (config_sub) - { - ct = run (3, - *config_sub, - ci.target.c_str (), - [] (string& l, bool) {return move (l);}); - l5 ([&]{trace << "config.sub target: '" << ct << "'";}); - } - - try - { - tt = target_triplet (ct.empty () ? ci.target : ct); - l5 ([&]{trace << "canonical target: '" << tt.string () << "'; " - << "class: " << tt.class_;}); - } - catch (const invalid_argument& e) - { - // This is where we suggest that the user specifies --config-sub to - // help us out. - // - fail << "unable to parse " << x_lang << " compiler target '" - << ci.target << "': " << e << - info << "consider using the --config-sub option"; - } - } - - // Assign values to variables that describe the compiler. - // - rs.assign (x_id) = ci.id.string (); - rs.assign (x_id_type) = to_string (ci.id.type); - rs.assign (x_id_variant) = ci.id.variant; - - rs.assign (x_class) = to_string (ci.class_); - - rs.assign (x_version) = ci.version.string; - rs.assign (x_version_major) = ci.version.major; - rs.assign (x_version_minor) = ci.version.minor; - rs.assign (x_version_patch) = ci.version.patch; - rs.assign (x_version_build) = ci.version.build; - - // Also enter as x.target.{cpu,vendor,system,version,class} for - // convenience of access. - // - rs.assign (x_target_cpu) = tt.cpu; - rs.assign (x_target_vendor) = tt.vendor; - rs.assign (x_target_system) = tt.system; - rs.assign (x_target_version) = tt.version; - rs.assign (x_target_class) = tt.class_; - - rs.assign (x_target) = move (tt); - - rs.assign (x_pattern) = ci.pattern; - - if (!x_stdlib.alias (c_stdlib)) - rs.assign (x_stdlib) = ci.x_stdlib; - - new_ = p.second; - - // Load cc.core.guess. - // - if (!cc_loaded) - { - // Prepare configuration hints. - // - variable_map h (rs.ctx); - - // Note that all these variables have already been registered. - // - h.assign ("config.cc.id") = cast (rs[x_id]); - h.assign ("config.cc.hinter") = string (x); - h.assign ("config.cc.target") = cast (rs[x_target]); - - if (!ci.pattern.empty ()) - h.assign ("config.cc.pattern") = ci.pattern; - - h.assign (c_runtime) = ci.runtime; - h.assign (c_stdlib) = ci.c_stdlib; - - load_module (rs, rs, "cc.core.guess", loc, false, h); - } - else - { - // If cc.core.guess is already loaded, verify its configuration - // matched ours since it could have been loaded by another c-family - // module. - // - const auto& h (cast (rs["cc.hinter"])); - - auto check = [&loc, &h, this] (const auto& cv, - const auto& xv, - const char* what, - bool error = true) - { - if (cv != xv) - { - diag_record dr (error ? fail (loc) : warn (loc)); - - dr << h << " and " << x << " module " << what << " mismatch" << - info << h << " is '" << cv << "'" << - info << x << " is '" << xv << "'" << - info << "consider explicitly specifying config." << h - << " and config." << x; - } - }; - - check (cast (rs["cc.id"]), - cast (rs[x_id]), - "toolchain"); - - // We used to not require that patterns match assuming that if the - // toolchain id and target are the same, then where exactly the tools - // come from doesn't really matter. But in most cases it will be the - // g++-7 vs gcc kind of mistakes. So now we warn since even if - // intentional, it is still probably a bad idea. - // - check (cast (rs["cc.pattern"]), - cast (rs[x_pattern]), - "toolchain pattern", - false); - - check (cast (rs["cc.target"]), - cast (rs[x_target]), - "target"); - - check (cast (rs["cc.runtime"]), - ci.runtime, - "runtime"); - - check (cast (rs["cc.stdlib"]), - ci.c_stdlib, - "c standard library"); - } - } - -#ifndef _WIN32 - static const dir_path usr_inc ("/usr/include"); - static const dir_path usr_loc_lib ("/usr/local/lib"); - static const dir_path usr_loc_inc ("/usr/local/include"); -# ifdef __APPLE__ - static const dir_path a_usr_inc ( - "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include"); -# endif -#endif - - void config_module:: - init (scope& rs, const location& loc, const variable_map&) - { - tracer trace (x, "config_init"); - - const compiler_info& ci (*ci_); - const target_triplet& tt (cast (rs[x_target])); - - // config.x.std overrides x.std - // - { - lookup l (config::omitted (rs, config_x_std).first); - - const string* v; - if (l.defined ()) - { - v = cast_null (l); - rs.assign (x_std) = v; - } - else - v = cast_null (rs[x_std]); - - // Translate x_std value (if any) to the compiler option(s) (if any). - // - tstd = translate_std (ci, rs, v); - } - - // Extract system header/library search paths from the compiler and - // determine if we need any additional search paths. - // - dir_paths lib_dirs; - dir_paths inc_dirs; - - switch (ci.class_) - { - case compiler_class::gcc: - { - lib_dirs = gcc_library_search_paths (ci.path, rs); - inc_dirs = gcc_header_search_paths (ci.path, rs); - break; - } - case compiler_class::msvc: - { - lib_dirs = msvc_library_search_paths (ci.path, rs); - inc_dirs = msvc_header_search_paths (ci.path, rs); - break; - } - } - - sys_lib_dirs_extra = lib_dirs.size (); - sys_inc_dirs_extra = inc_dirs.size (); - -#ifndef _WIN32 - // Add /usr/local/{include,lib}. We definitely shouldn't do this if we - // are cross-compiling. But even if the build and target are the same, - // it's possible the compiler uses some carefully crafted sysroot and by - // adding /usr/local/* we will just mess things up. So the heuristics - // that we will use is this: if the compiler's system include directories - // contain /usr[/local]/include then we add /usr/local/*. - // - // Note that similar to GCC we also check for the directory existence. - // Failed that, we can end up with some bizarre yo-yo'ing cases where - // uninstall removes the directories which in turn triggers a rebuild - // on the next invocation. - // - { - auto& is (inc_dirs); - auto& ls (lib_dirs); - - bool ui (find (is.begin (), is.end (), usr_inc) != is.end ()); - bool uli (find (is.begin (), is.end (), usr_loc_inc) != is.end ()); - -#ifdef __APPLE__ - // On Mac OS starting from 10.14 there is no longer /usr/include. - // Instead we get the following: - // - // Homebrew GCC 9: - // - // /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include - // - // Apple Clang 10.0.1: - // - // /Library/Developer/CommandLineTools/usr/include - // /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include - // - // What exactly all this means is anyone's guess, of course. So for - // now we will assume that anything that is or resolves (like that - // MacOSX10.14.sdk symlink) to: - // - // /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include - // - // Is Apple's /usr/include. - // - if (!ui && !uli) - { - for (const dir_path& d: inc_dirs) - { - // Both Clang and GCC skip non-existent paths but let's handle - // (and ignore) directories that cause any errors, for good - // measure. - // - try - { - if (d == a_usr_inc || dir_path (d).realize () == a_usr_inc) - { - ui = true; - break; - } - } - catch (...) {} - } - } -#endif - if (ui || uli) - { - 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. - // - if (!ull && exists (usr_loc_lib, true /* ignore_error */)) - ls.push_back (usr_loc_lib); - - // 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); - } - } -#endif - - // If this is a new value (e.g., we are configuring), then print the - // report at verbosity level 2 and up (-v). - // - if (verb >= (new_ ? 2 : 3)) - { - diag_record dr (text); - - { - dr << x << ' ' << project (rs) << '@' << rs << '\n' - << " " << left << setw (11) << x << ci.path << '\n' - << " id " << ci.id << '\n' - << " version " << ci.version.string << '\n' - << " major " << ci.version.major << '\n' - << " minor " << ci.version.minor << '\n' - << " patch " << ci.version.patch << '\n'; - } - - if (!ci.version.build.empty ()) - { - dr << " build " << ci.version.build << '\n'; - } - - { - const string& ct (tt.string ()); // Canonical target. - - dr << " signature " << ci.signature << '\n' - << " checksum " << ci.checksum << '\n' - << " target " << ct; - - if (ct != ci.original_target) - dr << " (" << ci.original_target << ")"; - - dr << "\n runtime " << ci.runtime - << "\n stdlib " << ci.x_stdlib; - - if (!x_stdlib.alias (c_stdlib)) - dr << "\n c stdlib " << ci.c_stdlib; - } - - if (!tstd.empty ()) - { - dr << "\n std "; // One less space. - for (const string& o: tstd) dr << ' ' << o; - } - - if (!ci.pattern.empty ()) // Note: bin_pattern printed by bin - { - dr << "\n pattern " << ci.pattern; - } - - if (verb >= 3 && !inc_dirs.empty ()) - { - dr << "\n inc dirs"; - for (size_t i (0); i != inc_dirs.size (); ++i) - { - if (i == sys_inc_dirs_extra) - dr << "\n --"; - dr << "\n " << inc_dirs[i]; - } - } - - if (verb >= 3 && !lib_dirs.empty ()) - { - dr << "\n lib dirs"; - for (size_t i (0); i != lib_dirs.size (); ++i) - { - if (i == sys_lib_dirs_extra) - dr << "\n --"; - dr << "\n " << lib_dirs[i]; - } - } - } - - rs.assign (x_path) = process_path (ci.path, false /* init */); - rs.assign (x_sys_lib_dirs) = move (lib_dirs); - rs.assign (x_sys_inc_dirs) = move (inc_dirs); - - rs.assign (x_signature) = ci.signature; - rs.assign (x_checksum) = ci.checksum; - - // config.x.{p,c,l}options - // config.x.libs - // - // These are optional. We also merge them into the corresponding - // x.* variables. - // - // The merging part gets a bit tricky if this module has already - // been loaded in one of the outer scopes. By doing the straight - // append we would just be repeating the same options over and - // over. So what we are going to do is only append to a value if - // it came from this scope. Then the usage for merging becomes: - // - // x.coptions = # Note: '='. - // using x - // x.coptions += # Note: '+='. - // - rs.assign (x_poptions) += cast_null ( - config::optional (rs, config_x_poptions)); - - rs.assign (x_coptions) += cast_null ( - config::optional (rs, config_x_coptions)); - - rs.assign (x_loptions) += cast_null ( - config::optional (rs, config_x_loptions)); - - rs.assign (x_aoptions) += cast_null ( - config::optional (rs, config_x_aoptions)); - - rs.assign (x_libs) += cast_null ( - config::optional (rs, config_x_libs)); - - // config.x.importable_header - // - // 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. - // - if (x_importable_headers != nullptr) - { - lookup l (config::omitted (rs, *config_x_importable_headers).first); - - // @@ MODHDR: if(modules) ? - // - rs.assign (x_importable_headers) += cast_null (l); - } - - // Load cc.core.config. - // - if (!cast_false (rs["cc.core.config.loaded"])) - { - variable_map h (rs.ctx); - - if (!ci.bin_pattern.empty ()) - h.assign ("config.bin.pattern") = ci.bin_pattern; - - load_module (rs, rs, "cc.core.config", loc, false, h); - } - } - - void module:: - init (scope& rs, const location& loc, const variable_map&) - { - tracer trace (x, "init"); - - // Load cc.core. Besides other things, this will load bin (core) plus - // extra bin.* modules we may need. - // - if (!cast_false (rs["cc.core.loaded"])) - load_module (rs, rs, "cc.core", loc); - - // Process, sort, and cache (in this->import_hdr) importable headers. - // Keep the cache NULL if unused or empty. - // - // @@ MODHDR TODO: support exclusions entries (e.g., -)? - // - if (modules && x_importable_headers != nullptr) - { - strings* ih (cast_null (rs.assign (x_importable_headers))); - - if (ih != nullptr && !ih->empty ()) - { - // 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) - { - if (h.empty ()) - continue; - - path f; - if (h.front () == '<' && h.back () == '>') - { - h.pop_back (); - h.erase (0, 1); - - for (const dir_path& d: sys_inc_dirs) - { - 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 restore the - // original form to aid debugging (it can't possibly match any - // absolute path). - // - h.insert (0, 1, '<'); - h.push_back ('>'); - continue; - - found: - ; // Fall through. - } - else - { - f = path (move (h)); - - if (f.relative ()) - f.complete (); - } - - // @@ 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 ()); - import_hdr = ih; - } - } - - // Register target types and configure their "installability". - // - bool install_loaded (cast_false (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 (); - rs.insert_target_type (); - - if (install_loaded) - install_path (rs, dir_path ("pkgconfig")); - } - - // Register rules. - // - { - using namespace bin; - - auto& r (rs.rules); - - // 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 (perform_update_id, x_compile, cr); - r.insert (perform_clean_id, x_compile, cr); - r.insert (configure_update_id, x_compile, cr); - - r.insert (perform_update_id, x_compile, cr); - r.insert (perform_clean_id, x_compile, cr); - r.insert (configure_update_id, x_compile, cr); - - r.insert (perform_update_id, x_compile, cr); - r.insert (perform_clean_id, x_compile, cr); - r.insert (configure_update_id, x_compile, cr); - - if (modules) - { - r.insert (perform_update_id, x_compile, cr); - r.insert (perform_clean_id, x_compile, cr); - r.insert (configure_update_id, x_compile, cr); - - r.insert (perform_update_id, x_compile, cr); - r.insert (perform_clean_id, x_compile, cr); - r.insert (configure_update_id, x_compile, cr); - - r.insert (perform_update_id, x_compile, cr); - r.insert (perform_clean_id, x_compile, cr); - r.insert (configure_update_id, x_compile, cr); - - r.insert (perform_update_id, x_compile, cr); - r.insert (perform_clean_id, x_compile, cr); - r.insert (configure_update_id, x_compile, cr); - - r.insert (perform_update_id, x_compile, cr); - r.insert (perform_clean_id, x_compile, cr); - r.insert (configure_update_id, x_compile, cr); - - r.insert (perform_update_id, x_compile, cr); - r.insert (perform_clean_id, x_compile, cr); - r.insert (configure_update_id, x_compile, cr); - } - - r.insert (perform_update_id, x_link, lr); - r.insert (perform_clean_id, x_link, lr); - r.insert (configure_update_id, x_link, lr); - - r.insert (perform_update_id, x_link, lr); - r.insert (perform_clean_id, x_link, lr); - r.insert (configure_update_id, x_link, lr); - - r.insert (perform_update_id, x_link, lr); - r.insert (perform_clean_id, x_link, lr); - r.insert (configure_update_id, x_link, lr); - - r.insert (perform_update_id, x_link, lr); - r.insert (perform_clean_id, x_link, lr); - r.insert (configure_update_id, x_link, lr); - - r.insert (perform_update_id, x_link, lr); - r.insert (perform_clean_id, x_link, lr); - r.insert (configure_update_id, x_link, lr); - - r.insert (perform_update_id, x_link, lr); - r.insert (perform_clean_id, x_link, lr); - r.insert (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) - { - const install_rule& ir (*this); - - r.insert (perform_install_id, x_install, ir); - r.insert (perform_uninstall_id, x_uninstall, ir); - - r.insert (perform_install_id, x_install, ir); - r.insert (perform_uninstall_id, x_uninstall, ir); - - r.insert (perform_install_id, x_install, ir); - r.insert (perform_uninstall_id, x_uninstall, ir); - - const libux_install_rule& lr (*this); - - r.insert (perform_install_id, x_install, lr); - r.insert (perform_uninstall_id, x_uninstall, lr); - - r.insert (perform_install_id, x_install, lr); - r.insert (perform_uninstall_id, x_uninstall, lr); - - r.insert (perform_install_id, x_install, lr); - r.insert (perform_uninstall_id, x_uninstall, lr); - } - } - } - } -} -- cgit v1.1