diff options
Diffstat (limited to 'build2/cc/link.cxx')
-rw-r--r-- | build2/cc/link.cxx | 269 |
1 files changed, 135 insertions, 134 deletions
diff --git a/build2/cc/link.cxx b/build2/cc/link.cxx index d8ccc0e..0c3534c 100644 --- a/build2/cc/link.cxx +++ b/build2/cc/link.cxx @@ -1007,6 +1007,10 @@ namespace build2 // *.export.libs is up-to-date (which will happen automatically if it is // listed as a prerequisite of this library). // + // Storing a reference to library path in proc_lib is legal (it comes + // either from the target's path or from one of the *.libs variables + // neither of which should change on this run). + // void link:: process_libraries ( scope& top_bs, @@ -1020,17 +1024,51 @@ namespace build2 const string& path, // Library path. bool sys)>& proc_lib, // True if system library. const function<void (file&, - const string& type, // cc.type - bool com, // cc. or x. - bool exp)>& proc_opt) const // *.export. + const string& type, // cc.type + bool com, // cc. or x. + bool exp)>& proc_opt, // *.export. + bool self /*= false*/) const // Call proc_lib on l? { - bool impl (proc_impl && proc_impl (l, la)); + // Determine if an absolute path is to a system library. Note that + // we assume both paths to be normalized. + // + auto sys = [] (const dir_paths& sysd, const string& p) -> bool + { + size_t pn (p.size ()); + + for (const dir_path& d: sysd) + { + const string& ds (d.string ()); // Can be "/", otherwise no slash. + size_t dn (ds.size ()); + + if (pn > dn && + p.compare (0, dn, ds) == 0 && + (path::traits::is_separator (ds[dn - 1]) || + path::traits::is_separator (p[dn]))) + return true; + } + + return false; + }; // See what type of library this is (C, C++, etc). Use it do decide // which x.libs variable name to use. If it's unknown, then we only // look into prerequisites. // const string* t (cast_null<string> (l.vars[c_type])); + + if (self && proc_lib) + { + const string& p (l.path ().string ()); + + bool s (t != nullptr // If cc library (matched or imported). + ? cast_false<bool> (l.vars[c_system]) + : sys (top_sysd, p)); + + proc_lib (&l, p, s); + } + + bool impl (proc_impl && proc_impl (l, la)); bool cc, same; auto& vp (var_pool); @@ -1066,47 +1104,28 @@ namespace build2 } } + scope& bs (t == nullptr || cc ? top_bs : l.base_scope ()); + optional<lorder> lo; // Calculate lazily. + const dir_paths* sysd (nullptr); // Resolve lazily. + // Find system search directories corresponding to this library, i.e., // from its project and for its type (C, C++, etc). // - auto find_sysd = [&top_sysd, this] ( - bool cc, bool same, const string& t, scope& bs) -> const dir_paths& + auto find_sysd = [&top_sysd, t, cc, same, &bs, &sysd, this] () { // Use the search dirs corresponding to this library scope/type. // - return cc - ? top_sysd // Imported library, use importer's sysd. - : cast<dir_paths> ( + sysd = (t == nullptr || cc) + ? &top_sysd // Imported library, use importer's sysd. + : &cast<dir_paths> ( bs.root_scope ()->vars[same ? x_sys_lib_dirs - : var_pool[t + ".sys_lib_dirs"]]); + : var_pool[*t + ".sys_lib_dirs"]]); }; - auto find_lo = [top_lo, this] (file& l, bool cc, scope& bs) -> lorder + auto find_lo = [top_lo, t, cc, &bs, &l, &lo, this] () { - return cc ? top_lo : link_order (bs, link_type (l)); - }; - - // Determine if an absolute path is to a system library. Note that - // we assume both paths to be normalized. - // - auto sys = [] (const dir_paths& sysd, const string& p) -> bool - { - size_t pn (p.size ()); - - for (const dir_path& d: sysd) - { - const string& ds (d.string ()); // Can be "/", otherwise no slash. - size_t dn (ds.size ()); - - if (pn > dn && - p.compare (0, dn, ds) == 0 && - (path::traits::is_separator (ds[dn - 1]) || - path::traits::is_separator (p[dn]))) - return true; - } - - return false; + lo = (t == nullptr || cc) ? top_lo : link_order (bs, link_type (l)); }; // Only go into prerequisites (implementation) if instructed and we are @@ -1123,23 +1142,12 @@ namespace build2 if ((a = (f = p->is_a<liba> ()) != nullptr) || (f = p->is_a<libs> ()) != nullptr) { - if (proc_lib) - { - const string& p (f->path ().string ()); - proc_lib (f, p, sys (top_sysd, p)); - } - - const string& t (cast<string> (f->vars[c_type])); // Must be there. - bool cc (t == "cc"); - bool same (!cc && t == x); - - scope& bs (cc ? top_bs : f->base_scope ()); + if (sysd == nullptr) find_sysd (); + if (!lo) find_lo (); - process_libraries (bs, - find_lo (*f, cc, bs), - find_sysd (cc, same, t, bs), + process_libraries (bs, *lo, *sysd, *f, a, - proc_impl, proc_lib, proc_opt); + proc_impl, proc_lib, proc_opt, true); } } } @@ -1153,22 +1161,17 @@ namespace build2 if (t == nullptr) return; - scope& bs (cc ? top_bs : l.base_scope ()); - optional<lorder> lo; // Calculate lazily. - const dir_paths* sysd (nullptr); // Resolve lazily. optional<dir_paths> usrd; // Extract lazily. // Determine if a "simple path" is a system library. // - auto sys_simple = [cc, same, t, &bs, &sysd, &sys, &find_sysd] ( - const string& p) -> bool + auto sys_simple = [&sysd, &sys, &find_sysd] (const string& p) -> bool { bool s (!path::traits::absolute (p)); if (!s) { - if (sysd == nullptr) - sysd = &find_sysd (cc, same, *t, bs); + if (sysd == nullptr) find_sysd (); s = sys (*sysd, p); } @@ -1176,7 +1179,7 @@ namespace build2 return s; }; - auto proc_int = [&l, cc, same, t, + auto proc_int = [&l, &proc_impl, &proc_lib, &proc_opt, &sysd, &usrd, &find_sysd, &find_lo, &sys, &sys_simple, @@ -1202,11 +1205,8 @@ namespace build2 { // This is a potentially project-qualified target. // - if (sysd == nullptr) - sysd = &find_sysd (cc, same, *t, bs); - - if (!lo) - lo = find_lo (l, cc, bs); + if (sysd == nullptr) find_sysd (); + if (!lo) find_lo (); file& t (resolve_library (n, bs, *lo, *sysd, usrd)); @@ -1217,25 +1217,21 @@ namespace build2 // library's prerequisites (i.e., it is not an implementation // dependency). // - if (t.path ().empty ()) - fail << "target " << t << " is out of date" << + // Note that we used to just check for path being assigned but + // on Windows import-installed DLLs may legally have empty + // paths. + // + if (t.mtime (false) == 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 << "?"; - - const string& p (t.path ().string ()); - - bool s (t.vars[c_type] // If cc library (matched or imported). - ? cast_false<bool> (t.vars[c_system]) - : sys (*sysd, p)); - - proc_lib (&t, p, s); } // Process it recursively. // process_libraries (bs, *lo, *sysd, t, t.is_a<liba> (), - proc_impl, proc_lib, proc_opt); + proc_impl, proc_lib, proc_opt, true); } } }; @@ -1376,11 +1372,25 @@ namespace build2 file& l, bool la, scope& bs, lorder lo) const { + bool win (tclass == "windows"); + auto imp = [] (file&, bool la) {return la;}; - auto lib = [&args] (file* f, const string& p, bool) + auto lib = [&args, win] (file* f, const string& p, bool) { - args.push_back (f != nullptr ? relative (f->path ()).string () : p); + if (f != nullptr) + { + // On Windows a shared library is a DLL with the import library as a + // first ad hoc group member. MinGW though can link directly to DLLs + // (see search_library() for details). + // + if (win && f->member != nullptr && f->is_a<libs> ()) + f = static_cast<file*> (f->member); + + args.push_back (relative (f->path ()).string ()); + } + else + args.push_back (p); }; auto opt = [&args, this] (file& l, const string& t, bool com, bool exp) @@ -1400,17 +1410,31 @@ namespace build2 } }; - process_libraries (bs, lo, sys_lib_dirs, l, la, imp, lib, opt); + process_libraries (bs, lo, sys_lib_dirs, l, la, imp, lib, opt, true); } void link:: hash_libraries (sha256& cs, file& l, bool la, scope& bs, lorder lo) const { + bool win (tclass == "windows"); + auto imp = [] (file&, bool la) {return la;}; - auto lib = [&cs] (file*, const string& p, bool) + auto lib = [&cs, win] (file* f, const string& p, bool) { - cs.append (p); + if (f != nullptr) + { + // On Windows a shared library is a DLL with the import library as a + // first ad hoc group member. MinGW though can link directly to DLLs + // (see search_library() for details). + // + if (win && f->member != nullptr && f->is_a<libs> ()) + f = static_cast<file*> (f->member); + + cs.append (f->path ().string ()); + } + else + cs.append (p); }; auto opt = [&cs, this] (file& l, const string& t, bool com, bool exp) @@ -1428,13 +1452,12 @@ namespace build2 } }; - process_libraries (bs, lo, sys_lib_dirs, l, la, imp, lib, opt); + process_libraries (bs, lo, sys_lib_dirs, l, la, imp, lib, opt, true); } void link:: rpath_libraries (strings& args, - file& l, bool la, - scope& bs, lorder lo, + target& t, scope& bs, lorder lo, bool for_install) const { // Use -rpath-link on targets that support it (Linux, FreeBSD). Note @@ -1445,14 +1468,6 @@ namespace build2 if (tclass != "linux" && tclass != "freebsd") return; } - else if (!la) - { - // Top-level sharen library dependency. It is either matched or - // imported so should be a cc library. - // - if (!cast_false<bool> (l.vars[c_system])) - args.push_back ("-Wl,-rpath," + l.path ().directory ().string ()); - } auto imp = [for_install] (file&, bool la) { @@ -1532,16 +1547,30 @@ namespace build2 d.args.push_back (move (o)); }; - process_libraries (bs, lo, sys_lib_dirs, l, la, imp, lib, nullptr); - } + for (target* pt: t.prerequisite_targets) + { + file* f; + liba* a; - // See windows-rpath.cxx. - // - timestamp - windows_rpath_timestamp (file&); + if ((f = a = pt->is_a<liba> ()) || + (f = pt->is_a<libs> ())) + { + if (!for_install && a == nullptr) + { + // Top-level sharen library dependency. It is either matched or + // imported so should be a cc library. + // + if (!cast_false<bool> (f->vars[c_system])) + args.push_back ( + "-Wl,-rpath," + f->path ().directory ().string ()); + } - void - windows_rpath_assembly (file&, const string& cpu, timestamp, bool scratch); + process_libraries (bs, lo, sys_lib_dirs, + *f, a != nullptr, + imp, lib, nullptr); + } + } + } // Filter link.exe noise (msvc.cxx). // @@ -1585,7 +1614,7 @@ namespace build2 // it if we are updating for install. // if (!for_install) - rpath_timestamp = windows_rpath_timestamp (t); + rpath_timestamp = windows_rpath_timestamp (t, bs, lo); path mf ( windows_manifest ( @@ -1828,15 +1857,7 @@ namespace build2 // rpath of the imported libraries (i.e., we assume they are also // installed). But we add -rpath-link for some platforms. // - for (target* pt: t.prerequisite_targets) - { - file* f; - liba* a; - - if ((f = a = pt->is_a<liba> ()) || - (f = pt->is_a<libs> ())) - rpath_libraries (sargs, *f, a != nullptr, bs, lo, for_install); - } + rpath_libraries (sargs, t, bs, lo, for_install); if (auto l = t["bin.rpath"]) for (const dir_path& p: cast<dir_paths> (l)) @@ -1882,23 +1903,13 @@ namespace build2 ((f = a = pt->is_a<liba> ()) || (f = s = pt->is_a<libs> ())))) { - // On Windows a shared library is a DLL with the import library as - // a first ad hoc group member. MinGW though can link directly to - // DLLs (see search_library() for details). - // - if (s != nullptr && tclass == "windows") - { - if (s->member != nullptr) - f = static_cast<file*> (s->member); - } - - cs.append (f->path ().string ()); - - // Link all the dependent interface libraries (shared) or - // interface and implementation (static), recursively. + // Link all the dependent interface libraries (shared) or interface + // and implementation (static), recursively. // if (a != nullptr || s != nullptr) hash_libraries (cs, *f, a != nullptr, bs, lo); + else + cs.append (f->path ().string ()); } } @@ -2118,23 +2129,13 @@ namespace build2 ((f = a = pt->is_a<liba> ()) || (f = s = pt->is_a<libs> ())))) { - // On Windows a shared library is a DLL with the import library as a - // first ad hoc group member. MinGW though can link directly to DLLs - // (see search_library() for details). - // - if (s != nullptr && tclass == "windows") - { - if (s->member != nullptr) - f = static_cast<file*> (s->member); - } - - sargs.push_back (relative (f->path ()).string ()); // string()&& - // Link all the dependent interface libraries (shared) or interface // and implementation (static), recursively. // if (a != nullptr || s != nullptr) append_libraries (sargs, *f, a != nullptr, bs, lo); + else + sargs.push_back (relative (f->path ()).string ()); // string()&& } } @@ -2256,7 +2257,7 @@ namespace build2 if (lt == otype::e && tclass == "windows") { if (!for_install) - windows_rpath_assembly (t, + windows_rpath_assembly (t, bs, lo, cast<string> (rs[x_target_cpu]), rpath_timestamp, scratch); |