From 113c43a42d20073428d46c04a1aa1cb305ea12d7 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Sun, 25 Aug 2019 07:09:15 +0200 Subject: Split import into search and load steps This allows us to load things in a separate context. --- libbuild2/file.cxx | 123 ++++++++++++++++++++++++++++++++------------------- libbuild2/file.hxx | 11 +++++ libbuild2/parser.cxx | 4 -- 3 files changed, 89 insertions(+), 49 deletions(-) diff --git a/libbuild2/file.cxx b/libbuild2/file.cxx index 9140e59..7520af2 100644 --- a/libbuild2/file.cxx +++ b/libbuild2/file.cxx @@ -1256,12 +1256,10 @@ namespace build2 return rs; } - names - import (scope& ibase, name target, const location& loc) + pair + import_search (scope& ibase, name target, const location& loc, bool subp) { - tracer trace ("import"); - - l5 ([&]{trace << target << " from " << ibase;}); + tracer trace ("import_search"); // If there is no project specified for this target, then our run will be // short and sweet: we simply return it as empty-project-qualified and @@ -1270,7 +1268,7 @@ namespace build2 if (target.unqualified ()) { target.proj = project_name (); - return names {move (target)}; + return make_pair (move (target), dir_path ()); } context& ctx (ibase.ctx); @@ -1282,7 +1280,7 @@ namespace build2 scope& iroot (*ibase.root_scope ()); - // Figure out this project's out_root. + // Figure out the imported project's out_root. // dir_path out_root; @@ -1322,7 +1320,7 @@ namespace build2 { target.proj = move (proj); l5 ([&]{trace << "skipping " << target;}); - return names {move (target)}; + return make_pair (move (target), dir_path ()); } break; @@ -1380,55 +1378,68 @@ namespace build2 target.dir = p.directory (); target.value = p.leaf ().string (); - return names {move (target)}; + return make_pair (move (target), dir_path ()); } } // Otherwise search subprojects, starting with our root and then trying // outer roots for as long as we are inside an amalgamation. // - for (scope* r (&iroot);; r = r->parent_scope ()->root_scope ()) + if (subp) { - l5 ([&]{trace << "looking in " << *r;}); - - // First check the amalgamation itself. - // - if (r != &iroot && - cast (r->vars[ctx.var_project]) == proj) + for (scope* r (&iroot);; r = r->parent_scope ()->root_scope ()) { - out_root = r->out_path (); - break; - } - - if (auto l = r->vars[ctx.var_subprojects]) - { - const auto& m (cast (l)); - auto i (m.find (proj)); + l5 ([&]{trace << "looking in " << *r;}); - if (i != m.end ()) + // First check the amalgamation itself. + // + if (r != &iroot && + cast (r->vars[ctx.var_project]) == proj) { - const dir_path& d ((*i).second); - out_root = r->out_path () / d; + out_root = r->out_path (); break; } + + if (auto l = r->vars[ctx.var_subprojects]) + { + const auto& m (cast (l)); + auto i (m.find (proj)); + + if (i != m.end ()) + { + const dir_path& d ((*i).second); + out_root = r->out_path () / d; + break; + } + } + + if (!r->vars[ctx.var_amalgamation]) + break; } - if (!r->vars[ctx.var_amalgamation]) - break; + break; } - - break; } - // If we couldn't find the project, convert it back into qualified target - // and return to let someone else (e.g., a rule) take a stab at it. + // Add the qualification back to the target (import_load() will remove it + // again). // - if (out_root.empty ()) - { - target.proj = move (proj); - l5 ([&]{trace << "postponing " << target;}); - return names {move (target)}; - } + target.proj = move (proj); + + return make_pair (move (target), move (out_root)); + } + + pair + import_load (context& ctx, pair x, const location& loc) + { + tracer trace ("import_load"); + + name target (move (x.first)); + dir_path out_root (move (x.second)); + + assert (target.proj); + project_name proj (move (*target.proj)); + target.proj = nullopt; // Bootstrap the imported root scope. This is pretty similar to what we do // in main() except that here we don't try to guess src_root. @@ -1452,11 +1463,13 @@ namespace build2 fwd = (src_root != out_root); } + scope& gs (ctx.global_scope.rw ()); + for (const scope* proot (nullptr); ; proot = root) { bool top (proot == nullptr); - root = &create_root (iroot, out_root, src_root)->second; + root = &create_root (gs, out_root, src_root)->second; bool bstrapped (bootstrapped (*root)); @@ -1539,10 +1552,9 @@ namespace build2 // load_root (*root); - // Create a temporary scope so that the export stub does not mess - // up any of our variables. + // Use a temporary scope so that the export stub doesn't mess anything up. // - temp_scope ts (ibase); + temp_scope ts (gs); // "Pass" the imported project's roots to the stub. // @@ -1576,7 +1588,7 @@ namespace build2 // name? // parser p (ctx); - names v (p.parse_export_stub (ifs, es, iroot, ts)); + names v (p.parse_export_stub (ifs, es, gs, ts)); // If there were no export directive executed in an export stub, assume // the target is not exported. @@ -1585,7 +1597,7 @@ namespace build2 fail (loc) << "target " << target << " is not exported by project " << proj; - return v; + return pair (move (v), *root); } catch (const io_error& e) { @@ -1593,6 +1605,27 @@ namespace build2 } } + names + import (scope& base, name target, const location& loc) + { + tracer trace ("import"); + + l5 ([&]{trace << target << " from " << base;}); + + pair r (import_search (base, move (target), loc)); + + // If we couldn't find the project, return to let someone else (e.g., a + // rule) take a stab at it. + // + if (r.second.empty ()) + { + l5 ([&]{trace << "postponing " << r.first;}); + return names {move (r.first)}; + } + + return import_load (base.ctx, move (r), loc).first; + } + const target* import (context& ctx, const prerequisite_key& pk, bool existing) { diff --git a/libbuild2/file.hxx b/libbuild2/file.hxx index aaa0fa0..009ba14 100644 --- a/libbuild2/file.hxx +++ b/libbuild2/file.hxx @@ -215,9 +215,20 @@ namespace build2 // foo and I see there is a package foo available in repository bar. Wanna, // like, download and use it or something?" // + // Note also that we return names rather than a single name: while normally + // it will be a single target name, it can be an out-qualified pair (if + // someone wants to return a source target) but it can also be a non-target + // since we don't restrict what users can import/export. + // LIBBUILD2_SYMEXPORT names import (scope& base, name, const location&); + LIBBUILD2_SYMEXPORT pair + import_search (scope& base, name, const location&, bool subproj = true); + + LIBBUILD2_SYMEXPORT pair + import_load (context&, pair, const location&); + const target& import (context&, const prerequisite_key&); diff --git a/libbuild2/parser.cxx b/libbuild2/parser.cxx index d346afc..c1787d6 100644 --- a/libbuild2/parser.cxx +++ b/libbuild2/parser.cxx @@ -1823,11 +1823,7 @@ namespace build2 atype = type::append; // Append subsequent values. } else if (atype == type::prepend) - { - // Note: multiple values will be prepended in reverse. - // val->prepend (move (r), var); - } else val->append (move (r), var); } -- cgit v1.1