aboutsummaryrefslogtreecommitdiff
path: root/build2/cxx/module.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'build2/cxx/module.cxx')
-rw-r--r--build2/cxx/module.cxx230
1 files changed, 230 insertions, 0 deletions
diff --git a/build2/cxx/module.cxx b/build2/cxx/module.cxx
new file mode 100644
index 0000000..4829a17
--- /dev/null
+++ b/build2/cxx/module.cxx
@@ -0,0 +1,230 @@
+// file : build2/cxx/module.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <build2/cxx/module>
+
+#include <butl/process>
+#include <butl/fdstream>
+
+#include <build2/scope>
+#include <build2/diagnostics>
+
+#include <build2/config/utility>
+#include <build2/install/utility>
+
+#include <build2/bin/target>
+
+#include <build2/cxx/target>
+#include <build2/cxx/compile>
+#include <build2/cxx/link>
+#include <build2/cxx/install>
+
+using namespace std;
+using namespace butl;
+
+namespace build2
+{
+ namespace cxx
+ {
+ extern "C" bool
+ cxx_init (scope& r,
+ scope& b,
+ const location& loc,
+ std::unique_ptr<module>&,
+ bool first,
+ bool)
+ {
+ tracer trace ("cxx::init");
+ level5 ([&]{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<bool> (*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<h> ();
+ t.insert<c> ();
+
+ t.insert<cxx> ();
+ t.insert<hxx> ();
+ t.insert<ixx> ();
+ t.insert<txx> ();
+ }
+
+ // Register rules.
+ //
+ {
+ using namespace bin;
+
+ auto& r (b.rules);
+
+ r.insert<obja> (perform_update_id, "cxx.compile", compile::instance);
+
+ r.insert<obja> (perform_update_id, "cxx.compile", compile::instance);
+ r.insert<obja> (perform_clean_id, "cxx.compile", compile::instance);
+
+ r.insert<objso> (perform_update_id, "cxx.compile", compile::instance);
+ r.insert<objso> (perform_clean_id, "cxx.compile", compile::instance);
+
+ r.insert<exe> (perform_update_id, "cxx.link", link::instance);
+ r.insert<exe> (perform_clean_id, "cxx.link", link::instance);
+
+ r.insert<liba> (perform_update_id, "cxx.link", link::instance);
+ r.insert<liba> (perform_clean_id, "cxx.link", link::instance);
+
+ r.insert<libso> (perform_update_id, "cxx.link", link::instance);
+ r.insert<libso> (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<obja> (configure_update_id, "cxx.compile", compile::instance);
+ r.insert<objso> (configure_update_id, "cxx.compile", compile::instance);
+
+ r.insert<exe> (configure_update_id, "cxx.link", link::instance);
+ r.insert<liba> (configure_update_id, "cxx.link", link::instance);
+ r.insert<libso> (configure_update_id, "cxx.link", link::instance);
+
+ //@@ Should we check if install module was loaded (see bin)?
+ //
+ r.insert<exe> (perform_install_id, "cxx.install", install::instance);
+ r.insert<liba> (perform_install_id, "cxx.install", install::instance);
+ r.insert<libso> (perform_install_id, "cxx.install", install::instance);
+ }
+
+ // Configure.
+ //
+
+ // config.cxx
+ //
+ if (first)
+ {
+ auto p (config::required (r, "config.cxx", "g++"));
+
+ // If we actually set a new value, test it by trying to execute.
+ //
+ if (p.second)
+ {
+ const string& cxx (as<string> (p.first));
+ const char* args[] = {cxx.c_str (), "-dumpversion", nullptr};
+
+ if (verb >= 2)
+ print_process (args);
+ else if (verb)
+ text << "test " << cxx;
+
+ string ver;
+ try
+ {
+ process pr (args, 0, -1); // Open pipe to stdout.
+ ifdstream is (pr.in_ofd);
+
+ bool r (getline (is, ver));
+
+ if (!r)
+ fail << "unexpected output from " << cxx;
+
+ if (!pr.wait ())
+ throw failed ();
+ }
+ catch (const process_error& e)
+ {
+ error << "unable to execute " << cxx << ": " << e.what ();
+
+ if (e.child ())
+ exit (1);
+
+ throw failed ();
+ }
+
+ if (verb >= 2)
+ text << cxx << " " << ver;
+ }
+ }
+
+ // 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 = <overridable options> # Note: '='.
+ // using cxx
+ // cxx.coptions += <overriding options> # Note: '+='.
+ //
+ if (const value& v = config::optional (r, "config.cxx.poptions"))
+ b.assign ("cxx.poptions") += as<strings> (v);
+
+ if (const value& v = config::optional (r, "config.cxx.coptions"))
+ b.assign ("cxx.coptions") += as<strings> (v);
+
+ if (const value& v = config::optional (r, "config.cxx.loptions"))
+ b.assign ("cxx.loptions") += as<strings> (v);
+
+ if (const value& v = config::optional (r, "config.cxx.libs"))
+ b.assign ("cxx.libs") += as<strings> (v);
+
+ // Configure "installability" of our target types.
+ //
+ {
+ using build2::install::path;
+
+ path<hxx> (b, dir_path ("include")); // Install into install.include.
+ path<ixx> (b, dir_path ("include"));
+ path<txx> (b, dir_path ("include"));
+ path<h> (b, dir_path ("include"));
+ }
+
+ return true;
+ }
+ }
+}