From b37f1aa6398065be806e6605a023189685669885 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 15 Feb 2017 03:55:15 +0200 Subject: Implement parallel match --- build2/cc/common.cxx | 198 +++++++++++++++++++++++++++------------------------ 1 file changed, 104 insertions(+), 94 deletions(-) (limited to 'build2/cc/common.cxx') diff --git a/build2/cc/common.cxx b/build2/cc/common.cxx index 7b8499c..88eb45d 100644 --- a/build2/cc/common.cxx +++ b/build2/cc/common.cxx @@ -46,6 +46,7 @@ namespace build2 // void common:: process_libraries ( + action act, const scope& top_bs, lorder top_lo, const dir_paths& top_sysd, @@ -174,13 +175,14 @@ namespace build2 // if (self && proc_lib) { - const string& p (l.path ().string ()); + const path& p (l.path ()); + assert (!p.empty ()); // Must be assigned. bool s (t != nullptr // If cc library (matched or imported). ? cast_false (l.vars[c_system]) - : sys (top_sysd, p)); + : sys (top_sysd, p.string ())); - proc_lib (&l, p, s); + proc_lib (&l, p.string (), s); } const scope& bs (t == nullptr || cc ? top_bs : l.base_scope ()); @@ -224,7 +226,7 @@ namespace build2 if (sysd == nullptr) find_sysd (); if (!lo) find_lo (); - process_libraries (bs, *lo, *sysd, + process_libraries (act, bs, *lo, *sysd, *f, a, proc_impl, proc_lib, proc_opt, true); } @@ -262,7 +264,7 @@ namespace build2 &proc_impl, &proc_lib, &proc_opt, &sysd, &usrd, &find_sysd, &find_lo, &sys, &sys_simple, - &bs, &lo, this] (const lookup& lu) + &bs, act, &lo, this] (const lookup& lu) { const vector* ns (cast_null> (lu)); if (ns == nullptr || ns->empty ()) @@ -287,7 +289,7 @@ namespace build2 if (sysd == nullptr) find_sysd (); if (!lo) find_lo (); - const file& t (resolve_library (bs, n, *lo, *sysd, usrd)); + const file& t (resolve_library (act, bs, n, *lo, *sysd, usrd)); if (proc_lib) { @@ -300,7 +302,7 @@ namespace build2 // on Windows import-installed DLLs may legally have empty // paths. // - if (t.mtime (false) == timestamp_unknown) + if (t.mtime () == timestamp_unknown) fail << "interface dependency " << t << " is out of date" << info << "mentioned in *.export.libs of target " << l << info << "is it a prerequisite of " << l << "?"; @@ -308,7 +310,7 @@ namespace build2 // Process it recursively. // - process_libraries (bs, *lo, *sysd, + process_libraries (act, bs, *lo, *sysd, t, t.is_a (), proc_impl, proc_lib, proc_opt, true); } @@ -386,7 +388,8 @@ namespace build2 // that's the only way to guarantee it will be up-to-date. // const file& common:: - resolve_library (const scope& s, + resolve_library (action act, + const scope& s, name n, lorder lo, const dir_paths& sysd, @@ -422,7 +425,7 @@ namespace build2 // dir_path out; prerequisite_key pk {n.proj, {tt, &n.dir, &out, &n.value, ext}, &s}; - xt = search_library_existing (sysd, usrd, pk); + xt = search_library_existing (act, sysd, usrd, pk); if (xt == nullptr) { @@ -437,17 +440,41 @@ namespace build2 // If this is lib{}, pick appropriate member. // if (const lib* l = xt->is_a ()) - xt = &link_member (*l, lo); // Pick liba{} or libs{}. + xt = &link_member (*l, act, lo); // Pick liba{} or libs{}. return xt->as (); } - // Note that pk's scope should not be NULL (even if dir is absolute). If - // sys is not NULL, then store there an inidication of whether this is a - // system library. + // Insert a target verifying that it already exists if requested. Return + // the lock. + // + template + ulock common:: + insert_library (T*& r, + const string& name, + const dir_path& d, + optional ext, + bool exist, + tracer& trace) + { + auto p (targets.insert_locked (T::static_type, + d, + dir_path (), + name, + move (ext), + true, // Implied. + trace)); + + assert (!exist || !p.second.owns_lock ()); + r = &p.first.template as (); + return move (p.second); + } + + // Note that pk's scope should not be NULL (even if dir is absolute). // target* common:: - search_library (const dir_paths& sysd, + search_library (action act, + const dir_paths& sysd, optional& usrd, const prerequisite_key& p, bool exist) const @@ -546,31 +573,11 @@ namespace build2 path f; // Reuse the buffer. const dir_path* pd (nullptr); - // Insert a target verifying that it already exists if requested. - // - auto insert = [&name, exist, &trace] (auto*& r, - const dir_path& d, - optional ext) - { - using T = typename std::remove_reference::type; - - auto p (targets.insert (T::static_type, - d, - dir_path (), - name, - move (ext), - true, // Implied. - trace)); - - assert (!exist || !p.second); - r = &p.first.template as (); - }; - auto search =[&a, &s, &an, &ae, &sn, &se, &name, ext, - &p, &f, &insert, exist, this] (const dir_path& d) -> bool + &p, &f, exist, &trace, this] (const dir_path& d) -> bool { timestamp mt; @@ -593,17 +600,22 @@ namespace build2 // if (tclass == "windows") { - insert (s, d, nullopt); + libi* i (nullptr); + insert_library (i, name, d, se, exist, trace); + + ulock l (insert_library (s, name, d, nullopt, exist, trace)); - if (s->member == nullptr) + if (!exist) { - libi* i; - insert (i, d, se); + if (l.owns_lock ()) + s->member = i; + else + assert (s->member == i); - if (i->path ().empty ()) - i->path (move (f)); + l.unlock (); i->mtime (mt); + i->path (move (f)); // Presumably there is a DLL somewhere, we just don't know // where (and its possible we might have to look for one if we @@ -612,17 +624,15 @@ namespace build2 // but valid timestamp (aka "trust me, it's there"). // s->mtime (mt); - s->member = i; + s->path (path ()); } } else { - insert (s, d, se); - - if (s->path ().empty ()) - s->path (move (f)); + insert_library (s, name, d, se, exist, trace); s->mtime (mt); + s->path (move (f)); } } else if (!ext && tsys == "mingw32") @@ -639,12 +649,10 @@ namespace build2 if (mt != timestamp_nonexistent) { - insert (s, d, se); - - if (s->path ().empty ()) - s->path (move (f)); + insert_library (s, name, d, se, exist, trace); s->mtime (mt); + s->path (move (f)); } } } @@ -666,12 +674,9 @@ namespace build2 // Note that this target is outside any project which we treat // as out trees. // - insert (a, d, ae); - - if (a->path ().empty ()) - a->path (move (f)); - + insert_library (a, name, d, ae, exist, trace); a->mtime (mt); + a->path (move (f)); } } @@ -727,29 +732,44 @@ namespace build2 if (pd == nullptr) return nullptr; - // Enter (or find) the lib{} target group. Note that we must be careful - // here since its possible we have already imported some of its members. + // Enter (or find) the lib{} target group. // lib* lt; - insert (lt, *pd, l ? p.tk.ext : nullopt); + insert_library (lt, name, *pd, l ? p.tk.ext : nullopt, exist, trace); - // It should automatically link-up to the members we have found. + // Result. // - assert (a == nullptr || lt->a == a); - assert (s == nullptr || lt->s == s); + target* r (l ? lt : (p.is_a () ? static_cast (a) : s)); + + // Assume the rest is already done if existing. + // + if (exist) + return r; - // Update the bin.lib variable to indicate what's available. Assume - // already done if existing. + // If we cannot acquire the lock then this mean the target has already + // been matched (though not clear by whom) and we assume all of this + // has already been done. // - if (!exist) + target_lock ll (lock (act, *lt)); + + // Set lib{} group members to indicate what's available. Note that we + // must be careful here since its possible we have already imported some + // of its members. + // + if (ll) { - const char* bl (lt->a != nullptr - ? (lt->s != nullptr ? "both" : "static") - : "shared"); - lt->assign (var_pool["bin.lib"]) = bl; + if (a != nullptr) lt->a = a; + if (s != nullptr) lt->s = s; } - target* r (l ? lt : (p.is_a () ? static_cast (a) : s)); + target_lock al (a != nullptr ? lock (act, *a) : target_lock ()); + target_lock sl (s != nullptr ? lock (act, *s) : target_lock ()); + + if (!al) a = nullptr; + if (!sl) s = nullptr; + + if (a != nullptr) a->group = lt; + if (s != nullptr) s->group = lt; // Mark as a "cc" library (unless already marked) and set the system // flag. @@ -769,24 +789,16 @@ namespace build2 return p.second; }; - // If the library already has cc.type, then assume it was either already - // imported or was matched by a rule. - // - // Assume already done if existing. + // If the library already has cc.type, then assume it was either + // already imported or was matched by a rule. // - if (!exist) - { - if (a != nullptr && !mark_cc (*a)) - a = nullptr; - - if (s != nullptr && !mark_cc (*s)) - s = nullptr; - } + if (a != nullptr && !mark_cc (*a)) a = nullptr; + if (s != nullptr && !mark_cc (*s)) s = nullptr; // Add the "using static/shared library" macro (used, for example, to - // handle DLL export). The absence of either of these macros would mean - // some other build system that cannot distinguish between the two (and - // no pkg-config information). + // handle DLL export). The absence of either of these macros would + // mean some other build system that cannot distinguish between the + // two (and no pkg-config information). // auto add_macro = [this] (target& t, const char* suffix) { @@ -832,17 +844,15 @@ namespace build2 } }; - // Assume already done if existing. - // - if (!exist && (a != nullptr || s != nullptr)) + if (ll && (a != nullptr || s != nullptr)) { - // Try to extract library information from pkg-config. We only add the - // default macro if we could not extract more precise information. The - // idea is that when we auto-generate .pc files, we will copy those - // macros (or custom ones) from *.export.poptions. + // Try to extract library information from pkg-config. We only add + // the default macro if we could not extract more precise + // information. The idea is that when we auto-generate .pc files, we + // will copy those macros (or custom ones) from *.export.poptions. // - if (pkgconfig == nullptr || - !pkgconfig_extract (*p.scope, *lt, a, s, p.proj, name, *pd, sysd)) + if (pkgconfig == nullptr || !pkgconfig_extract ( + act, *p.scope, *lt, a, s, p.proj, name, *pd, sysd)) { if (a != nullptr) add_macro (*a, "STATIC"); if (s != nullptr) add_macro (*s, "SHARED"); -- cgit v1.1