aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/root.build3
-rw-r--r--build2/buildfile1
-rw-r--r--build2/c/init.cxx274
-rw-r--r--build2/cc/common43
-rw-r--r--build2/cc/compile.cxx24
-rw-r--r--build2/cc/gcc.cxx128
-rw-r--r--build2/cc/init.cxx233
-rw-r--r--build2/cc/link34
-rw-r--r--build2/cc/link.cxx230
-rw-r--r--build2/cc/module29
-rw-r--r--build2/cc/module.cxx331
-rw-r--r--build2/cc/msvc.cxx9
-rw-r--r--build2/cc/pkgconfig.cxx27
-rw-r--r--build2/cxx/init.cxx272
-rw-r--r--build2/pkgconfig/init.cxx4
15 files changed, 882 insertions, 760 deletions
diff --git a/build/root.build b/build/root.build
index 9ed207f..0851534 100644
--- a/build/root.build
+++ b/build/root.build
@@ -2,6 +2,8 @@
# copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
+cxx.std = 14
+
using cxx
hxx{*}: extension =
@@ -9,7 +11,6 @@ ixx{*}: extension = ixx
txx{*}: extension = txx
cxx{*}: extension = cxx
-cxx.std = 14
cxx.poptions =+ -I$out_root -I$src_root
# All exe{} in tests/ are, well, tests. Don't install them.
diff --git a/build2/buildfile b/build2/buildfile
index ad5a023..b24fc15 100644
--- a/build2/buildfile
+++ b/build2/buildfile
@@ -42,6 +42,7 @@ exe{b}: \
c/{hxx }{ target } \
cc/{hxx }{ common } \
cc/{hxx cxx}{ compile } \
+ cc/{ cxx}{ gcc } \
cc/{hxx cxx}{ guess } \
cc/{hxx cxx}{ init } \
cc/{hxx cxx}{ install } \
diff --git a/build2/c/init.cxx b/build2/c/init.cxx
index c846ae1..4032e07 100644
--- a/build2/c/init.cxx
+++ b/build2/c/init.cxx
@@ -8,6 +8,7 @@
#include <build2/context>
#include <build2/diagnostics>
+#include <build2/cc/guess>
#include <build2/cc/module>
#include <build2/c/target>
@@ -19,24 +20,29 @@ namespace build2
{
namespace c
{
- using cc::config_module;
+ using cc::compiler_info;
- class module: public cc::module
+ class config_module: public cc::config_module
{
public:
explicit
- module (data&& d): common (move (d)), cc::module (move (d)) {}
+ config_module (config_data&& d)
+ : config_data (move (d)), cc::config_module (move (d)) {}
- bool
- translate_std (string&, scope&, const value&) const override;
+ string
+ translate_std (const compiler_info&,
+ scope&,
+ const string&) const override;
};
- bool module::
- translate_std (string& s, scope& r, const value& val) const
+ using cc::module;
+
+ string config_module::
+ translate_std (const compiler_info& ci, scope& rs, const string& v) const
{
- const string& v (cast<string> (val));
+ string r;
- if (cid == "msvc")
+ if (ci.id.type == "msvc")
{
// Standard-wise, with VC you get what you get. The question is
// whether we should verify that the requested standard is provided by
@@ -56,128 +62,129 @@ namespace build2
//
if (v != "90")
{
- uint64_t cver (cast<uint64_t> (r[x_version_major]));
+ uint64_t cver (ci.version.major);
if ((v == "99" && cver < 16) || // Since VS2010/10.0.
(v == "11" && cver < 17)) // Since VS2012/11.0.
{
- fail << "C" << v << " is not supported by "
- << cast<string> (r[x_signature]) <<
- info << "required by " << project (r) << '@' << r.out_path ();
+ fail << "C" << v << " is not supported by " << ci.signature <<
+ info << "required by " << project (rs) << '@' << rs.out_path ();
}
}
-
- return false;
}
else
{
// 90 and 89 are the same standard. Translate 99 to 9x and 11 to 1x
// for compatibility with older versions of the compilers.
//
- s = "-std=";
+ r = "-std=";
if (v == "90")
- s += "c90";
+ r += "c90";
else if (v == "99")
- s += "c9x";
+ r += "c9x";
else if (v == "11")
- s += "c1x";
+ r += "c1x";
else
- s += v; // In case the user specifies something like 'gnu11'.
-
- return true;
+ r += v; // In case the user specifies something like 'gnu11'.
}
+
+ return r;
}
bool
- config_init (scope& r,
- scope& b,
+ config_init (scope& rs,
+ scope& bs,
const location& loc,
- unique_ptr<module_base>& m,
- bool first,
+ unique_ptr<module_base>& mod,
+ bool,
bool,
const variable_map& hints)
{
tracer trace ("c::config_init");
- l5 ([&]{trace << "for " << b.out_path ();});
+ l5 ([&]{trace << "for " << bs.out_path ();});
- if (first)
- {
- // Load cc.core.vars so that we can cache all the cc.* variables.
- //
- if (!cast_false<bool> (b["cc.core.vars.loaded"]))
- load_module ("cc.core.vars", r, b, loc);
+ // We only support root loading (which means there can only be one).
+ //
+ if (&rs != &bs)
+ fail (loc) << "c.config module must be loaded in project root";
- // Enter all the variables and initialize the module data.
- //
- auto& v (var_pool);
-
- cc::config_data d {
- cc::lang::c,
-
- "c",
- "c",
- "gcc",
-
- // Note: some overridable, some not.
- //
- v.insert<path> ("config.c", true),
- v.insert<strings> ("config.c.poptions", true),
- v.insert<strings> ("config.c.coptions", true),
- v.insert<strings> ("config.c.loptions", true),
- v.insert<strings> ("config.c.libs", true),
-
- v.insert<process_path> ("c.path"),
- v.insert<strings> ("c.poptions"),
- v.insert<strings> ("c.coptions"),
- v.insert<strings> ("c.loptions"),
- v.insert<strings> ("c.libs"),
-
- v["cc.poptions"],
- v["cc.coptions"],
- v["cc.loptions"],
- v["cc.libs"],
-
- v.insert<strings> ("c.export.poptions"),
- v.insert<strings> ("c.export.coptions"),
- v.insert<strings> ("c.export.loptions"),
- v.insert<names> ("c.export.libs"),
-
- v["cc.export.poptions"],
- v["cc.export.coptions"],
- v["cc.export.loptions"],
- v["cc.export.libs"],
-
- v["cc.type"],
-
- v.insert<string> ("c.std", true),
-
- v.insert<string> ("c.id"),
- v.insert<string> ("c.id.type"),
- v.insert<string> ("c.id.variant"),
-
- v.insert<string> ("c.version"),
- v.insert<uint64_t> ("c.version.major"),
- v.insert<uint64_t> ("c.version.minor"),
- v.insert<uint64_t> ("c.version.patch"),
- v.insert<string> ("c.version.build"),
-
- v.insert<string> ("c.signature"),
- v.insert<string> ("c.checksum"),
-
- v.insert<string> ("c.target"),
- v.insert<string> ("c.target.cpu"),
- v.insert<string> ("c.target.vendor"),
- v.insert<string> ("c.target.system"),
- v.insert<string> ("c.target.version"),
- v.insert<string> ("c.target.class")
- };
-
- assert (m == nullptr);
- m.reset (new config_module (move (d)));
- }
+ // Load cc.core.vars so that we can cache all the cc.* variables.
+ //
+ if (!cast_false<bool> (rs["cc.core.vars.loaded"]))
+ load_module ("cc.core.vars", rs, rs, loc);
- static_cast<config_module&> (*m).init (r, b, loc, first, hints);
+ // Enter all the variables and initialize the module data.
+ //
+ auto& v (var_pool);
+
+ cc::config_data d {
+ cc::lang::c,
+
+ "c",
+ "c",
+ "gcc",
+
+ // Note: some overridable, some not.
+ //
+ v.insert<path> ("config.c", true),
+ v.insert<strings> ("config.c.poptions", true),
+ v.insert<strings> ("config.c.coptions", true),
+ v.insert<strings> ("config.c.loptions", true),
+ v.insert<strings> ("config.c.libs", true),
+
+ v.insert<process_path> ("c.path"),
+ v.insert<dir_paths> ("c.sys_lib_dirs"),
+
+ v.insert<strings> ("c.poptions"),
+ v.insert<strings> ("c.coptions"),
+ v.insert<strings> ("c.loptions"),
+ v.insert<strings> ("c.libs"),
+
+ v["cc.poptions"],
+ v["cc.coptions"],
+ v["cc.loptions"],
+ v["cc.libs"],
+
+ v.insert<strings> ("c.export.poptions"),
+ v.insert<strings> ("c.export.coptions"),
+ v.insert<strings> ("c.export.loptions"),
+ v.insert<names> ("c.export.libs"),
+
+ v["cc.export.poptions"],
+ v["cc.export.coptions"],
+ v["cc.export.loptions"],
+ v["cc.export.libs"],
+
+ v["cc.type"],
+
+ v.insert<string> ("c.std", true),
+
+ v.insert<string> ("c.id"),
+ v.insert<string> ("c.id.type"),
+ v.insert<string> ("c.id.variant"),
+
+ v.insert<string> ("c.version"),
+ v.insert<uint64_t> ("c.version.major"),
+ v.insert<uint64_t> ("c.version.minor"),
+ v.insert<uint64_t> ("c.version.patch"),
+ v.insert<string> ("c.version.build"),
+
+ v.insert<string> ("c.signature"),
+ v.insert<string> ("c.checksum"),
+
+ v.insert<string> ("c.target"),
+ v.insert<string> ("c.target.cpu"),
+ v.insert<string> ("c.target.vendor"),
+ v.insert<string> ("c.target.system"),
+ v.insert<string> ("c.target.version"),
+ v.insert<string> ("c.target.class")
+ };
+
+ assert (mod == nullptr);
+ config_module* m;
+ mod.reset (m = new config_module (move (d)));
+ m->init (rs, loc, hints);
return true;
}
@@ -195,51 +202,56 @@ namespace build2
};
bool
- init (scope& r,
- scope& b,
+ init (scope& rs,
+ scope& bs,
const location& loc,
- unique_ptr<module_base>& m,
- bool first,
+ unique_ptr<module_base>& mod,
+ bool,
bool,
const variable_map& hints)
{
tracer trace ("c::init");
- l5 ([&]{trace << "for " << b.out_path ();});
+ l5 ([&]{trace << "for " << bs.out_path ();});
+
+ // We only support root loading (which means there can only be one).
+ //
+ if (&rs != &bs)
+ fail (loc) << "c module must be loaded in project root";
// Load c.config.
//
- if (!cast_false<bool> (b["c.config.loaded"]))
- load_module ("c.config", r, b, loc, false, hints);
+ if (!cast_false<bool> (rs["c.config.loaded"]))
+ load_module ("c.config", rs, rs, loc, false, hints);
- if (first)
- {
- config_module& cm (*r.modules.lookup<config_module> ("c.config"));
+ config_module& cm (*rs.modules.lookup<config_module> ("c.config"));
- cc::data d {
- cm,
+ cc::data d {
+ cm,
- "c.compile",
- "c.link",
- "c.install",
- "c.uninstall",
+ "c.compile",
+ "c.link",
+ "c.install",
+ "c.uninstall",
- cast<string> (r[cm.x_id]),
- cast<string> (r[cm.x_target]),
- cast<string> (r[cm.x_target_system]),
- cast<string> (r[cm.x_target_class]),
+ cast<string> (rs[cm.x_id]),
+ cast<string> (rs[cm.x_target]),
+ cast<string> (rs[cm.x_target_system]),
+ cast<string> (rs[cm.x_target_class]),
- cast_null<process_path> (r["pkgconfig.path"]),
+ cm.tstd,
- c::static_type,
- hdr,
- inc
- };
+ cast_null<process_path> (rs["pkgconfig.path"]),
+ cast<dir_paths> (rs[cm.x_sys_lib_dirs]),
- assert (m == nullptr);
- m.reset (new module (move (d)));
- }
+ c::static_type,
+ hdr,
+ inc
+ };
- static_cast<module&> (*m).init (r, b, loc, first, hints);
+ assert (mod == nullptr);
+ module* m;
+ mod.reset (m = new module (move (d)));
+ m->init (rs, loc, hints);
return true;
}
}
diff --git a/build2/cc/common b/build2/cc/common
index c25683c..41bcef5 100644
--- a/build2/cc/common
+++ b/build2/cc/common
@@ -36,7 +36,9 @@ namespace build2
const variable& config_x_loptions;
const variable& config_x_libs;
- const variable& x_path;
+ const variable& x_path; // Compiler process path.
+ const variable& x_sys_lib_dirs; // System library search directories.
+
const variable& x_poptions;
const variable& x_coptions;
const variable& x_loptions;
@@ -89,14 +91,17 @@ namespace build2
const char* x_install;
const char* x_uninstall;
- // Cached values for some commonly-used variables.
+ // Cached values for some commonly-used variables/values.
//
const string& cid; // x.id
const string& ctg; // x.target
const string& tsys; // x.target.system
const string& tclass; // x.target.class
+ const string& tstd; // Translated x_std value (can be empty).
+
const process_path* pkgconfig; // pkgconfig.path (can be NULL).
+ const dir_paths& sys_lib_dirs; // x.sys_lib_dirs
const target_type& x_src; // Source target type (c{}, cxx{}).
@@ -131,9 +136,11 @@ namespace build2
const char* uninstall,
const string& id,
const string& tg,
- const string& sys,
- const string& class_,
+ const string& ts,
+ const string& tc,
+ const string& std,
const process_path* pkgc,
+ const dir_paths& sld,
const target_type& src,
const target_type* const* hdr,
const target_type* const* inc)
@@ -142,8 +149,8 @@ namespace build2
x_link (link),
x_install (install),
x_uninstall (uninstall),
- cid (id), ctg (tg), tsys (sys), tclass (class_),
- pkgconfig (pkgc),
+ cid (id), ctg (tg), tsys (ts), tclass (tc),
+ tstd (std), pkgconfig (pkgc), sys_lib_dirs (sld),
x_src (src), x_hdr (hdr), x_inc (inc) {}
};
@@ -152,31 +159,21 @@ namespace build2
public:
common (data&& d): data (move (d)) {}
- // Language standard (x.std) mapping. T is either target or scope.
+ // Language standard (x.std) mapping.
//
- template <typename T>
void
- append_std (cstrings& args, scope& root, T& t, string& storage) const
+ append_std (cstrings& args) const
{
- if (auto l = t[x_std])
- if (translate_std (storage, root, *l))
- args.push_back (storage.c_str ());
+ if (!tstd.empty ())
+ args.push_back (tstd.c_str ());
}
- template <typename T>
void
- hash_std (sha256& csum, scope& root, T& t) const
+ hash_std (sha256& cs) const
{
- string s;
- if (auto l = t[x_std])
- if (translate_std (s, root, *l))
- csum.append (s);
+ if (!tstd.empty ())
+ cs.append (tstd);
}
-
- // Return true if there is an option (stored in the first argument).
- //
- virtual bool
- translate_std (string&, scope&, const value&) const = 0;
};
}
}
diff --git a/build2/cc/compile.cxx b/build2/cc/compile.cxx
index fdd4231..20cd392 100644
--- a/build2/cc/compile.cxx
+++ b/build2/cc/compile.cxx
@@ -82,7 +82,8 @@ namespace build2
append_options (args, l, var);
};
- link_.process_libraries (l, l.is_a<liba> (), true, nullptr, opt);
+ link_.process_libraries (
+ sys_lib_dirs, l, l.is_a<liba> (), true, nullptr, opt);
}
void compile::
@@ -102,7 +103,8 @@ namespace build2
hash_options (cs, l, var);
};
- link_.process_libraries (l, l.is_a<liba> (), true, nullptr, opt);
+ link_.process_libraries (
+ sys_lib_dirs, l, l.is_a<liba> (), true, nullptr, opt);
}
recipe compile::
@@ -172,7 +174,7 @@ namespace build2
// When cleaning, ignore prerequisites that are not in the same or a
// subdirectory of our project root.
//
- optional<dir_paths> lib_paths; // Extract lazily.
+ optional<dir_paths> usr_lib_dirs; // Extract lazily.
lorder lo;
if (a.operation () == update_id)
@@ -197,7 +199,7 @@ namespace build2
//
if (p.proj () == nullptr ||
link_.search_library (
- lib_paths, p.prerequisite, lo) == nullptr)
+ sys_lib_dirs, usr_lib_dirs, p.prerequisite, lo) == nullptr)
{
match_only (a, p.search ());
}
@@ -280,7 +282,7 @@ namespace build2
hash_options (cs, t, x_poptions);
hash_options (cs, t, c_coptions);
hash_options (cs, t, x_coptions);
- hash_std (cs, rs, t);
+ hash_std (cs);
if (ct == otype::s)
{
@@ -461,7 +463,8 @@ namespace build2
append_prefixes (m, l, var);
};
- link_.process_libraries (l, l.is_a<liba> (), true, nullptr, opt);
+ link_.process_libraries (
+ sys_lib_dirs, l, l.is_a<liba> (), true, nullptr, opt);
}
auto compile::
@@ -689,9 +692,8 @@ namespace build2
//
const process_path* xc (nullptr);
cstrings args;
- string std; // Storage.
- auto init_args = [&t, lo, &src, &rs, &xc, &args, &std, this] ()
+ auto init_args = [&t, lo, &src, &rs, &xc, &args, this] ()
{
xc = &cast<process_path> (rs[x_path]);
args.push_back (xc->recall_string ());
@@ -719,7 +721,7 @@ namespace build2
append_options (args, t, c_coptions);
append_options (args, t, x_coptions);
- append_std (args, rs, t, std);
+ append_std (args);
if (t.is_a<objs> ())
{
@@ -1388,9 +1390,9 @@ namespace build2
append_options (args, t, c_coptions);
append_options (args, t, x_coptions);
- string std, out, out1; // Storage.
+ string out, out1; // Storage.
- append_std (args, rs, t, std);
+ append_std (args);
if (cid == "msvc")
{
diff --git a/build2/cc/gcc.cxx b/build2/cc/gcc.cxx
new file mode 100644
index 0000000..a6c7448
--- /dev/null
+++ b/build2/cc/gcc.cxx
@@ -0,0 +1,128 @@
+// file : build2/cc/gcc.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <build2/scope>
+#include <build2/target>
+#include <build2/context>
+#include <build2/variable>
+#include <build2/filesystem>
+#include <build2/diagnostics>
+
+#include <build2/bin/target>
+
+#include <build2/cc/types>
+
+#include <build2/cc/module>
+
+using namespace std;
+using namespace butl;
+
+namespace build2
+{
+ namespace cc
+ {
+ using namespace bin;
+
+ // Extract system library search paths from GCC (gcc/g++) or compatible
+ // (Clang, Intel) using the -print-search-dirs option.
+ //
+ dir_paths config_module::
+ gcc_library_search_paths (process_path& xc, scope& rs) const
+ {
+ dir_paths r;
+
+ cstrings args;
+ string std; // Storage.
+
+ args.push_back (xc.recall_string ());
+ append_options (args, rs, c_coptions);
+ append_options (args, rs, x_coptions);
+ if (!tstd.empty ()) args.push_back (tstd.c_str ());
+ append_options (args, rs, c_loptions);
+ append_options (args, rs, x_loptions);
+ args.push_back ("-print-search-dirs");
+ args.push_back (nullptr);
+
+ if (verb >= 3)
+ print_process (args);
+
+ string l;
+ try
+ {
+ process pr (xc, args.data (), 0, -1); // Open pipe to stdout.
+
+ try
+ {
+ ifdstream is (pr.in_ofd, fdstream_mode::skip, ifdstream::badbit);
+
+ string s;
+ while (getline (is, s))
+ {
+ if (s.compare (0, 12, "libraries: =") == 0)
+ {
+ l.assign (s, 12, string::npos);
+ break;
+ }
+ }
+
+ is.close (); // Don't block.
+
+ if (!pr.wait ())
+ throw failed ();
+ }
+ catch (const ifdstream::failure&)
+ {
+ pr.wait ();
+ fail << "error reading " << x_lang << " compiler -print-search-dirs "
+ << "output";
+ }
+ }
+ catch (const process_error& e)
+ {
+ error << "unable to execute " << args[0] << ": " << e.what ();
+
+ if (e.child ())
+ exit (1);
+
+ throw failed ();
+ }
+
+ if (l.empty ())
+ fail << "unable to extract " << x_lang << " compiler system library "
+ << "search paths";
+
+ // Now the fun part: figuring out which delimiter is used. Normally it
+ // is ':' but on Windows it is ';' (or can be; who knows for sure). Also
+ // note that these paths are absolute (or should be). So here is what we
+ // are going to do: first look for ';'. If found, then that's the
+ // delimiter. If not found, then there are two cases: it is either a
+ // single Windows path or the delimiter is ':'. To distinguish these two
+ // cases we check if the path starts with a Windows drive.
+ //
+ char d (';');
+ string::size_type e (l.find (d));
+
+ if (e == string::npos &&
+ (l.size () < 2 || l[0] == '/' || l[1] != ':'))
+ {
+ d = ':';
+ e = l.find (d);
+ }
+
+ // Now chop it up. We already have the position of the first delimiter
+ // (if any).
+ //
+ for (string::size_type b (0);; e = l.find (d, (b = e + 1)))
+ {
+ r.emplace_back (l, b, (e != string::npos ? e - b : e));
+ r.back ().normalize ();
+
+ if (e == string::npos)
+ break;
+ }
+
+ return r;
+ }
+ }
+}
diff --git a/build2/cc/init.cxx b/build2/cc/init.cxx
index 066367d..42412a7 100644
--- a/build2/cc/init.cxx
+++ b/build2/cc/init.cxx
@@ -74,8 +74,8 @@ namespace build2
}
bool
- core_config_init (scope& r,
- scope& b,
+ core_config_init (scope& rs,
+ scope&,
const location& loc,
unique_ptr<module_base>&,
bool first,
@@ -83,96 +83,93 @@ namespace build2
const variable_map& hints)
{
tracer trace ("cc::core_config_init");
- l5 ([&]{trace << "for " << b.out_path ();});
+ l5 ([&]{trace << "for " << rs.out_path ();});
+
+ assert (first);
// Load cc.core.vars.
//
- if (first)
- {
- if (!cast_false<bool> (b["cc.core.vars.loaded"]))
- load_module ("cc.core.vars", r, b, loc);
- }
+ if (!cast_false<bool> (rs["cc.core.vars.loaded"]))
+ load_module ("cc.core.vars", rs, rs, loc);
// Configure.
//
- if (first)
+
+ // Adjust module priority (compiler).
+ //
+ config::save_module (rs, "cc", 250);
+
+ // config.cc.id
+ //
{
- // Adjust module priority (compiler).
+ // This value must be hinted.
//
- config::save_module (r, "cc", 250);
+ rs.assign<string> ("cc.id") = cast<string> (hints["config.cc.id"]);
+ }
- // config.cc.id
+ // config.cc.target
+ //
+ {
+ // This value must be hinted and already canonicalized.
//
+ const string& s (cast<string> (hints["config.cc.target"]));
+
+ try
{
- // This value must be hinted.
+ //@@ 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?
//
- r.assign<string> ("cc.id") = cast<string> (hints["config.cc.id"]);
- }
+ triplet t (s);
- // config.cc.target
- //
- {
- // This value must be hinted and already canonicalized.
+ // Enter as cc.target.{cpu,vendor,system,version,class}.
//
- const string& s (cast<string> (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<string> ("cc.target") = s;
- r.assign<string> ("cc.target.cpu") = move (t.cpu);
- r.assign<string> ("cc.target.vendor") = move (t.vendor);
- r.assign<string> ("cc.target.system") = move (t.system);
- r.assign<string> ("cc.target.version") = move (t.version);
- r.assign<string> ("cc.target.class") = move (t.class_);
- }
- catch (const invalid_argument& e)
- {
- assert (false); // Should have been caught by the hinting module.
- }
+ rs.assign<string> ("cc.target") = s;
+ rs.assign<string> ("cc.target.cpu") = move (t.cpu);
+ rs.assign<string> ("cc.target.vendor") = move (t.vendor);
+ rs.assign<string> ("cc.target.system") = move (t.system);
+ rs.assign<string> ("cc.target.version") = move (t.version);
+ rs.assign<string> ("cc.target.class") = move (t.class_);
}
-
- // config.cc.pattern
- //
+ catch (const invalid_argument& e)
{
- // This value could be hinted.
- //
- if (auto l = hints["config.cc.pattern"])
- r.assign<string> ("cc.pattern") = cast<string> (l);
+ assert (false); // Should have been caught by the hinting module.
}
+ }
- // 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.pattern
+ //
+ {
+ // This value could be hinted.
+ //
+ if (auto l = hints["config.cc.pattern"])
+ rs.assign<string> ("cc.pattern") = cast<string> (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<strings> (
- config::optional (r, "config.cc.poptions"));
+ rs.assign ("cc.poptions") += cast_null<strings> (
+ config::optional (rs, "config.cc.poptions"));
- b.assign ("cc.coptions") += cast_null<strings> (
- config::optional (r, "config.cc.coptions"));
+ rs.assign ("cc.coptions") += cast_null<strings> (
+ config::optional (rs, "config.cc.coptions"));
- b.assign ("cc.loptions") += cast_null<strings> (
- config::optional (r, "config.cc.loptions"));
+ rs.assign ("cc.loptions") += cast_null<strings> (
+ config::optional (rs, "config.cc.loptions"));
- b.assign ("cc.libs") += cast_null<strings> (
- config::optional (r, "config.cc.libs"));
+ rs.assign ("cc.libs") += cast_null<strings> (
+ config::optional (rs, "config.cc.libs"));
// Load the bin.config module.
//
- if (!cast_false<bool> (b["bin.config.loaded"]))
+ if (!cast_false<bool> (rs["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.
@@ -180,13 +177,13 @@ namespace build2
variable_map h;
if (first)
{
- h.assign ("config.bin.target") = cast<string> (r["cc.target"]);
+ h.assign ("config.bin.target") = cast<string> (rs["cc.target"]);
if (auto l = hints["config.bin.pattern"])
- h.assign ("config.bin.pattern") = cast<string> (l);
+ h.assign ("config.bin.pattern") = cast<string> (l);
}
- load_module ("bin.config", r, b, loc, false, h);
+ load_module ("bin.config", rs, rs, loc, false, h);
}
// Verify bin's target matches ours (we do it even if we loaded it
@@ -195,8 +192,8 @@ namespace build2
//
if (first)
{
- const string& ct (cast<string> (r["cc.target"]));
- const string& bt (cast<string> (r["bin.target"]));
+ const string& ct (cast<string> (rs["cc.target"]));
+ const string& bt (cast<string> (rs["bin.target"]));
if (bt != ct)
fail (loc) << "cc and bin module target mismatch" <<
@@ -204,31 +201,31 @@ namespace build2
info << "bin.target is " << bt;
}
- const string& cid (cast<string> (r["cc.id"]));
- const string& tsys (cast<string> (r["cc.target.system"]));
+ const string& cid (cast<string> (rs["cc.id"]));
+ const string& tsys (cast<string> (rs["cc.target.system"]));
// Load bin.*.config for bin.* modules we may need (see core_init()
// below).
//
- if (auto l = r["config.bin.lib"])
+ if (auto l = rs["config.bin.lib"])
{
if (cast<string> (l) != "shared")
{
- if (!cast_false<bool> (b["bin.ar.config.loaded"]))
- load_module ("bin.ar.config", r, b, loc);
+ if (!cast_false<bool> (rs["bin.ar.config.loaded"]))
+ load_module ("bin.ar.config", rs, rs, loc);
}
}
if (cid == "msvc")
{
- if (!cast_false<bool> (b["bin.ld.config.loaded"]))
- load_module ("bin.ld.config", r, b, loc);
+ if (!cast_false<bool> (rs["bin.ld.config.loaded"]))
+ load_module ("bin.ld.config", rs, rs, loc);
}
if (tsys == "mingw32")
{
- if (!cast_false<bool> (b["bin.rc.config.loaded"]))
- load_module ("bin.rc.config", r, b, loc);
+ if (!cast_false<bool> (rs["bin.rc.config.loaded"]))
+ load_module ("bin.rc.config", rs, rs, loc);
}
// Load (optionally) the pkgconfig.config module.
@@ -238,53 +235,55 @@ namespace build2
// doesn't set pkgconfig.target. Perhaps only set if it was used
// to derive the program name?
//
- if (first && !cast_false<bool> (b["pkgconfig.config.loaded"]))
+ if (!cast_false<bool> (rs["pkgconfig.config.loaded"]))
{
// Prepare configuration hints.
//
variable_map h;
- h.assign ("config.pkgconfig.target") = cast<string> (r["cc.target"]);
+ h.assign ("config.pkgconfig.target") = cast<string> (rs["cc.target"]);
- load_module ("pkgconfig.config", r, r, loc, true, h);
+ load_module ("pkgconfig.config", rs, rs, loc, true, h);
}
return true;
}
bool
- core_init (scope& r,
- scope& b,
+ core_init (scope& rs,
+ scope&,
const location& loc,
unique_ptr<module_base>&,
- bool,
+ bool first,
bool,
const variable_map& hints)
{
tracer trace ("cc::core_init");
- l5 ([&]{trace << "for " << b.out_path ();});
+ l5 ([&]{trace << "for " << rs.out_path ();});
+
+ assert (first);
// Load cc.core.config.
//
- if (!cast_false<bool> (b["cc.core.config.loaded"]))
- load_module ("cc.core.config", r, b, loc, false, hints);
+ if (!cast_false<bool> (rs["cc.core.config.loaded"]))
+ load_module ("cc.core.config", rs, rs, loc, false, hints);
// Load the bin module.
//
- if (!cast_false<bool> (b["bin.loaded"]))
- load_module ("bin", r, b, loc);
+ if (!cast_false<bool> (rs["bin.loaded"]))
+ load_module ("bin", rs, rs, loc);
- const string& cid (cast<string> (r["cc.id"]));
- const string& tsys (cast<string> (r["cc.target.system"]));
+ const string& cid (cast<string> (rs["cc.id"]));
+ const string& tsys (cast<string> (rs["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 (auto l = rs["config.bin.lib"])
{
if (cast<string> (l) != "shared")
{
- if (!cast_false<bool> (b["bin.ar.loaded"]))
- load_module ("bin.ar", r, b, loc);
+ if (!cast_false<bool> (rs["bin.ar.loaded"]))
+ load_module ("bin.ar", rs, rs, loc);
}
}
@@ -293,8 +292,8 @@ namespace build2
//
if (cid == "msvc")
{
- if (!cast_false<bool> (b["bin.ld.loaded"]))
- load_module ("bin.ld", r, b, loc);
+ if (!cast_false<bool> (rs["bin.ld.loaded"]))
+ load_module ("bin.ld", rs, rs, loc);
}
// If our target is MinGW, then we will need the resource compiler
@@ -302,8 +301,8 @@ namespace build2
//
if (tsys == "mingw32")
{
- if (!cast_false<bool> (b["bin.rc.loaded"]))
- load_module ("bin.rc", r, b, loc);
+ if (!cast_false<bool> (rs["bin.rc.loaded"]))
+ load_module ("bin.rc", rs, rs, loc);
}
return true;
@@ -315,45 +314,51 @@ namespace build2
//
static inline bool
init_alias (tracer& trace,
+ const char* m,
const char* c,
const char* c_loaded,
const char* cxx,
const char* cxx_loaded,
- scope& r,
- scope& b,
+ scope& rs,
+ scope& bs,
const location& loc,
const variable_map& hints)
{
- l5 ([&]{trace << "for " << b.out_path ();});
+ l5 ([&]{trace << "for " << bs.out_path ();});
+
+ // We only support root loading (which means there can only be one).
+ //
+ if (&rs != &bs)
+ fail (loc) << m << " module must be loaded in project root";
// 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<bool> (b[c_loaded]));
- bool lp (!cast_false<bool> (b[cxx_loaded]));
+ bool lc (!cast_false<bool> (rs[c_loaded]));
+ bool lp (!cast_false<bool> (rs[cxx_loaded]));
// If none of them are already loaded, load c first only if config.c
// is specified.
//
- if (lc && lp && r["config.c"])
+ if (lc && lp && rs["config.c"])
{
- load_module (c, r, b, loc, false, hints);
- load_module (cxx, r, b, loc, false, hints);
+ load_module (c, rs, rs, loc, false, hints);
+ load_module (cxx, rs, rs, loc, false, hints);
}
else
{
- if (lp) load_module (cxx, r, b, loc, false, hints);
- if (lc) load_module (c, r, b, loc, false, hints);
+ if (lp) load_module (cxx, rs, rs, loc, false, hints);
+ if (lc) load_module (c, rs, rs, loc, false, hints);
}
return true;
}
bool
- config_init (scope& r,
- scope& b,
+ config_init (scope& rs,
+ scope& bs,
const location& loc,
unique_ptr<module_base>&,
bool,
@@ -361,17 +366,15 @@ namespace build2
const variable_map& hints)
{
tracer trace ("cc::config_init");
- return init_alias (trace,
+ return init_alias (trace, "cc.config",
"c.config", "c.config.loaded",
"cxx.config", "cxx.config.loaded",
- r, b,
- loc,
- hints);
+ rs, bs, loc, hints);
}
bool
- init (scope& r,
- scope& b,
+ init (scope& rs,
+ scope& bs,
const location& loc,
unique_ptr<module_base>&,
bool,
@@ -379,12 +382,10 @@ namespace build2
const variable_map& hints)
{
tracer trace ("cc::init");
- return init_alias (trace,
+ return init_alias (trace, "cc",
"c", "c.loaded",
"cxx", "cxx.loaded",
- r, b,
- loc,
- hints);
+ rs, bs, loc, hints);
}
}
}
diff --git a/build2/cc/link b/build2/cc/link
index 474c299..09678c2 100644
--- a/build2/cc/link
+++ b/build2/cc/link
@@ -40,7 +40,8 @@ namespace build2
friend class compile;
void
- process_libraries (file&,
+ process_libraries (const dir_paths&,
+ file&,
bool,
bool,
const function<void (const path&)>&,
@@ -55,21 +56,14 @@ namespace build2
hash_libraries (sha256&, file&, bool) const;
file&
- resolve_library (name, scope&, lorder, optional<dir_paths>&) const;
-
- // Extract system library search paths from GCC or compatible (Clang,
- // Intel) using the -print-search-dirs option.
- //
- void
- gcc_library_search_paths (scope&, dir_paths&) const;
-
- // Extract system library search paths from VC (msvc.cxx).
- //
- void
- msvc_library_search_paths (scope&, dir_paths&) const;
+ resolve_library (name,
+ scope&,
+ lorder,
+ const dir_paths&,
+ optional<dir_paths>&) const;
dir_paths
- extract_library_paths (scope&) const;
+ extract_library_dirs (scope&) const;
bool
pkgconfig_extract (scope&,
@@ -77,7 +71,7 @@ namespace build2
const string*,
const string&,
const dir_path&,
- optional<dir_paths>&,
+ const dir_paths&,
lorder) const;
// Alternative search logic for VC (msvc.cxx).
@@ -93,20 +87,20 @@ namespace build2
const prerequisite_key&) const;
target*
- search_library (optional<dir_paths>& spc,
+ search_library (const dir_paths& sysd,
+ optional<dir_paths>& usrd,
prerequisite& p,
lorder lo) const
{
if (p.target == nullptr) // First check the cache.
- p.target = search_library (spc, p.key (), lo);
+ p.target = search_library (sysd, usrd, p.key (), lo);
return p.target;
}
- // Note that pk's scope should not be NULL (even if dir is absolute).
- //
target*
- search_library (optional<dir_paths>&,
+ search_library (const dir_paths&,
+ optional<dir_paths>&,
const prerequisite_key&,
lorder) const;
diff --git a/build2/cc/link.cxx b/build2/cc/link.cxx
index a4fa1dd..f26bf57 100644
--- a/build2/cc/link.cxx
+++ b/build2/cc/link.cxx
@@ -39,107 +39,8 @@ namespace build2
{
}
- // Extract system library search paths from GCC or compatible (Clang,
- // Intel) using the -print-search-dirs option.
- //
- void link::
- gcc_library_search_paths (scope& bs, dir_paths& r) const
- {
- scope& rs (*bs.root_scope ());
-
- cstrings args;
- string std; // Storage.
-
- args.push_back (cast<path> (rs[config_x]).string ().c_str ());
- append_options (args, bs, c_coptions);
- append_options (args, bs, x_coptions);
- append_std (args, rs, bs, std);
- append_options (args, bs, c_loptions);
- append_options (args, bs, x_loptions);
- args.push_back ("-print-search-dirs");
- args.push_back (nullptr);
-
- if (verb >= 3)
- print_process (args);
-
- string l;
- try
- {
- process pr (args.data (), 0, -1); // Open pipe to stdout.
-
- try
- {
- ifdstream is (pr.in_ofd, fdstream_mode::skip, ifdstream::badbit);
-
- string s;
- while (getline (is, s))
- {
- if (s.compare (0, 12, "libraries: =") == 0)
- {
- l.assign (s, 12, string::npos);
- break;
- }
- }
-
- is.close (); // Don't block.
-
- if (!pr.wait ())
- throw failed ();
- }
- catch (const ifdstream::failure&)
- {
- pr.wait ();
- fail << "error reading " << x_lang << " compiler -print-search-dirs "
- << "output";
- }
- }
- catch (const process_error& e)
- {
- error << "unable to execute " << args[0] << ": " << e.what ();
-
- if (e.child ())
- exit (1);
-
- throw failed ();
- }
-
- if (l.empty ())
- fail << "unable to extract " << x_lang << " compiler system library "
- << "search paths";
-
- // Now the fun part: figuring out which delimiter is used. Normally it
- // is ':' but on Windows it is ';' (or can be; who knows for sure). Also
- // note that these paths are absolute (or should be). So here is what we
- // are going to do: first look for ';'. If found, then that's the
- // delimiter. If not found, then there are two cases: it is either a
- // single Windows path or the delimiter is ':'. To distinguish these two
- // cases we check if the path starts with a Windows drive.
- //
- char d (';');
- string::size_type e (l.find (d));
-
- if (e == string::npos &&
- (l.size () < 2 || l[0] == '/' || l[1] != ':'))
- {
- d = ':';
- e = l.find (d);
- }
-
- // Now chop it up. We already have the position of the first delimiter
- // (if any).
- //
- for (string::size_type b (0);; e = l.find (d, (b = e + 1)))
- {
- r.emplace_back (l, b, (e != string::npos ? e - b : e));
- r.back ().normalize ();
-
- if (e == string::npos)
- break;
- }
- }
-
dir_paths link::
- extract_library_paths (scope& bs) const
+ extract_library_dirs (scope& bs) const
{
dir_paths r;
@@ -193,16 +94,14 @@ namespace build2
if (auto l = bs[c_loptions]) extract (*l);
if (auto l = bs[x_loptions]) extract (*l);
- if (cid == "msvc")
- msvc_library_search_paths (bs, r);
- else
- gcc_library_search_paths (bs, r);
-
return r;
}
+ // Note that pk's scope should not be NULL (even if dir is absolute).
+ //
target* link::
- search_library (optional<dir_paths>& spc,
+ search_library (const dir_paths& sysd,
+ optional<dir_paths>& usrd,
const prerequisite_key& p,
lorder lo) const
{
@@ -300,15 +199,17 @@ namespace build2
// Now search.
//
- if (!spc)
- spc = extract_library_paths (*p.scope);
-
liba* a (nullptr);
libs* s (nullptr);
path f; // Reuse the buffer.
- const dir_path* pd;
- for (const dir_path& d: *spc)
+ const dir_path* pd (nullptr);
+
+ auto search =[&a, &s,
+ &an, &ae,
+ &sn, &se,
+ &name, ext,
+ &p, &f, &trace, this] (const dir_path& d) -> bool
{
timestamp mt;
@@ -427,14 +328,38 @@ namespace build2
a = msvc_search_static (ld, d, p);
}
- if (a != nullptr || s != nullptr)
+ return a != nullptr || s != nullptr;
+ };
+
+ // First try user directories (i.e., -L).
+ //
+ if (!usrd)
+ usrd = extract_library_dirs (*p.scope);
+
+ for (const dir_path& d: *usrd)
+ {
+ if (search (d))
{
pd = &d;
break;
}
}
- if (a == nullptr && s == nullptr)
+ // Next try system directories (i.e., those extracted from the compiler).
+ //
+ if (pd == nullptr)
+ {
+ for (const dir_path& d: sysd)
+ {
+ if (search (d))
+ {
+ pd = &d;
+ break;
+ }
+ }
+ }
+
+ if (pd == nullptr)
return nullptr;
// Add the "using static/shared library" macro (used, for example, to
@@ -508,14 +433,14 @@ namespace build2
// will copy those macros (or custom ones) from *.export.poptions.
//
if (pkgconfig == nullptr ||
- !pkgconfig_extract (*p.scope, *a, p.proj, name, *pd, spc, lo))
+ !pkgconfig_extract (*p.scope, *a, p.proj, name, *pd, sysd, lo))
add_macro (*a, "STATIC");
}
if (s != nullptr && mark_cc (*s))
{
if (pkgconfig == nullptr ||
- !pkgconfig_extract (*p.scope, *s, p.proj, name, *pd, spc, lo))
+ !pkgconfig_extract (*p.scope, *s, p.proj, name, *pd, sysd, lo))
add_macro (*s, "SHARED");
}
@@ -643,7 +568,7 @@ namespace build2
scope& bs (t.base_scope ());
lorder lo (link_order (bs, lt));
- optional<dir_paths> lib_paths; // Extract lazily.
+ optional<dir_paths> usr_lib_dirs; // Extract lazily.
for (prerequisite_member p: group_prerequisite_members (a, t))
{
@@ -654,7 +579,8 @@ namespace build2
// Handle imported libraries.
//
if (p.proj () != nullptr)
- pt = search_library (lib_paths, p.prerequisite, lo);
+ pt = search_library (
+ sys_lib_dirs, usr_lib_dirs, p.prerequisite, lo);
if (pt == nullptr)
{
@@ -826,7 +752,7 @@ namespace build2
//
inject_fsdir (a, t);
- optional<dir_paths> lib_paths; // Extract lazily.
+ optional<dir_paths> usr_lib_dirs; // Extract lazily.
// Process prerequisites: do rule chaining for C and X source files as
// well as search and match.
@@ -847,7 +773,8 @@ namespace build2
// Handle imported libraries.
//
if (p.proj () != nullptr)
- pt = search_library (lib_paths, p.prerequisite, lo);
+ pt = search_library (
+ sys_lib_dirs, usr_lib_dirs, p.prerequisite, lo);
// The rest is the same basic logic as in search_and_match().
//
@@ -1075,6 +1002,7 @@ namespace build2
//
void link::
process_libraries (
+ const dir_paths& def_sysd,
file& l,
bool la,
bool iface_only,
@@ -1135,7 +1063,11 @@ namespace build2
if (proc_lib)
proc_lib (f->path ());
- process_libraries (*f, a, iface_only, proc_lib, proc_opt);
+ // Note that def_sysd (which is wrong) will never be used since
+ // this library was matched by a rule (see below).
+ //
+ process_libraries (
+ def_sysd, *f, a, iface_only, proc_lib, proc_opt);
}
}
}
@@ -1143,14 +1075,18 @@ namespace build2
// Process libraries (recursively) from *.export.libs (of type names)
// handling import, etc.
//
- scope* bs (nullptr); // Resolve lazily.
- optional<lorder> lo; // Calculate lazily.
- optional<dir_paths> spc; // Extract lazily.
-
- auto proc_int =
- [&l, la, iface_only, &proc_lib, &proc_opt, &bs, &lo, &spc, this] (
- const lookup& lu)
+ scope* bs (nullptr); // Resolve lazily.
+ optional<lorder> lo; // Calculate lazily.
+ const dir_paths* sysd (nullptr); // Resolve lazily.
+ optional<dir_paths> usrd; // Extract lazily.
+
+ auto proc_int = [&l, la, t, iface_only,
+ &proc_lib, &proc_opt,
+ &sysd, &usrd, &def_sysd,
+ &bs, &lo, this] (const lookup& lu)
{
+ assert (t != nullptr);
+
const names* ns (cast_null<names> (lu));
if (ns == nullptr || ns->empty ())
return;
@@ -1175,7 +1111,23 @@ namespace build2
if (!lo)
lo = link_order (*bs, la ? otype::a : otype::s);
- file& t (resolve_library (n, *bs, *lo, spc));
+ if (sysd == nullptr)
+ {
+ if (*t == "cc")
+ sysd = &def_sysd; // Imported library, use importer's sysd.
+ else
+ {
+ // Use the search dirs corresponding to this library type.
+ //
+ scope& rs (*bs->root_scope ());
+ sysd = &cast<dir_paths> (
+ rs.vars[*t == x
+ ? x_sys_lib_dirs
+ : var_pool[*t + ".sys_lib_dirs"]]);
+ }
+ }
+
+ file& t (resolve_library (n, *bs, *lo, *sysd, usrd));
if (proc_lib)
{
@@ -1195,7 +1147,7 @@ namespace build2
// Process it recursively.
//
process_libraries (
- t, t.is_a<liba> (), iface_only, proc_lib, proc_opt);
+ *sysd, t, t.is_a<liba> (), iface_only, proc_lib, proc_opt);
}
}
};
@@ -1299,7 +1251,7 @@ namespace build2
append_options (args, l, var);
};
- process_libraries (l, la, false, lib, opt);
+ process_libraries (sys_lib_dirs, l, la, false, lib, opt);
}
void link::
@@ -1322,7 +1274,7 @@ namespace build2
hash_options (cs, l, var);
};
- process_libraries (l, la, false, lib, opt);
+ process_libraries (sys_lib_dirs, l, la, false, lib, opt);
}
// The name can be an absolute target name (e.g., /tmp/libfoo/lib{foo}) or
@@ -1338,7 +1290,8 @@ namespace build2
resolve_library (name n,
scope& s,
lorder lo,
- optional<dir_paths>& spc) const
+ const dir_paths& sysd,
+ optional<dir_paths>& usrd) const
{
if (n.type != "lib" && n.type != "liba" && n.type != "libs")
fail << "target name " << n << " is not a library";
@@ -1368,7 +1321,7 @@ namespace build2
dir_path out;
prerequisite_key pk {n.proj, {tt, &n.dir, &out, &n.value, ext}, &s};
- xt = search_library (spc, pk, lo);
+ xt = search_library (sysd, usrd, pk, lo);
if (xt == nullptr)
{
@@ -1605,7 +1558,6 @@ namespace build2
// Storage.
//
- string std;
string soname1, soname2;
strings sargs;
@@ -1632,7 +1584,7 @@ namespace build2
{
append_options (args, t, c_coptions);
append_options (args, t, x_coptions);
- append_std (args, rs, t, std);
+ append_std (args);
}
append_options (args, t, c_loptions);
@@ -1809,7 +1761,7 @@ namespace build2
// Ok, so we are updating. Finish building the command line.
//
- string out, out1, out2; // Storage.
+ string out, out1, out2, out3; // Storage.
// Translate paths to relative (to working directory) ones. This results
// in easier to read diagnostics.
@@ -1901,10 +1853,10 @@ namespace build2
//
if (!manifest.empty ())
{
- std = "/MANIFESTINPUT:"; // Repurpose storage for std.
- std += relative (manifest).string ();
+ out3 = "/MANIFESTINPUT:";
+ out3 += relative (manifest).string ();
args.push_back ("/MANIFEST:EMBED");
- args.push_back (std.c_str ());
+ args.push_back (out3.c_str ());
}
if (lt == otype::s)
diff --git a/build2/cc/module b/build2/cc/module
index bed7673..09f5e5a 100644
--- a/build2/cc/module
+++ b/build2/cc/module
@@ -21,6 +21,8 @@ namespace build2
{
namespace cc
{
+ struct compiler_info;
+
class config_module: public module_base, public virtual config_data
{
public:
@@ -28,11 +30,22 @@ namespace build2
config_module (config_data&& d) : config_data (move (d)) {}
void
- init (scope&,
- scope&,
- const location&,
- bool first,
- const variable_map&);
+ init (scope&, const location&, const variable_map&);
+
+ // Translate the x.std value to the standard-selecting option if there
+ // is any.
+ //
+ virtual string
+ translate_std (const compiler_info&, scope&, const string&) const = 0;
+
+ string tstd;
+
+ private:
+ dir_paths
+ gcc_library_search_paths (process_path&, scope&) const; // gcc.cxx
+
+ dir_paths
+ msvc_library_search_paths (process_path&, scope&) const; // msvc.cxx
};
class module: public module_base, protected virtual common,
@@ -47,11 +60,7 @@ namespace build2
install (move (d), *this) {}
void
- init (scope&,
- scope&,
- const location&,
- bool first,
- const variable_map&);
+ init (scope&, const location&, const variable_map&);
};
}
}
diff --git a/build2/cc/module.cxx b/build2/cc/module.cxx
index 76b2b56..7ed8a9d 100644
--- a/build2/cc/module.cxx
+++ b/build2/cc/module.cxx
@@ -27,161 +27,183 @@ namespace build2
namespace cc
{
void config_module::
- init (scope& r,
- scope& b,
- const location& loc,
- bool first,
- const variable_map&)
+ init (scope& rs, const location& loc, const variable_map&)
{
tracer trace (x, "config_init");
- bool cc_loaded (cast_false<bool> (b["cc.core.config.loaded"]));
+ bool cc_loaded (cast_false<bool> (rs["cc.core.config.loaded"]));
// Configure.
//
compiler_info ci; // For program patterns.
- if (first)
+ // 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);
+
+ const variable& config_c_coptions (var_pool["config.cc.coptions"]);
+
+ // 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 == nullptr)
{
- // 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 someone already loaded cc.core.config 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).
//
- if (!cc_loaded)
- config::save_module (r, "cc", 250);
+ path d (cc_loaded
+ ? guess_default (x_lang,
+ cast<string> (rs["cc.id"]),
+ cast_null<string> (rs["cc.pattern"]))
+ : path (x_default));
+
+ // 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.
+ //
+ auto p1 (config::required (rs,
+ config_x,
+ d,
+ false,
+ cc_loaded ? config::save_commented : 0));
+ p.first = &p1.first.get ();
+ p.second = p1.second;
+ }
- config::save_module (r, x, 250);
+ // Figure out which compiler we are dealing with, its target, etc.
+ //
+ const path& xc (cast<path> (*p.first));
+ ci = guess (x_lang,
+ xc,
+ cast_null<strings> (rs[config_c_coptions]),
+ cast_null<strings> (rs[config_x_coptions]));
- const variable& config_c_coptions (var_pool["config.cc.coptions"]);
+ // Translate x_std value (if any) to the compiler option (if any).
+ //
+ if (auto l = rs[x_std])
+ tstd = translate_std (ci, rs, cast<string> (*l));
- // config.x
- //
+ // Extract system library search paths from the compiler.
+ //
+ dir_paths lib_dirs (ci.id.type == "msvc"
+ ? msvc_library_search_paths (ci.path, rs)
+ : gcc_library_search_paths (ci.path, rs));
- // 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 (r, config_x));
+ // 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))
+ {
+ diag_record dr (text);
- if (p.first == nullptr)
{
- // If someone already loaded cc.core.config 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 (cc_loaded
- ? guess_default (x_lang,
- cast<string> (r["cc.id"]),
- cast_null<string> (r["cc.pattern"]))
- : path (x_default));
-
- // 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.
- //
- auto p1 (config::required (r,
- config_x,
- d,
- false,
- cc_loaded ? config::save_commented : 0));
- p.first = &p1.first.get ();
- p.second = p1.second;
+ dr << x << ' ' << project (rs) << '@' << rs.out_path () << '\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';
}
- // Figure out which compiler we are dealing with, its target, etc.
- //
- const path& xc (cast<path> (*p.first));
- ci = guess (x_lang,
- xc,
- cast_null<strings> (r[config_c_coptions]),
- cast_null<strings> (r[config_x_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))
+ if (!ci.version.build.empty ())
{
- diag_record dr (text);
-
- {
- dr << x << ' ' << project (r) << '@' << r.out_path () << '\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';
-
- {
- dr << " signature " << ci.signature << '\n'
- << " target " << ci.target << '\n';
- }
-
- if (!ci.cc_pattern.empty ()) // bin_pattern printed by bin
- dr << " pattern " << ci.cc_pattern << '\n';
-
- {
- dr << " checksum " << ci.checksum;
- }
+ dr << " build " << ci.version.build << '\n';
}
- r.assign (x_path) = move (ci.path);
- r.assign (x_id) = ci.id.string ();
- r.assign (x_id_type) = move (ci.id.type);
- r.assign (x_id_variant) = move (ci.id.variant);
-
- r.assign (x_version) = move (ci.version.string);
- r.assign (x_version_major) = ci.version.major;
- r.assign (x_version_minor) = ci.version.minor;
- r.assign (x_version_patch) = ci.version.patch;
- r.assign (x_version_build) = move (ci.version.build);
+ {
+ dr << " signature " << ci.signature << '\n'
+ << " target " << ci.target << '\n';
+ }
- r.assign (x_signature) = move (ci.signature);
- r.assign (x_checksum) = move (ci.checksum);
+ if (!tstd.empty ())
+ {
+ dr << " std " << tstd << '\n';
+ }
- // Split/canonicalize the target. First see if the user asked us to
- // use config.sub.
- //
- if (ops.config_sub_specified ())
+ if (!ci.cc_pattern.empty ()) // bin_pattern printed by bin
{
- ci.target = run<string> (ops.config_sub (),
- ci.target.c_str (),
- [] (string& l) {return move (l);});
- l5 ([&]{trace << "config.sub target: '" << ci.target << "'";});
+ dr << " pattern " << ci.cc_pattern << '\n';
}
- try
+ if (verb >= 3 && !lib_dirs.empty ())
{
- string canon;
- triplet t (ci.target, canon);
-
- l5 ([&]{trace << "canonical target: '" << canon << "'; "
- << "class: " << t.class_;});
-
- // Enter as x.target.{cpu,vendor,system,version,class}.
- //
- r.assign (x_target) = move (canon);
- r.assign (x_target_cpu) = move (t.cpu);
- r.assign (x_target_vendor) = move (t.vendor);
- r.assign (x_target_system) = move (t.system);
- r.assign (x_target_version) = move (t.version);
- r.assign (x_target_class) = move (t.class_);
+ dr << " lib dirs\n";
+ for (const dir_path& d: lib_dirs)
+ dr << " " << d << '\n';
}
- 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.what () <<
- info << "consider using the --config-sub option";
+ dr << " checksum " << ci.checksum;
}
}
+ rs.assign (x_path) = move (ci.path);
+ rs.assign (x_sys_lib_dirs) = move (lib_dirs);
+
+ rs.assign (x_id) = ci.id.string ();
+ rs.assign (x_id_type) = move (ci.id.type);
+ rs.assign (x_id_variant) = move (ci.id.variant);
+
+ rs.assign (x_version) = move (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) = move (ci.version.build);
+
+ rs.assign (x_signature) = move (ci.signature);
+ rs.assign (x_checksum) = move (ci.checksum);
+
+ // Split/canonicalize the target. First see if the user asked us to
+ // use config.sub.
+ //
+ if (ops.config_sub_specified ())
+ {
+ ci.target = run<string> (ops.config_sub (),
+ ci.target.c_str (),
+ [] (string& l) {return move (l);});
+ l5 ([&]{trace << "config.sub target: '" << ci.target << "'";});
+ }
+
+ try
+ {
+ string canon;
+ triplet t (ci.target, canon);
+
+ l5 ([&]{trace << "canonical target: '" << canon << "'; "
+ << "class: " << t.class_;});
+
+ // Enter as x.target.{cpu,vendor,system,version,class}.
+ //
+ rs.assign (x_target) = move (canon);
+ rs.assign (x_target_cpu) = move (t.cpu);
+ rs.assign (x_target_vendor) = move (t.vendor);
+ rs.assign (x_target_system) = move (t.system);
+ rs.assign (x_target_version) = move (t.version);
+ rs.assign (x_target_class) = move (t.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.what () <<
+ info << "consider using the --config-sub option";
+ }
+
// config.x.{p,c,l}options
// config.x.libs
//
@@ -198,52 +220,49 @@ namespace build2
// using x
// x.coptions += <overriding options> # Note: '+='.
//
- b.assign (x_poptions) += cast_null<strings> (
- config::optional (r, config_x_poptions));
+ rs.assign (x_poptions) += cast_null<strings> (
+ config::optional (rs, config_x_poptions));
- b.assign (x_coptions) += cast_null<strings> (
- config::optional (r, config_x_coptions));
+ rs.assign (x_coptions) += cast_null<strings> (
+ config::optional (rs, config_x_coptions));
- b.assign (x_loptions) += cast_null<strings> (
- config::optional (r, config_x_loptions));
+ rs.assign (x_loptions) += cast_null<strings> (
+ config::optional (rs, config_x_loptions));
- b.assign (x_libs) += cast_null<strings> (
- config::optional (r, config_x_libs));
+ rs.assign (x_libs) += cast_null<strings> (
+ config::optional (rs, config_x_libs));
// Load cc.core.config.
//
if (!cc_loaded)
{
- // Prepare configuration hints. They are only used on the first load
- // of cc.core.config so we only populate them on our first load.
+ // Prepare configuration hints.
//
variable_map h;
- if (first)
- {
- h.assign ("config.cc.id") = cast<string> (r[x_id]);
- h.assign ("config.cc.target") = cast<string> (r[x_target]);
- if (!ci.cc_pattern.empty ())
- h.assign ("config.cc.pattern") = move (ci.cc_pattern);
+ h.assign ("config.cc.id") = cast<string> (rs[x_id]);
+ h.assign ("config.cc.target") = cast<string> (rs[x_target]);
- if (!ci.bin_pattern.empty ())
- h.assign ("config.bin.pattern") = move (ci.bin_pattern);
- }
+ if (!ci.cc_pattern.empty ())
+ h.assign ("config.cc.pattern") = move (ci.cc_pattern);
+
+ if (!ci.bin_pattern.empty ())
+ h.assign ("config.bin.pattern") = move (ci.bin_pattern);
- load_module ("cc.core.config", r, b, loc, false, h);
+ load_module ("cc.core.config", rs, rs, loc, false, h);
}
- else if (first)
+ else
{
// If cc.core.config is already loaded, verify its configuration
// matched ours since it could have been loaded by another c-family
// module.
//
- auto check = [&r, &loc, this](const char* cvar,
+ auto check = [&rs, &loc, this](const char* cvar,
const variable& xvar,
const char* w)
{
- const string& cv (cast<string> (r[cvar]));
- const string& xv (cast<string> (r[xvar]));
+ const string& cv (cast<string> (rs[cvar]));
+ const string& xv (cast<string> (rs[xvar]));
if (cv != xv)
fail (loc) << "cc and " << x << " module " << w << " mismatch" <<
@@ -261,26 +280,22 @@ namespace build2
}
void module::
- init (scope& r,
- scope& b,
- const location& loc,
- bool,
- const variable_map&)
+ 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<bool> (b["cc.core.loaded"]))
- load_module ("cc.core", r, b, loc);
+ if (!cast_false<bool> (rs["cc.core.loaded"]))
+ load_module ("cc.core", rs, rs, loc);
// Register target types and configure their "installability".
//
{
using namespace install;
- auto& t (b.target_types);
+ auto& t (rs.target_types);
t.insert (x_src);
@@ -289,7 +304,7 @@ namespace build2
for (const target_type* const* ht (x_hdr); *ht != nullptr; ++ht)
{
t.insert (**ht);
- install_path (**ht, b, dir_path ("include"));
+ install_path (**ht, rs, dir_path ("include"));
}
}
@@ -298,7 +313,7 @@ namespace build2
{
using namespace bin;
- auto& r (b.rules);
+ auto& r (rs.rules);
// We register for configure so that we detect unresolved imports
// during configuration rather that later, e.g., during update.
@@ -323,7 +338,7 @@ namespace build2
// Only register static object/library rules if the bin.ar module is
// loaded (by us or by the user).
//
- if (cast_false<bool> (b["bin.ar.loaded"]))
+ if (cast_false<bool> (rs["bin.ar.loaded"]))
{
r.insert<obja> (perform_update_id, x_compile, cr);
r.insert<obja> (perform_clean_id, x_compile, cr);
diff --git a/build2/cc/msvc.cxx b/build2/cc/msvc.cxx
index 216bbf2..e4323d4 100644
--- a/build2/cc/msvc.cxx
+++ b/build2/cc/msvc.cxx
@@ -14,7 +14,9 @@
#include <build2/bin/target>
#include <build2/cc/types>
+
#include <build2/cc/link>
+#include <build2/cc/module>
using namespace std;
using namespace butl;
@@ -85,8 +87,8 @@ namespace build2
// Extract system library search paths from MSVC.
//
- void link::
- msvc_library_search_paths (scope&, dir_paths&) const
+ dir_paths config_module::
+ msvc_library_search_paths (process_path&, scope&) const
{
// The linker doesn't seem to have any built-in paths and all of them
// come from the LIB environment variable.
@@ -96,8 +98,9 @@ namespace build2
//
// Should we actually bother? LIB is normally used for system
// libraries and its highly unlikely we will see an explicit import
- // for a library from one of those directories.
+ // for a library from one of those directories. Let's wait and see.
//
+ return dir_paths ();
}
// Inspect the file and determine if it is static or import library.
diff --git a/build2/cc/pkgconfig.cxx b/build2/cc/pkgconfig.cxx
index 2122ea5..eb7f0a6 100644
--- a/build2/cc/pkgconfig.cxx
+++ b/build2/cc/pkgconfig.cxx
@@ -41,12 +41,11 @@ namespace build2
const string* proj,
const string& stem,
const dir_path& libd,
- optional<dir_paths>& sys_sp,
+ const dir_paths& sysd,
lorder lo) const
{
tracer trace (x, "link::pkgconfig_extract");
- assert (sys_sp);
assert (pkgconfig != nullptr);
// Check if we have the pkgconfig/ subdirectory in this library's
@@ -291,15 +290,15 @@ namespace build2
// The reason we do it is the link order. For general libraries it
// shouldn't matter if we imported them via an export stub, direct
// import installed, or via a .pc file (which we could have generated
- // from the export stub). The exception is "system libraries" (which
+ // from the export stub). The exception is "runtime libraries" (which
// are really the extension of libc) such as -lm, -ldl, -lpthread,
// etc. Those we will detect and leave as -l*.
//
- // If we managed to resolve all the -l's (sans system), then we can
+ // If we managed to resolve all the -l's (sans runtime), then we can
// omit -L's for nice and tidy command line.
//
bool all (true);
- optional<dir_paths> sp; // Populate lazily.
+ optional<dir_paths> usrd; // Populate lazily.
for (name& n: libs)
{
@@ -333,15 +332,13 @@ namespace build2
continue;
}
- // Prepare the search paths.
+ // Prepare user search paths by entering the -L paths from the .pc
+ // file.
//
- if (have_L && !sp)
+ if (have_L && !usrd)
{
- sp = dir_paths ();
+ usrd = dir_paths ();
- // First enter the -L paths from the .pc file so that they take
- // precedence.
- //
for (auto i (lops.begin ()); i != lops.end (); ++i)
{
const string& o (*i);
@@ -361,13 +358,9 @@ namespace build2
fail << "relative -L directory in '" << lstr << "'" <<
info << "while parsing pkg-config --libs output of " << f;
- sp->push_back (move (d));
+ usrd->push_back (move (d));
}
}
-
- // Then append system paths.
- //
- sp->insert (sp->end (), sys_sp->begin (), sys_sp->end ());
}
// @@ OUT: for now we assume out is undetermined, just like in
@@ -381,7 +374,7 @@ namespace build2
nullptr, {&lib::static_type, &out, &out, &name, ext}, &s};
if (lib* lt = static_cast<lib*> (
- search_library (have_L ? sp : sys_sp, pk, lo)))
+ search_library (sysd, usrd, pk, lo)))
{
file& f (static_cast<file&> (link_member (*lt, lo)));
l = f.path ().string ();
diff --git a/build2/cxx/init.cxx b/build2/cxx/init.cxx
index e504284..b5de7d9 100644
--- a/build2/cxx/init.cxx
+++ b/build2/cxx/init.cxx
@@ -8,6 +8,7 @@
#include <build2/context>
#include <build2/diagnostics>
+#include <build2/cc/guess>
#include <build2/cc/module>
#include <build2/cxx/target>
@@ -19,24 +20,29 @@ namespace build2
{
namespace cxx
{
- using cc::config_module;
+ using cc::compiler_info;
- class module: public cc::module
+ class config_module: public cc::config_module
{
public:
explicit
- module (data&& d): common (move (d)), cc::module (move (d)) {}
+ config_module (config_data&& d)
+ : config_data (move (d)), cc::config_module (move (d)) {}
- bool
- translate_std (string&, scope&, const value&) const override;
+ string
+ translate_std (const compiler_info&,
+ scope&,
+ const string&) const override;
};
- bool module::
- translate_std (string& s, scope& r, const value& val) const
+ using cc::module;
+
+ string config_module::
+ translate_std (const compiler_info& ci, scope& rs, const string& v) const
{
- const string& v (cast<string> (val));
+ string r;
- if (cid == "msvc")
+ if (ci.id.type == "msvc")
{
// C++ standard-wise, with VC you get what you get. The question is
// whether we should verify that the requested standard is provided by
@@ -49,7 +55,7 @@ namespace build2
//
if (v != "98" && v != "03")
{
- uint64_t cver (cast<uint64_t> (r[x_version_major]));
+ uint64_t cver (ci.version.major);
// @@ Is mapping for 14 and 17 correct? Maybe Update 2 for 14?
//
@@ -57,127 +63,128 @@ namespace build2
(v == "14" && cver < 19) || // C++14 since VS2015/14.0.
(v == "17" && cver < 20)) // C++17 since VS20??/15.0.
{
- fail << "C++" << v << " is not supported by "
- << cast<string> (r[x_signature]) <<
- info << "required by " << project (r) << '@' << r.out_path ();
+ fail << "C++" << v << " is not supported by " << ci.signature <<
+ info << "required by " << project (rs) << '@' << rs.out_path ();
}
}
-
- return false;
}
else
{
// Translate 11 to 0x, 14 to 1y, and 17 to 1z for compatibility with
// older versions of the compilers.
//
- s = "-std=";
+ r = "-std=";
if (v == "98")
- s += "c++98";
+ r += "c++98";
else if (v == "03")
- s += "c++03";
+ r += "c++03";
else if (v == "11")
- s += "c++0x";
+ r += "c++0x";
else if (v == "14")
- s += "c++1y";
+ r += "c++1y";
else if (v == "17")
- s += "c++1z";
+ r += "c++1z";
else
- s += v; // In case the user specifies something like 'gnu++17'.
-
- return true;
+ r += v; // In case the user specifies something like 'gnu++17'.
}
+
+ return r;
}
bool
- config_init (scope& r,
- scope& b,
+ config_init (scope& rs,
+ scope& bs,
const location& loc,
- unique_ptr<module_base>& m,
- bool first,
+ unique_ptr<module_base>& mod,
+ bool,
bool,
const variable_map& hints)
{
tracer trace ("cxx::config_init");
- l5 ([&]{trace << "for " << b.out_path ();});
+ l5 ([&]{trace << "for " << bs.out_path ();});
- if (first)
- {
- // Load cc.core.vars so that we can cache all the cc.* variables.
- //
- if (!cast_false<bool> (b["cc.core.vars.loaded"]))
- load_module ("cc.core.vars", r, b, loc);
+ // We only support root loading (which means there can only be one).
+ //
+ if (&rs != &bs)
+ fail (loc) << "cxx.config module must be loaded in project root";
- // Enter all the variables and initialize the module data.
- //
- auto& v (var_pool);
+ // Load cc.core.vars so that we can cache all the cc.* variables.
+ //
+ if (!cast_false<bool> (rs["cc.core.vars.loaded"]))
+ load_module ("cc.core.vars", rs, rs, loc);
- cc::config_data d {
- cc::lang::cxx,
+ // Enter all the variables and initialize the module data.
+ //
+ auto& v (var_pool);
- "cxx",
- "c++",
- "g++",
+ cc::config_data d {
+ cc::lang::cxx,
- // Note: some overridable, some not.
- //
- v.insert<path> ("config.cxx", true),
- v.insert<strings> ("config.cxx.poptions", true),
- v.insert<strings> ("config.cxx.coptions", true),
- v.insert<strings> ("config.cxx.loptions", true),
- v.insert<strings> ("config.cxx.libs", true),
-
- v.insert<process_path> ("cxx.path"),
- v.insert<strings> ("cxx.poptions"),
- v.insert<strings> ("cxx.coptions"),
- v.insert<strings> ("cxx.loptions"),
- v.insert<strings> ("cxx.libs"),
-
- v["cc.poptions"],
- v["cc.coptions"],
- v["cc.loptions"],
- v["cc.libs"],
-
- v.insert<strings> ("cxx.export.poptions"),
- v.insert<strings> ("cxx.export.coptions"),
- v.insert<strings> ("cxx.export.loptions"),
- v.insert<names> ("cxx.export.libs"),
-
- v["cc.export.poptions"],
- v["cc.export.coptions"],
- v["cc.export.loptions"],
- v["cc.export.libs"],
-
- v["cc.type"],
-
- v.insert<string> ("cxx.std", true),
-
- v.insert<string> ("cxx.id"),
- v.insert<string> ("cxx.id.type"),
- v.insert<string> ("cxx.id.variant"),
-
- v.insert<string> ("cxx.version"),
- v.insert<uint64_t> ("cxx.version.major"),
- v.insert<uint64_t> ("cxx.version.minor"),
- v.insert<uint64_t> ("cxx.version.patch"),
- v.insert<string> ("cxx.version.build"),
-
- v.insert<string> ("cxx.signature"),
- v.insert<string> ("cxx.checksum"),
-
- v.insert<string> ("cxx.target"),
- v.insert<string> ("cxx.target.cpu"),
- v.insert<string> ("cxx.target.vendor"),
- v.insert<string> ("cxx.target.system"),
- v.insert<string> ("cxx.target.version"),
- v.insert<string> ("cxx.target.class")
- };
-
- assert (m == nullptr);
- m.reset (new config_module (move (d)));
- }
+ "cxx",
+ "c++",
+ "g++",
- static_cast<config_module&> (*m).init (r, b, loc, first, hints);
+ // Note: some overridable, some not.
+ //
+ v.insert<path> ("config.cxx", true),
+ v.insert<strings> ("config.cxx.poptions", true),
+ v.insert<strings> ("config.cxx.coptions", true),
+ v.insert<strings> ("config.cxx.loptions", true),
+ v.insert<strings> ("config.cxx.libs", true),
+
+ v.insert<process_path> ("cxx.path"),
+ v.insert<dir_paths> ("cxx.sys_lib_dirs"),
+
+ v.insert<strings> ("cxx.poptions"),
+ v.insert<strings> ("cxx.coptions"),
+ v.insert<strings> ("cxx.loptions"),
+ v.insert<strings> ("cxx.libs"),
+
+ v["cc.poptions"],
+ v["cc.coptions"],
+ v["cc.loptions"],
+ v["cc.libs"],
+
+ v.insert<strings> ("cxx.export.poptions"),
+ v.insert<strings> ("cxx.export.coptions"),
+ v.insert<strings> ("cxx.export.loptions"),
+ v.insert<names> ("cxx.export.libs"),
+
+ v["cc.export.poptions"],
+ v["cc.export.coptions"],
+ v["cc.export.loptions"],
+ v["cc.export.libs"],
+
+ v["cc.type"],
+
+ v.insert<string> ("cxx.std", true),
+
+ v.insert<string> ("cxx.id"),
+ v.insert<string> ("cxx.id.type"),
+ v.insert<string> ("cxx.id.variant"),
+
+ v.insert<string> ("cxx.version"),
+ v.insert<uint64_t> ("cxx.version.major"),
+ v.insert<uint64_t> ("cxx.version.minor"),
+ v.insert<uint64_t> ("cxx.version.patch"),
+ v.insert<string> ("cxx.version.build"),
+
+ v.insert<string> ("cxx.signature"),
+ v.insert<string> ("cxx.checksum"),
+
+ v.insert<string> ("cxx.target"),
+ v.insert<string> ("cxx.target.cpu"),
+ v.insert<string> ("cxx.target.vendor"),
+ v.insert<string> ("cxx.target.system"),
+ v.insert<string> ("cxx.target.version"),
+ v.insert<string> ("cxx.target.class")
+ };
+
+ assert (mod == nullptr);
+ config_module* m;
+ mod.reset (m = new config_module (move (d)));
+ m->init (rs, loc, hints);
return true;
}
@@ -202,51 +209,56 @@ namespace build2
};
bool
- init (scope& r,
- scope& b,
+ init (scope& rs,
+ scope& bs,
const location& loc,
- unique_ptr<module_base>& m,
- bool first,
+ unique_ptr<module_base>& mod,
+ bool,
bool,
const variable_map& hints)
{
tracer trace ("cxx::init");
- l5 ([&]{trace << "for " << b.out_path ();});
+ l5 ([&]{trace << "for " << bs.out_path ();});
+
+ // We only support root loading (which means there can only be one).
+ //
+ if (&rs != &bs)
+ fail (loc) << "cxx module must be loaded in project root";
// Load cxx.config.
//
- if (!cast_false<bool> (b["cxx.config.loaded"]))
- load_module ("cxx.config", r, b, loc, false, hints);
+ if (!cast_false<bool> (rs["cxx.config.loaded"]))
+ load_module ("cxx.config", rs, rs, loc, false, hints);
- if (first)
- {
- config_module& cm (*r.modules.lookup<config_module> ("cxx.config"));
+ config_module& cm (*rs.modules.lookup<config_module> ("cxx.config"));
- cc::data d {
- cm,
+ cc::data d {
+ cm,
- "cxx.compile",
- "cxx.link",
- "cxx.install",
- "cxx.uninstall",
+ "cxx.compile",
+ "cxx.link",
+ "cxx.install",
+ "cxx.uninstall",
- cast<string> (r[cm.x_id]),
- cast<string> (r[cm.x_target]),
- cast<string> (r[cm.x_target_system]),
- cast<string> (r[cm.x_target_class]),
+ cast<string> (rs[cm.x_id]),
+ cast<string> (rs[cm.x_target]),
+ cast<string> (rs[cm.x_target_system]),
+ cast<string> (rs[cm.x_target_class]),
- cast_null<process_path> (r["pkgconfig.path"]),
+ cm.tstd,
- cxx::static_type,
- hdr,
- inc
- };
+ cast_null<process_path> (rs["pkgconfig.path"]),
+ cast<dir_paths> (rs[cm.x_sys_lib_dirs]),
- assert (m == nullptr);
- m.reset (new module (move (d)));
- }
+ cxx::static_type,
+ hdr,
+ inc
+ };
- static_cast<module&> (*m).init (r, b, loc, first, hints);
+ assert (mod == nullptr);
+ module* m;
+ mod.reset (m = new module (move (d)));
+ m->init (rs, loc, hints);
return true;
}
}
diff --git a/build2/pkgconfig/init.cxx b/build2/pkgconfig/init.cxx
index b7100e3..f82e710 100644
--- a/build2/pkgconfig/init.cxx
+++ b/build2/pkgconfig/init.cxx
@@ -30,8 +30,10 @@ namespace build2
tracer trace ("pkgconfig::config_init");
l5 ([&]{trace << "for " << bs.out_path ();});
+ // We only support root loading (which means there can only be one).
+ //
if (&rs != &bs)
- fail (l) << "pkgconfig.config loaded for non-root scope";
+ fail (l) << "pkgconfig.config module must be loaded in project root";
// Enter variables.
//