aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-05-31 16:35:50 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2017-05-31 16:36:49 +0200
commit9ae4897cfe935598333a5f709e967fefc4c161aa (patch)
tree16bfbcb21a10994a29db602f5cb77a0a50627bdf
parentb2fc1fb4a13ffa58640333a3909dd0e53bd21995 (diff)
C++ modules work: add target types
-rw-r--r--build2/bin/init.cxx9
-rw-r--r--build2/bin/rule.cxx14
-rw-r--r--build2/bin/rule.hxx12
-rw-r--r--build2/bin/target.cxx135
-rw-r--r--build2/bin/target.hxx61
-rw-r--r--build2/c/init.cxx3
-rw-r--r--build2/cc/common.hxx10
-rw-r--r--build2/cc/compile.cxx117
-rw-r--r--build2/cc/link.cxx2
-rw-r--r--build2/cc/module.cxx33
-rw-r--r--build2/cc/utility.hxx2
-rw-r--r--build2/cc/utility.ixx14
-rw-r--r--build2/cxx/init.cxx11
-rw-r--r--build2/cxx/target.cxx13
-rw-r--r--build2/cxx/target.hxx15
15 files changed, 346 insertions, 105 deletions
diff --git a/build2/bin/init.cxx b/build2/bin/init.cxx
index 71c77b2..71c580b 100644
--- a/build2/bin/init.cxx
+++ b/build2/bin/init.cxx
@@ -25,6 +25,7 @@ namespace build2
namespace bin
{
static const obj_rule obj_;
+ static const bmi_rule bmi_;
static const lib_rule lib_;
// Default config.bin.*.lib values.
@@ -362,6 +363,11 @@ namespace build2
t.insert<obja> ();
t.insert<objs> ();
+ t.insert<bmi> ();
+ t.insert<bmie> ();
+ t.insert<bmia> ();
+ t.insert<bmis> ();
+
t.insert<lib> ();
t.insert<liba> ();
t.insert<libs> ();
@@ -419,6 +425,9 @@ namespace build2
r.insert<obj> (perform_update_id, "bin.obj", obj_);
r.insert<obj> (perform_clean_id, "bin.obj", obj_);
+ r.insert<bmi> (perform_update_id, "bin.bmi", bmi_);
+ r.insert<bmi> (perform_clean_id, "bin.bmi", bmi_);
+
r.insert<lib> (perform_update_id, "bin.lib", lib_);
r.insert<lib> (perform_clean_id, "bin.lib", lib_);
diff --git a/build2/bin/rule.cxx b/build2/bin/rule.cxx
index 3aa3c81..b6e5a53 100644
--- a/build2/bin/rule.cxx
+++ b/build2/bin/rule.cxx
@@ -31,6 +31,20 @@ namespace build2
recipe obj_rule::
apply (action, target&) const {return empty_recipe;}
+ // bmi
+ //
+ match_result bmi_rule::
+ match (action a, target& t, const string&) const
+ {
+ fail << diag_doing (a, t) << " target group" <<
+ info << "explicitly select bmie{}, bmia{}, or bmis{} member";
+
+ return false;
+ }
+
+ recipe bmi_rule::
+ apply (action, target&) const {return empty_recipe;}
+
// lib
//
// The whole logic is pretty much as if we had our two group members as
diff --git a/build2/bin/rule.hxx b/build2/bin/rule.hxx
index 7109473..4637479 100644
--- a/build2/bin/rule.hxx
+++ b/build2/bin/rule.hxx
@@ -26,6 +26,18 @@ namespace build2
apply (action, target&) const override;
};
+ class bmi_rule: public rule
+ {
+ public:
+ bmi_rule () {}
+
+ virtual match_result
+ match (action, target&, const string&) const override;
+
+ virtual recipe
+ apply (action, target&) const override;
+ };
+
class lib_rule: public rule
{
public:
diff --git a/build2/bin/target.cxx b/build2/bin/target.cxx
index 962befa..f0e0152 100644
--- a/build2/bin/target.cxx
+++ b/build2/bin/target.cxx
@@ -19,27 +19,41 @@ namespace build2
extern const char ext_var[] = "extension"; // VC14 rejects constexpr.
- template <typename T>
+ // obj*{} and bmi*{} member factory.
+ //
+ template <typename M, typename G>
static pair<target*, optional<string>>
- objx_factory (const target_type&,
- dir_path dir,
- dir_path out,
- string n,
- optional<string> ext)
+ m_factory (const target_type&,
+ dir_path dir,
+ dir_path out,
+ string n,
+ optional<string> ext)
{
- const obj* g (targets.find<obj> (dir, out, n));
+ const G* g (targets.find<G> (dir, out, n));
- T* x (new T (move (dir), move (out), move (n)));
- x->group = g;
+ M* m (new M (move (dir), move (out), move (n)));
+ m->group = g;
- return make_pair (x, move (ext));
+ return make_pair (m, move (ext));
}
const target_type obje::static_type
{
"obje",
&file::static_type,
- &objx_factory<obje>,
+ &m_factory<obje, obj>,
+ &target_extension_var<ext_var, nullptr>,
+ &target_pattern_var<ext_var, nullptr>,
+ nullptr,
+ &target_search, // Note: not _file(); don't look for an existing file.
+ false
+ };
+
+ const target_type bmie::static_type
+ {
+ "bmie",
+ &file::static_type,
+ &m_factory<bmie, bmi>,
&target_extension_var<ext_var, nullptr>,
&target_pattern_var<ext_var, nullptr>,
nullptr,
@@ -51,7 +65,19 @@ namespace build2
{
"obja",
&file::static_type,
- &objx_factory<obja>,
+ &m_factory<obja, obj>,
+ &target_extension_var<ext_var, nullptr>,
+ &target_pattern_var<ext_var, nullptr>,
+ nullptr,
+ &target_search, // Note: not _file(); don't look for an existing file.
+ false
+ };
+
+ const target_type bmia::static_type
+ {
+ "bmia",
+ &file::static_type,
+ &m_factory<bmia, bmi>,
&target_extension_var<ext_var, nullptr>,
&target_pattern_var<ext_var, nullptr>,
nullptr,
@@ -63,7 +89,7 @@ namespace build2
{
"objs",
&file::static_type,
- &objx_factory<objs>,
+ &m_factory<objs, obj>,
&target_extension_var<ext_var, nullptr>,
&target_pattern_var<ext_var, nullptr>,
nullptr,
@@ -71,39 +97,54 @@ namespace build2
false
};
+ const target_type bmis::static_type
+ {
+ "bmis",
+ &file::static_type,
+ &m_factory<bmis, bmi>,
+ &target_extension_var<ext_var, nullptr>,
+ &target_pattern_var<ext_var, nullptr>,
+ nullptr,
+ &target_search, // Note: not _file(); don't look for an existing file.
+ false
+ };
+
+ // obj{} and bmi{} group factory.
+ //
+ template <typename G, typename E, typename A, typename S>
static pair<target*, optional<string>>
- obj_factory (const target_type&,
- dir_path dir,
- dir_path out,
- string n,
- optional<string> ext)
+ g_factory (const target_type&,
+ dir_path dir,
+ dir_path out,
+ string n,
+ optional<string> ext)
{
// Casts are MT-aware (during serial load).
//
- obje* e (phase == run_phase::load
- ? const_cast<obje*> (targets.find<obje> (dir, out, n))
- : nullptr);
- obja* a (phase == run_phase::load
- ? const_cast<obja*> (targets.find<obja> (dir, out, n))
- : nullptr);
- objs* s (phase == run_phase::load
- ? const_cast<objs*> (targets.find<objs> (dir, out, n))
- : nullptr);
+ E* e (phase == run_phase::load
+ ? const_cast<E*> (targets.find<E> (dir, out, n))
+ : nullptr);
+ A* a (phase == run_phase::load
+ ? const_cast<A*> (targets.find<A> (dir, out, n))
+ : nullptr);
+ S* s (phase == run_phase::load
+ ? const_cast<S*> (targets.find<S> (dir, out, n))
+ : nullptr);
- obj* o (new obj (move (dir), move (out), move (n)));
+ G* g (new G (move (dir), move (out), move (n)));
- if (e != nullptr) e->group = o;
- if (a != nullptr) a->group = o;
- if (s != nullptr) s->group = o;
+ if (e != nullptr) e->group = g;
+ if (a != nullptr) a->group = g;
+ if (s != nullptr) s->group = g;
- return make_pair (o, move (ext));
+ return make_pair (g, move (ext));
}
const target_type obj::static_type
{
"obj",
&target::static_type,
- &obj_factory,
+ &g_factory<obj, obje, obja, objs>,
nullptr,
nullptr,
nullptr,
@@ -111,21 +152,17 @@ namespace build2
false
};
- template <typename T>
- static pair<target*, optional<string>>
- libx_factory (const target_type&,
- dir_path dir,
- dir_path out,
- string n,
- optional<string> ext)
+ const target_type bmi::static_type
{
- const lib* g (targets.find<lib> (dir, out, n));
-
- T* x (new T (move (dir), move (out), move (n)));
- x->group = g;
-
- return make_pair (x, move (ext));
- }
+ "bmi",
+ &target::static_type,
+ &g_factory<bmi, bmie, bmia, bmis>,
+ nullptr,
+ nullptr,
+ nullptr,
+ &target_search,
+ false
+ };
// What extensions should we use? At the outset, this is platform-
// dependent. And if we consider cross-compilation, is it build or
@@ -141,7 +178,7 @@ namespace build2
{
"liba",
&file::static_type,
- &libx_factory<liba>,
+ &m_factory<liba, lib>,
&target_extension_var<ext_var, nullptr>,
&target_pattern_var<ext_var, nullptr>,
nullptr,
@@ -153,7 +190,7 @@ namespace build2
{
"libs",
&file::static_type,
- &libx_factory<libs>,
+ &m_factory<libs, lib>,
&target_extension_var<ext_var, nullptr>,
&target_pattern_var<ext_var, nullptr>,
nullptr,
diff --git a/build2/bin/target.hxx b/build2/bin/target.hxx
index d920cc1..13d7596 100644
--- a/build2/bin/target.hxx
+++ b/build2/bin/target.hxx
@@ -56,6 +56,67 @@ namespace build2
virtual const target_type& dynamic_type () const {return static_type;}
};
+ // Binary module interface.
+ //
+ // While currently there are only C++ modules, if things pan out, chances
+ // are we will have C (or Obj-C) modules. And in that case it is plausible
+ // we will also have some binutils to examine BMIs, similar to objdump,
+ // etc. So that's why this target type is in bin and not cxx.
+ //
+ // bmi*{} is similar to obj*{} though the semantics is a bit different:
+ // the idea is that we should try hard to re-use a single bmiX{} file for
+ // an entire "build" but if that's not possible (because the compilation
+ // options are too different), then compile a private version for
+ // ourselves (the definition of "too different" is, of course, compiler-
+ // specific).
+ //
+ // When we compile a module interface unit, we end up with bmi*{} and
+ // obj*{}. How that obj*{} is produced is compiler-dependent. While it
+ // makes sense to decouple the production of the two in order to increase
+ // parallelism, doing so will further complicate the already hairy
+ // organization. So, at least for now, we produce the two at the same time
+ // and make obj*{} an ad hoc member of bmi*{}.
+ //
+ class bmie: public file
+ {
+ public:
+ using file::file;
+
+ public:
+ static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
+ };
+
+ class bmia: public file
+ {
+ public:
+ using file::file;
+
+ public:
+ static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
+ };
+
+ class bmis: public file
+ {
+ public:
+ using file::file;
+
+ public:
+ static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
+ };
+
+ class bmi: public target
+ {
+ public:
+ using target::target;
+
+ public:
+ static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
+ };
+
// The lib{} target group.
//
class liba: public file
diff --git a/build2/c/init.cxx b/build2/c/init.cxx
index b4b2bca..00482a7 100644
--- a/build2/c/init.cxx
+++ b/build2/c/init.cxx
@@ -262,13 +262,14 @@ namespace build2
cm.tstd,
- false, // No C modules for now.
+ false, // No C modules yet.
cast_null<process_path> (rs["pkgconfig.path"]),
cast<dir_paths> (rs[cm.x_sys_lib_dirs]),
cast<dir_paths> (rs[cm.x_sys_inc_dirs]),
c::static_type,
+ nullptr, // No C modules yet.
hdr,
inc
};
diff --git a/build2/cc/common.hxx b/build2/cc/common.hxx
index 155d670..7d520d0 100644
--- a/build2/cc/common.hxx
+++ b/build2/cc/common.hxx
@@ -120,7 +120,8 @@ namespace build2
const dir_paths& sys_lib_dirs; // x.sys_lib_dirs
const dir_paths& sys_inc_dirs; // x.sys_inc_dirs
- const target_type& x_src; // Source target type (c{}, cxx{}).
+ const target_type& x_src; // Source target type (c{}, cxx{}).
+ const target_type* x_mod; // Module target type (mxx{}), if any.
// Array of target types that are considered headers. Keep them in the
// most likely to appear order and terminate with NULL.
@@ -156,11 +157,12 @@ namespace build2
const process_path& path,
const target_triplet& tg,
const strings& std,
- bool mod,
+ bool fm,
const process_path* pkgc,
const dir_paths& sld,
const dir_paths& sid,
const target_type& src,
+ const target_type* mod,
const target_type* const* hdr,
const target_type* const* inc)
: config_data (cd),
@@ -171,9 +173,9 @@ namespace build2
cid (id), cvar (var), cmaj (mj), cmin (mi), cpath (path),
ctg (tg), tsys (ctg.system), tclass (ctg.class_),
tstd (std),
- modules (mod),
+ modules (fm),
pkgconfig (pkgc), sys_lib_dirs (sld), sys_inc_dirs (sid),
- x_src (src), x_hdr (hdr), x_inc (inc) {}
+ x_src (src), x_mod (mod), x_hdr (hdr), x_inc (inc) {}
};
class common: protected data
diff --git a/build2/cc/compile.cxx b/build2/cc/compile.cxx
index c7fc3ea..e5f23c4 100644
--- a/build2/cc/compile.cxx
+++ b/build2/cc/compile.cxx
@@ -56,9 +56,13 @@ namespace build2
struct match_data
{
explicit
- match_data (const prerequisite_member& s)
- : src (s), pp (preprocessed::none), mt (timestamp_unknown) {}
+ match_data (bool m, const prerequisite_member& s)
+ : mod (m),
+ src (s),
+ pp (preprocessed::none),
+ mt (timestamp_unknown) {}
+ bool mod; // Target is bmi*{} and src is x_mod.
prerequisite_member src;
preprocessed pp;
auto_rmfile psrc; // Preprocessed source, if any.
@@ -73,29 +77,28 @@ namespace build2
{
tracer trace (x, "compile::match");
- // @@ TODO:
- //
- // - check prerequisites: single source file
- // - if path already assigned, verify extension?
- //
+ bool mod (t.is_a<bmie> () || t.is_a<bmia> () || t.is_a<bmis> ());
- // Link-up to our group (this is the obj{} target group protocol which
- // means this can be done whether we match or not).
+ // Link-up to our group (this is the obj/bmi{} target group protocol
+ // which means this can be done whether we match or not).
//
if (t.group == nullptr)
- t.group = targets.find<obj> (t.dir, t.out, t.name);
+ {
+ const target_type& tt (mod ? bmi::static_type : obj::static_type);
+ t.group = targets.find (tt, t.dir, t.out, t.name);
+ }
// See if we have a source file. Iterate in reverse so that a source
- // file specified for an obj*{} member overrides the one specified for
- // the group. Also "see through" groups.
+ // file specified for a member overrides the one specified for the
+ // group. Also "see through" groups.
//
for (prerequisite_member p: reverse_group_prerequisite_members (act, t))
{
- if (p.is_a (x_src))
+ if (p.is_a (mod ? *x_mod : x_src))
{
// Save in the target's auxilary storage.
//
- t.data (match_data (p));
+ t.data (match_data (mod, p));
return true;
}
}
@@ -312,57 +315,82 @@ namespace build2
{
tracer trace (x, "compile::apply");
- file& t (xt.as<file> ());
+ file& t (xt.as<file> ()); // Either obj*{} or bmi*{}.
+
match_data& md (t.data<match_data> ());
+ bool mod (md.mod);
const scope& bs (t.base_scope ());
const scope& rs (*bs.root_scope ());
- otype ct (compile_type (t));
+ otype ct (compile_type (t, mod));
lorder lo (link_order (bs, ct));
// Derive file name from target name.
//
- const char* e (nullptr);
+ string e; // In case of a module, this is the object file extension.
if (tsys == "win32-msvc")
{
switch (ct)
{
- case otype::e: e = "exe.obj"; break;
- case otype::a: e = "lib.obj"; break;
- case otype::s: e = "dll.obj"; break;
+ case otype::e: e = "exe."; break;
+ case otype::a: e = "lib."; break;
+ case otype::s: e = "dll."; break;
}
}
else if (tsys == "mingw32")
{
switch (ct)
{
- case otype::e: e = "exe.o"; break;
- case otype::a: e = "a.o"; break;
- case otype::s: e = "dll.o"; break;
+ case otype::e: e = "exe."; break;
+ case otype::a: e = "a."; break;
+ case otype::s: e = "dll."; break;
}
}
else if (tsys == "darwin")
{
switch (ct)
{
- case otype::e: e = "o"; break;
- case otype::a: e = "a.o"; break;
- case otype::s: e = "dylib.o"; break;
+ case otype::e: e = ""; break;
+ case otype::a: e = "a."; break;
+ case otype::s: e = "dylib."; break;
}
}
else
{
switch (ct)
{
- case otype::e: e = "o"; break;
- case otype::a: e = "a.o"; break;
- case otype::s: e = "so.o"; break;
+ case otype::e: e = ""; break;
+ case otype::a: e = "a."; break;
+ case otype::s: e = "so."; break;
+ }
+ }
+
+ switch (cid)
+ {
+ case compiler_id::gcc:
+ {
+ if (mod) e += "nms.";
+ e += "o";
+ break;
+ }
+ case compiler_id::clang:
+ {
+ if (mod) e += "pcm.";
+ e += "o";
+ break;
+ }
+ case compiler_id::msvc:
+ case compiler_id::icc:
+ {
+ if (mod) e += "ifc.";
+ e += (tsys == "win32-msvc" ? "obj" : "o");
+ break;
}
}
- const path& tp (t.derive_path (e));
+ const path& tp (t.derive_path (e.c_str ()));
// Inject dependency on the output directory.
//
@@ -2206,7 +2234,26 @@ namespace build2
throw failed ();
}
- //@@ TODO: if bmi{}, make sure module_name is not empty.
+ // Sanity checks.
+ //
+ if (modules)
+ {
+ // If we are compiling a module interface unit, make sure it has the
+ // necessary declarations.
+ //
+ if (src.is_a (*x_mod))
+ {
+ // VC is not (yet) using the 'export module' syntax so use the
+ // preprequisite type to distinguish between interface and
+ // implementation units.
+ //
+ if (cid == compiler_id::msvc)
+ tu.module_interface = true;
+
+ if (tu.module_name.empty () || !tu.module_interface)
+ fail << src << " is not a module interface unit";
+ }
+ }
if (tu.module_name.empty () && tu.module_imports.empty ())
return;
@@ -2228,12 +2275,16 @@ namespace build2
{
const file& t (xt.as<file> ());
const path& tp (t.path ());
+
match_data md (move (t.data<match_data> ()));
+ bool mod (md.mod);
// While all our prerequisites are already up-to-date, we still have
// to execute them to keep the dependency counts straight.
//
- auto pr (execute_prerequisites<file> (x_src, act, t, md.mt));
+ auto pr (
+ execute_prerequisites<file> (
+ (mod ? *x_mod : x_src), act, t, md.mt));
if (pr.first)
{
@@ -2246,7 +2297,7 @@ namespace build2
const scope& bs (t.base_scope ());
const scope& rs (*bs.root_scope ());
- otype ct (compile_type (t));
+ otype ct (compile_type (t, mod));
lorder lo (link_order (bs, ct));
cstrings args {cpath.recall_string ()};
diff --git a/build2/cc/link.cxx b/build2/cc/link.cxx
index 5c75d34..0d2a14f 100644
--- a/build2/cc/link.cxx
+++ b/build2/cc/link.cxx
@@ -641,7 +641,7 @@ namespace build2
p1.is_a<lib> () ||
p1.is_a<liba> () ||
p1.is_a<libs> () ||
- (p.is_a (x_src) && x_header (p1)) ||
+ (p.is_a (x_src) && x_header (p1)) || // Includes x_mod.
(p.is_a<c> () && p1.is_a<h> ()))
continue;
diff --git a/build2/cc/module.cxx b/build2/cc/module.cxx
index cdc45e5..3755817 100644
--- a/build2/cc/module.cxx
+++ b/build2/cc/module.cxx
@@ -348,6 +348,8 @@ namespace build2
t.insert (x_src);
+ // Note: module (x_mod) is in x_hdr.
+
for (const target_type* const* ht (x_hdr); *ht != nullptr; ++ht)
{
t.insert (**ht);
@@ -376,22 +378,37 @@ namespace build2
r.insert<obje> (perform_clean_id, x_compile, cr);
r.insert<obje> (configure_update_id, x_compile, cr);
- r.insert<exe> (perform_update_id, x_link, lr);
- r.insert<exe> (perform_clean_id, x_link, lr);
- r.insert<exe> (configure_update_id, x_link, lr);
-
r.insert<obja> (perform_update_id, x_compile, cr);
r.insert<obja> (perform_clean_id, x_compile, cr);
r.insert<obja> (configure_update_id, x_compile, cr);
- r.insert<liba> (perform_update_id, x_link, lr);
- r.insert<liba> (perform_clean_id, x_link, lr);
- r.insert<liba> (configure_update_id, x_link, lr);
-
r.insert<objs> (perform_update_id, x_compile, cr);
r.insert<objs> (perform_clean_id, x_compile, cr);
r.insert<objs> (configure_update_id, x_compile, cr);
+ if (modules)
+ {
+ r.insert<bmie> (perform_update_id, x_compile, cr);
+ r.insert<bmie> (perform_clean_id, x_compile, cr);
+ r.insert<bmie> (configure_update_id, x_compile, cr);
+
+ r.insert<bmia> (perform_update_id, x_compile, cr);
+ r.insert<bmia> (perform_clean_id, x_compile, cr);
+ r.insert<bmia> (configure_update_id, x_compile, cr);
+
+ r.insert<bmis> (perform_update_id, x_compile, cr);
+ r.insert<bmis> (perform_clean_id, x_compile, cr);
+ r.insert<bmis> (configure_update_id, x_compile, cr);
+ }
+
+ r.insert<exe> (perform_update_id, x_link, lr);
+ r.insert<exe> (perform_clean_id, x_link, lr);
+ r.insert<exe> (configure_update_id, x_link, lr);
+
+ r.insert<liba> (perform_update_id, x_link, lr);
+ r.insert<liba> (perform_clean_id, x_link, lr);
+ r.insert<liba> (configure_update_id, x_link, lr);
+
r.insert<libs> (perform_update_id, x_link, lr);
r.insert<libs> (perform_clean_id, x_link, lr);
r.insert<libs> (configure_update_id, x_link, lr);
diff --git a/build2/cc/utility.hxx b/build2/cc/utility.hxx
index e0529af..11abf90 100644
--- a/build2/cc/utility.hxx
+++ b/build2/cc/utility.hxx
@@ -22,7 +22,7 @@ namespace build2
// Compile/link output type.
//
otype
- compile_type (const target&);
+ compile_type (const target&, bool module);
otype
link_type (const target&);
diff --git a/build2/cc/utility.ixx b/build2/cc/utility.ixx
index bc9cd05..b15791a 100644
--- a/build2/cc/utility.ixx
+++ b/build2/cc/utility.ixx
@@ -7,20 +7,24 @@ namespace build2
namespace cc
{
inline otype
- compile_type (const target& t)
+ compile_type (const target& t, bool mod)
{
+ using namespace bin;
+
return
- t.is_a<bin::obje> () ? otype::e :
- t.is_a<bin::obja> () ? otype::a :
+ t.is_a (mod ? bmie::static_type : obje::static_type) ? otype::e :
+ t.is_a (mod ? bmia::static_type : obja::static_type) ? otype::a :
otype::s;
}
inline otype
link_type (const target& t)
{
+ using namespace bin;
+
return
- t.is_a<exe> () ? otype::e :
- t.is_a<bin::liba> () ? otype::a :
+ t.is_a<exe> () ? otype::e :
+ t.is_a<liba> () ? otype::a :
otype::s;
}
}
diff --git a/build2/cxx/init.cxx b/build2/cxx/init.cxx
index fde12e3..a5422d2 100644
--- a/build2/cxx/init.cxx
+++ b/build2/cxx/init.cxx
@@ -375,19 +375,21 @@ namespace build2
static const target_type* const hdr[] =
{
&hxx::static_type,
+ &h::static_type,
&ixx::static_type,
&txx::static_type,
- &h::static_type,
+ &mxx::static_type,
nullptr
};
static const target_type* const inc[] =
{
&hxx::static_type,
+ &h::static_type,
&ixx::static_type,
&txx::static_type,
+ &mxx::static_type,
&cxx::static_type,
- &h::static_type,
&c::static_type,
nullptr
};
@@ -414,6 +416,8 @@ namespace build2
if (!cast_false<bool> (rs["cxx.config.loaded"]))
load_module (rs, rs, "cxx.config", loc, false, hints);
+ bool modules (cast<bool> (rs["cxx.features.modules"]));
+
config_module& cm (*rs.modules.lookup<config_module> ("cxx.config"));
cc::data d {
@@ -433,13 +437,14 @@ namespace build2
cm.tstd,
- cast<bool> (rs["cxx.features.modules"]),
+ modules,
cast_null<process_path> (rs["pkgconfig.path"]),
cast<dir_paths> (rs[cm.x_sys_lib_dirs]),
cast<dir_paths> (rs[cm.x_sys_inc_dirs]),
cxx::static_type,
+ modules ? &mxx::static_type : nullptr,
hdr,
inc
};
diff --git a/build2/cxx/target.cxx b/build2/cxx/target.cxx
index 7fb9971..5641e7a 100644
--- a/build2/cxx/target.cxx
+++ b/build2/cxx/target.cxx
@@ -63,5 +63,18 @@ namespace build2
&file_search,
false
};
+
+ extern const char mxx_ext_def[] = "mxx";
+ const target_type mxx::static_type
+ {
+ "mxx",
+ &cc::static_type,
+ &target_factory<mxx>,
+ &target_extension_var<ext_var, mxx_ext_def>,
+ &target_pattern_var<ext_var, mxx_ext_def>,
+ nullptr,
+ &file_search,
+ false
+ };
}
}
diff --git a/build2/cxx/target.hxx b/build2/cxx/target.hxx
index 4dd93e3..f5591d1 100644
--- a/build2/cxx/target.hxx
+++ b/build2/cxx/target.hxx
@@ -57,6 +57,21 @@ namespace build2
static const target_type static_type;
virtual const target_type& dynamic_type () const {return static_type;}
};
+
+ // The module interface unit is both like a header (e.g., we need to
+ // install it) and like a source (we need to compile it). Plus, to
+ // support dual use (modules/headers) it could actually be #include'd
+ // (and in both cases).
+ //
+ class mxx: public cc::cc
+ {
+ public:
+ using cc::cc;
+
+ public:
+ static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
+ };
}
}