From 9fa5f73d00905568e8979d0c93ec4a8f645c81d5 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 9 Aug 2016 11:31:53 +0200 Subject: Implement support for C compilation We now have two new modules: cc (c-common) and c. --- build2/cc/init.cxx | 321 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 321 insertions(+) create mode 100644 build2/cc/init.cxx (limited to 'build2/cc/init.cxx') diff --git a/build2/cc/init.cxx b/build2/cc/init.cxx new file mode 100644 index 0000000..2623c79 --- /dev/null +++ b/build2/cc/init.cxx @@ -0,0 +1,321 @@ +// 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; + } + } +} -- cgit v1.1