From 074a8c04a384a9752466bd2af69b695333b2955c Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 29 Nov 2017 17:44:48 +0200 Subject: Reimplement module sidebuilding using an ad hoc subproject --- build2/cc/compile.cxx | 112 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 82 insertions(+), 30 deletions(-) (limited to 'build2/cc/compile.cxx') diff --git a/build2/cc/compile.cxx b/build2/cc/compile.cxx index fef7eb6..0ab9bfc 100644 --- a/build2/cc/compile.cxx +++ b/build2/cc/compile.cxx @@ -7,6 +7,7 @@ #include // exit() #include // strlen() +#include #include #include #include @@ -15,6 +16,7 @@ #include #include +#include // create_project() #include #include // h @@ -3692,15 +3694,12 @@ namespace build2 tracer trace (x, "compile::make_module_sidebuild"); // First figure out where we are going to build. We want to avoid - // multiple sidebuilds so the outermost scope that has loaded the module - // capable of compiling things and that is within our amalgmantion seems - // like a good place. + // multiple sidebuilds so the outermost scope that has loaded the + // cc.config module and that is within our amalgmantion seems like a + // good place. // - // @@ TODO: this is actually pretty restrictive: we need cxx and with - // modules enabled! Which means things like bpkg configurations won't - // work (only loads cc.config). - // - const scope* as (bs.root_scope ()); + const scope& rs (*bs.root_scope ()); + const scope* as (&rs); { const scope* ws (as->weak_scope ()); if (as != ws) @@ -3710,14 +3709,82 @@ namespace build2 { s = s->parent_scope ()->root_scope (); - const module* m (s->modules.lookup ("cxx")); - if (m != nullptr && m->modules) + // Use cc.core.vars as a proxy for {c,cxx}.config (a bit smelly). + // + if (cast_false ((*s)["cc.core.vars.loaded"])) as = s; } while (s != ws); } } + // We build modules in a subproject (since there might be no full + // language support module loaded in the amalgamation, only *.config). + // So the first step is to check if the project has already been created + // and/or loaded and if not, then to go ahead and do so. + // + dir_path pd (as->out_path ()); + pd /= "build"; + pd /= "cc"; + pd /= "modules"; + pd /= x; + { + const scope* ps (&scopes.find (pd)); + + if (ps->out_path () != pd) + { + // Switch the phase to load then create and load the subproject. + // + phase_switch phs (run_phase::load); + + // Re-test again now that we are in exclusive phase (another thread + // could have already created and loaded the subproject). + // + ps = &scopes.find (pd); + + if (ps->out_path () != pd) + { + // The project might already be created in which case we just need + // to load it. + // + if (!is_src_root (pd)) + { + // Copy our standard and force modules. + // + string extra; + + if (const string* std = cast_null (rs[x_std])) + extra += string (x) + ".std = " + *std + '\n'; + + extra += string (x) + ".features.modules = true"; + + dir_path ad (((dir_path ("..") /= "..") /= "..") /= ".."); + + config::create_project (pd, + ad, /* amalgamation */ + {}, /* boot_modules */ + extra, /* root_pre */ + {string (x) + '.'}, /* root_modules */ + "", /* root_post */ + false, /* config */ + false, /* buildfile */ + "the cc module", + 2); /* verbosity */ + } + + ps = &load_project (as->rw () /* lock */, pd, pd); + } + } + + // Some sanity checks. + // +#ifndef NDEBUG + assert (ps->root ()); + const module* m (ps->modules.lookup (x)); + assert (m != nullptr && m->modules); +#endif + } + // Next we need to come up with a file/target name that will be unique // enough not to conflict with other modules. If we assume that within // an amalgamation there is only one "version" of each module, then the @@ -3729,13 +3796,6 @@ namespace build2 back_inserter (mf), [] (char c) {return c == '.' ? '-' : c;}); - // Store the BMI target in the build//modules/ subdirectory. - // - dir_path md (as->out_path ()); - md /= "build"; - md /= x; - md /= "modules"; - // It seems natural to build a BMI type that corresponds to the library // type. After all, this is where the object file part of the BMI is // going to come from (though things will probably be different for @@ -3749,27 +3809,19 @@ namespace build2 case otype::e: assert (false); } - // If the target already exists then we assume all this is already done - // (otherwise why would someone have created such a target). + // Store the BMI target in the subproject root. If the target already + // exists then we assume all this is already done (otherwise why would + // someone have created such a target). // if (const target* bt = targets.find ( *tt, - md, + pd, dir_path (), // Always in the out tree. mf, nullopt, // Use default extension. trace)) return *bt; - // Make sure the output directory exists. This is not strictly necessary - // if out != src since inject_fsdir() will take care of it. For out == - // src we initially tried to add an explicit fsdir{} preprequisite but - // that didn't work out since this is a nested directory. So now we keep - // it simple and just create it. The proper way to handle this as well - // as cleanup is probably at the cxx module level, which is @@ TODO. - // - mkdir_p (md, 3); - prerequisites ps; ps.push_back (prerequisite (mt)); @@ -3794,7 +3846,7 @@ namespace build2 } auto p (targets.insert_locked (*tt, - move (md), + move (pd), dir_path (), // Always in the out tree. move (mf), nullopt, // Use default extension. -- cgit v1.1