// file : build2/cc/init.cxx -*- C++ -*- // copyright : Copyright (c) 2014-2016 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file #include #include #include #include #include #include #include using namespace std; using namespace butl; namespace build2 { namespace cc { bool vars_init (scope& r, scope&, const location&, unique_ptr&, bool first, bool, const variable_map&) { tracer trace ("cc::vars_init"); l5 ([&]{trace << "for " << r.out_path ();}); assert (first); // Enter variables. Note: some overridable, some not. // auto& v (var_pool); v.insert ("config.cc.poptions", true); v.insert ("config.cc.coptions", true); v.insert ("config.cc.loptions", true); v.insert ("config.cc.libs", true); v.insert ("cc.poptions"); v.insert ("cc.coptions"); v.insert ("cc.loptions"); v.insert ("cc.libs"); v.insert ("cc.export.poptions"); v.insert ("cc.export.coptions"); v.insert ("cc.export.loptions"); v.insert ("cc.export.libs"); // Hint variables (not overridable). // v.insert ("config.cc.id"); v.insert ("config.cc.target"); v.insert ("config.cc.pattern"); return true; } bool config_init (scope& r, scope& b, const location& loc, unique_ptr&, bool first, bool, const variable_map& hints) { tracer trace ("cc::config_init"); l5 ([&]{trace << "for " << b.out_path ();}); // Load cc.vars. // if (first) { if (!cast_false (b["cc.vars.loaded"])) load_module ("cc.vars", r, b, loc); } // Configure. // if (first) { // config.cc.id // { // This value must be hinted. // r.assign ("cc.id") = cast (hints["config.cc.id"]); } // config.cc.target // { // This value must be hinted and already canonicalized. // const string& s (cast (hints["config.cc.target"])); try { //@@ We do it in the hinting module and here. Any way not to // duplicate the effort? Maybe move the splitting here and // simply duplicate the values there? // triplet t (s); // Enter as cc.target.{cpu,vendor,system,version,class}. // r.assign ("cc.target") = s; r.assign ("cc.target.cpu") = move (t.cpu); r.assign ("cc.target.vendor") = move (t.vendor); r.assign ("cc.target.system") = move (t.system); r.assign ("cc.target.version") = move (t.version); r.assign ("cc.target.class") = move (t.class_); } catch (const invalid_argument& e) { assert (false); // Should have been caught by the hinting module. } } // config.cc.pattern // { // This value could be hinted. // if (auto l = hints["config.cc.pattern"]) r.assign ("cc.pattern") = cast (l); } // Note that we are not having a config report since it will just // duplicate what has already been printed by the hinting module. } // config.cc.{p,c,l}options // config.cc.libs // // @@ Same nonsense as in module. // // b.assign ("cc.poptions") += cast_null ( config::optional (r, "config.cc.poptions")); b.assign ("cc.coptions") += cast_null ( config::optional (r, "config.cc.coptions")); b.assign ("cc.loptions") += cast_null ( config::optional (r, "config.cc.loptions")); b.assign ("cc.libs") += cast_null ( config::optional (r, "config.cc.libs")); // Load the bin.config module. // if (!cast_false (b["bin.config.loaded"])) { // Prepare configuration hints. They are only used on the first load // of bin.config so we only populate them on our first load. // variable_map h; if (first) { h.assign ("config.bin.target") = cast (r["cc.target"]); if (auto l = r["cc.pattern"]) h.assign ("config.bin.pattern") = cast (l); } load_module ("bin.config", r, b, loc, false, h); } // Verify bin's target matches ours (we do it even if we loaded it // ourselves since the target can come from the configuration and not // our hint). // if (first) { const string& ct (cast (r["cc.target"])); const string& bt (cast (r["bin.target"])); if (bt != ct) fail (loc) << "cc and bin module target mismatch" << info << "cc.target is " << ct << info << "bin.target is " << bt; } const string& cid (cast (r["cc.id"])); const string& tsys (cast (r["cc.target.system"])); // Load bin.*.config for bin.* modules we may need (see core_init() // below). // if (auto l = r["config.bin.lib"]) { if (cast (l) != "shared") { if (!cast_false (b["bin.ar.config.loaded"])) load_module ("bin.ar.config", r, b, loc); } } if (cid == "msvc") { if (!cast_false (b["bin.ld.config.loaded"])) load_module ("bin.ld.config", r, b, loc); } if (tsys == "mingw32") { if (!cast_false (b["bin.rc.config.loaded"])) load_module ("bin.rc.config", r, b, loc); } return true; } bool core_init (scope& r, scope& b, const location& loc, unique_ptr&, bool, bool, const variable_map& hints) { tracer trace ("cc::core_init"); l5 ([&]{trace << "for " << b.out_path ();}); // Load cc.config. // if (!cast_false (b["cc.config.loaded"])) load_module ("cc.config", r, b, loc, false, hints); // Load the bin module. // if (!cast_false (b["bin.loaded"])) load_module ("bin", r, b, loc); const string& cid (cast (r["cc.id"])); const string& tsys (cast (r["cc.target.system"])); // Load the bin.ar module unless we were asked to only build shared // libraries. // if (auto l = r["config.bin.lib"]) { if (cast (l) != "shared") { if (!cast_false (b["bin.ar.loaded"])) load_module ("bin.ar", r, b, loc); } } // In the VC world you link things directly with link.exe so load the // bin.ld module. // if (cid == "msvc") { if (!cast_false (b["bin.ld.loaded"])) load_module ("bin.ld", r, b, loc); } // If our target is MinGW, then we will need the resource compiler // (windres) in order to embed manifests into executables. // if (tsys == "mingw32") { if (!cast_false (b["bin.rc.loaded"])) load_module ("bin.rc", r, b, loc); } return true; } bool init (scope& r, scope& b, const location& loc, unique_ptr&, bool, bool, const variable_map&) { tracer trace ("cc::init"); l5 ([&]{trace << "for " << b.out_path ();}); // This module is an "alias" for c.config and cxx.config. Its intended // use is to make sure that the C/C++ configuration is captured in an // amalgamation rather than subprojects. // // We want to order the loading to match what user specified on the // command line (config.c or config.cxx). This way the first loaded // module (with user-specified config.*) will hint the compiler to the // second. // bool lc (!cast_false (b["c.config.loaded"])); bool lp (!cast_false (b["cxx.config.loaded"])); // If none of them are already loaded, load c first only if config.c // is specified. // if (lc && lp && r["config.c"]) { load_module ("c.config", r, b, loc); load_module ("cxx.config", r, b, loc); } else { if (lp) load_module ("cxx.config", r, b, loc); if (lc) load_module ("c.config", r, b, loc); } return true; } } }