aboutsummaryrefslogtreecommitdiff
path: root/build2/cc
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 /build2/cc
parentb2fc1fb4a13ffa58640333a3909dd0e53bd21995 (diff)
C++ modules work: add target types
Diffstat (limited to 'build2/cc')
-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
6 files changed, 126 insertions, 52 deletions
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;
}
}