// file : build2/cxx/module.cxx -*- C++ -*- // copyright : Copyright (c) 2014-2016 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace butl; namespace build2 { namespace cxx { extern "C" bool cxx_init (scope& r, scope& b, const location& loc, unique_ptr&, bool first, bool) { tracer trace ("cxx::init"); l5 ([&]{trace << "for " << b.out_path ();}); // Initialize the bin module. Only do this if it hasn't already // been loaded so that we don't overwrite user's bin.* settings. // { auto l (b["bin.loaded"]); if (!l || !as (*l)) load_module (false, "bin", r, b, loc); } // Enter module variables. // // @@ Probably should only be done on load; make sure reset() unloads // modules. // // @@ Should probably cache the variable pointers so we don't have // to keep looking them up. // if (first) { auto& v (var_pool); v.find ("config.cxx", string_type); //@@ VAR type v.find ("config.cxx.poptions", strings_type); v.find ("config.cxx.coptions", strings_type); v.find ("config.cxx.loptions", strings_type); v.find ("config.cxx.libs", strings_type); v.find ("cxx.poptions", strings_type); v.find ("cxx.coptions", strings_type); v.find ("cxx.loptions", strings_type); v.find ("cxx.libs", strings_type); v.find ("cxx.export.poptions", strings_type); v.find ("cxx.export.coptions", strings_type); v.find ("cxx.export.loptions", strings_type); v.find ("cxx.export.libs", strings_type); v.find ("cxx.std", string_type); } // Register target types. // { auto& t (b.target_types); t.insert (); t.insert (); t.insert (); t.insert (); t.insert (); t.insert (); } // Register rules. // { using namespace bin; auto& r (b.rules); r.insert (perform_update_id, "cxx.compile", compile::instance); r.insert (perform_update_id, "cxx.compile", compile::instance); r.insert (perform_clean_id, "cxx.compile", compile::instance); r.insert (perform_update_id, "cxx.compile", compile::instance); r.insert (perform_clean_id, "cxx.compile", compile::instance); r.insert (perform_update_id, "cxx.link", link::instance); r.insert (perform_clean_id, "cxx.link", link::instance); r.insert (perform_update_id, "cxx.link", link::instance); r.insert (perform_clean_id, "cxx.link", link::instance); r.insert (perform_update_id, "cxx.link", link::instance); r.insert (perform_clean_id, "cxx.link", link::instance); // Register for configure so that we detect unresolved imports // during configuration rather that later, e.g., during update. // r.insert (configure_update_id, "cxx.compile", compile::instance); r.insert (configure_update_id, "cxx.compile", compile::instance); r.insert (configure_update_id, "cxx.link", link::instance); r.insert (configure_update_id, "cxx.link", link::instance); r.insert (configure_update_id, "cxx.link", link::instance); //@@ Should we check if install module was loaded (see bin)? // r.insert (perform_install_id, "cxx.install", install::instance); r.insert (perform_install_id, "cxx.install", install::instance); r.insert (perform_install_id, "cxx.install", install::instance); } // Configure. // // config.cxx.{p,c,l}options // config.cxx.libs // // These are optional. We also merge them into the corresponding // cxx.* 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: // // cxx.coptions = # Note: '='. // using cxx // cxx.coptions += # Note: '+='. // if (const value& v = config::optional (r, "config.cxx.poptions")) b.assign ("cxx.poptions") += as (v); if (const value& v = config::optional (r, "config.cxx.coptions")) b.assign ("cxx.coptions") += as (v); if (const value& v = config::optional (r, "config.cxx.loptions")) b.assign ("cxx.loptions") += as (v); if (const value& v = config::optional (r, "config.cxx.libs")) b.assign ("cxx.libs") += as (v); // config.cxx // if (first) { auto p (config::required (r, "config.cxx", "g++")); // Figure out which compiler we are dealing with, its target, etc. // const path& cxx (path (as (p.first))); // @@ VAR compiler_info ci (guess (cxx, r["cxx.coptions"])); // 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)) { //@@ Print project out root or name? Don't print if unnamed? text << cxx << ":\n" << " id " << ci.id << "\n" << " major " << ci.version.major << "\n" << " minor " << ci.version.minor << "\n" << " patch " << ci.version.patch << "\n" << " build " << ci.version.build << "\n" << " signature " << ci.signature << "\n" << " checksum " << ci.checksum << "\n" << " target " << ci.target << ""; } r.assign ("cxx.id", string_type) = ci.id.string (); r.assign ("cxx.id.type", string_type) = move (ci.id.type); r.assign ("cxx.id.variant", string_type) = move (ci.id.variant); r.assign ("cxx.version", string_type) = ci.version.string (); r.assign ("cxx.version.major", string_type) = move (ci.version.major); r.assign ("cxx.version.minor", string_type) = move (ci.version.minor); r.assign ("cxx.version.patch", string_type) = move (ci.version.patch); r.assign ("cxx.version.build", string_type) = move (ci.version.build); r.assign ("cxx.signature", string_type) = move (ci.signature); r.assign ("cxx.checksum", string_type) = move (ci.checksum); // Split/canonicalize the target. // try { string canon; triplet t (ci.target, canon); l5 ([&]{trace << "canonical target: '" << canon << "'; " << "class: " << t.class_;}); // Enter as cxx.target.{cpu,vendor,system,version,class}. // r.assign ("cxx.target", string_type) = move (canon); r.assign ("cxx.target.cpu", string_type) = move (t.cpu); r.assign ("cxx.target.vendor", string_type) = move (t.vendor); r.assign ("cxx.target.system", string_type) = move (t.system); r.assign ("cxx.target.version", string_type) = move (t.version); r.assign ("cxx.target.class", string_type) = move (t.class_); } catch (const invalid_argument& e) { // This is where we could suggest that the user specifies // --config-sub to help us out. // fail << "unable to parse compiler target '" << ci.target << "': " << e.what (); } } // Configure "installability" of our target types. // { using build2::install::path; path (b, dir_path ("include")); // Install into install.include. path (b, dir_path ("include")); path (b, dir_path ("include")); path (b, dir_path ("include")); } return true; } } }