From 9ae4897cfe935598333a5f709e967fefc4c161aa Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 31 May 2017 16:35:50 +0200 Subject: C++ modules work: add target types --- build2/cc/common.hxx | 10 +++-- build2/cc/compile.cxx | 117 ++++++++++++++++++++++++++++++++++++-------------- build2/cc/link.cxx | 2 +- build2/cc/module.cxx | 33 ++++++++++---- build2/cc/utility.hxx | 2 +- build2/cc/utility.ixx | 14 +++--- 6 files changed, 126 insertions(+), 52 deletions(-) (limited to 'build2/cc') 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 () || t.is_a () || t.is_a ()); - // 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 (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& t (xt.as ()); // Either obj*{} or bmi*{}. + match_data& md (t.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 ()); const path& tp (t.path ()); + match_data md (move (t.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 (x_src, act, t, md.mt)); + auto pr ( + execute_prerequisites ( + (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 () || p1.is_a () || p1.is_a () || - (p.is_a (x_src) && x_header (p1)) || + (p.is_a (x_src) && x_header (p1)) || // Includes x_mod. (p.is_a () && p1.is_a ())) 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 (perform_clean_id, x_compile, cr); r.insert (configure_update_id, x_compile, cr); - r.insert (perform_update_id, x_link, lr); - r.insert (perform_clean_id, x_link, lr); - r.insert (configure_update_id, x_link, lr); - r.insert (perform_update_id, x_compile, cr); r.insert (perform_clean_id, x_compile, cr); r.insert (configure_update_id, x_compile, cr); - r.insert (perform_update_id, x_link, lr); - r.insert (perform_clean_id, x_link, lr); - r.insert (configure_update_id, x_link, lr); - r.insert (perform_update_id, x_compile, cr); r.insert (perform_clean_id, x_compile, cr); r.insert (configure_update_id, x_compile, cr); + if (modules) + { + r.insert (perform_update_id, x_compile, cr); + r.insert (perform_clean_id, x_compile, cr); + r.insert (configure_update_id, x_compile, cr); + + r.insert (perform_update_id, x_compile, cr); + r.insert (perform_clean_id, x_compile, cr); + r.insert (configure_update_id, x_compile, cr); + + r.insert (perform_update_id, x_compile, cr); + r.insert (perform_clean_id, x_compile, cr); + r.insert (configure_update_id, x_compile, cr); + } + + r.insert (perform_update_id, x_link, lr); + r.insert (perform_clean_id, x_link, lr); + r.insert (configure_update_id, x_link, lr); + + r.insert (perform_update_id, x_link, lr); + r.insert (perform_clean_id, x_link, lr); + r.insert (configure_update_id, x_link, lr); + r.insert (perform_update_id, x_link, lr); r.insert (perform_clean_id, x_link, lr); r.insert (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 () ? otype::e : - t.is_a () ? 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 () ? otype::e : - t.is_a () ? otype::a : + t.is_a () ? otype::e : + t.is_a () ? otype::a : otype::s; } } -- cgit v1.1