diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2016-08-27 16:37:12 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2016-08-27 16:37:12 +0200 |
commit | 457f83ee501ba8f9a6a576de741e43ff9dfef039 (patch) | |
tree | dfb64944e3aef2666454b070169bc6b14227ed12 | |
parent | 9b8320565fe3a0197d1217792f1705f67e773082 (diff) |
Fix rpath-link
-rw-r--r-- | build2/cc/compile.cxx | 9 | ||||
-rw-r--r-- | build2/cc/link | 2 | ||||
-rw-r--r-- | build2/cc/link.cxx | 152 |
3 files changed, 96 insertions, 67 deletions
diff --git a/build2/cc/compile.cxx b/build2/cc/compile.cxx index 20cd392..10171ed 100644 --- a/build2/cc/compile.cxx +++ b/build2/cc/compile.cxx @@ -72,6 +72,9 @@ namespace build2 auto opt = [&args, this] (file& l, const string& t, bool com, bool exp) { + // Note that in our model *.export.poptions are always "interface", + // even if set on liba{}/libs{}, unlike loptions. + // assert (exp); const variable& var ( @@ -83,7 +86,7 @@ namespace build2 }; link_.process_libraries ( - sys_lib_dirs, l, l.is_a<liba> (), true, nullptr, opt); + sys_lib_dirs, l, l.is_a<liba> (), nullptr, nullptr, opt); } void compile:: @@ -104,7 +107,7 @@ namespace build2 }; link_.process_libraries ( - sys_lib_dirs, l, l.is_a<liba> (), true, nullptr, opt); + sys_lib_dirs, l, l.is_a<liba> (), nullptr, nullptr, opt); } recipe compile:: @@ -464,7 +467,7 @@ namespace build2 }; link_.process_libraries ( - sys_lib_dirs, l, l.is_a<liba> (), true, nullptr, opt); + sys_lib_dirs, l, l.is_a<liba> (), nullptr, nullptr, opt); } auto compile:: diff --git a/build2/cc/link b/build2/cc/link index a12ed5d..8c85343 100644 --- a/build2/cc/link +++ b/build2/cc/link @@ -43,7 +43,7 @@ namespace build2 process_libraries (const dir_paths&, file&, bool, - bool, + const function<bool (file&, bool)>&, const function<void (file*, const string&, bool)>&, const function<void (file&, const string&, diff --git a/build2/cc/link.cxx b/build2/cc/link.cxx index b6cc9fa..0f7a525 100644 --- a/build2/cc/link.cxx +++ b/build2/cc/link.cxx @@ -999,12 +999,9 @@ namespace build2 } } - // Recursively process prerequisite libraries. Only interface - // (*.export.libs) for shared libraries, interface and implementation - // (both prerequisite and from *.libs, unless overriden) for static - // libraries (unless iface_only is true, in which case we use - // *.export.libs even for static libraries which means *.export.libs - // should be set on lib{}, not libs{}). + // Recursively process prerequisite libraries. If proc_impl returns false, + // then only process interface (*.export.libs), otherwise -- interface and + // implementation (prerequisite and from *.libs, unless overriden). // // Note that here we assume that an interface library is also an // implementation (since we don't use *.export.libs in static link). We @@ -1017,7 +1014,8 @@ namespace build2 const dir_paths& top_sysd, file& l, bool la, - bool iface_only, + const function<bool (file&, + bool la)>& proc_impl, // Implementation? const function<void (file*, // Can be NULL. const string& path, // Library path. bool sys)>& proc_lib, // True if system library. @@ -1026,6 +1024,8 @@ namespace build2 bool com, // cc. or x. bool exp)>& proc_opt) const // *.export. { + bool impl (proc_impl && proc_impl (l, la)); + // 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. @@ -1037,17 +1037,16 @@ namespace build2 if (t != nullptr) { - // If static, then the explicit export override should be set on the - // liba{} target itself. Note also that we only check for *.libs. If - // one doesn't have any libraries but needs to set, say, *.loptions, - // then *.libs should be set to NULL or empty (this is why we check - // for result being defined). - // - // @@ Should we set it in import installed then? + // The explicit export override should be set on the liba/libs{} + // target itself. Note also that we only check for *.libs. If one + // doesn't have any libraries but needs to set, say, *.loptions, then + // *.libs should be set to NULL or empty (this is why we check for + // the result being defined). // - c_e_libs = la && !iface_only - ? l.vars[c_export_libs] - : l[c_export_libs]; + if (impl) + c_e_libs = l.vars[c_export_libs]; // Override. + else if (l.group != nullptr) // lib{} group. + c_e_libs = l.group->vars[c_export_libs]; if (*t != "cc") { @@ -1055,7 +1054,10 @@ namespace build2 ? x_export_libs : var_pool[*t + ".export.libs"]); - x_e_libs = la && !iface_only ? l.vars[var] : l[var]; + if (impl) + x_e_libs = l.vars[var]; // Override. + else if (l.group != nullptr) // lib{} group. + x_e_libs = l.group->vars[var]; } } @@ -1106,12 +1108,11 @@ namespace build2 return false; }; - // Only go into prerequisites (implementation dependencies) if this is a - // static library and it's not using explicit export. For shared library - // or if iface_only, we are only interested in interface dependencies - // which come from the *.export.libs below. + // Only go into prerequisites (implementation) if instructed and it's + // not using explicit export. Otherwise, interface dependencies come + // from the lib{}:*.export.libs below. // - if (la && !iface_only && !c_e_libs.defined () && !x_e_libs.defined ()) + if (impl && !c_e_libs.defined () && !x_e_libs.defined ()) { for (target* p: l.prerequisite_targets) { @@ -1128,8 +1129,8 @@ namespace build2 } process_libraries (find_sysd (*f, nullptr, nullptr), - *f, a, iface_only, - proc_lib, proc_opt); + *f, a, + proc_impl, proc_lib, proc_opt); } } } @@ -1137,6 +1138,13 @@ namespace build2 // Process libraries (recursively) from *.export.libs (of type names) // handling import, etc. // + + // If it is not a C-common library, then it probably doesn't have any of + // the *.libs and we are done. + // + if (t == nullptr) + return; + scope* bs (nullptr); // Resolve lazily. optional<lorder> lo; // Calculate lazily. const dir_paths* sysd (nullptr); // Resolve lazily. @@ -1163,8 +1171,8 @@ namespace build2 return s; }; - auto proc_int = [&l, la, t, iface_only, - &proc_lib, &proc_opt, + auto proc_int = [&l, la, t, + &proc_impl, &proc_lib, &proc_opt, &sysd, &usrd, &sys_simple, &sys, &find_sysd, &bs, &lo, this] (const lookup& lu) { @@ -1225,7 +1233,7 @@ namespace build2 // Process it recursively. // process_libraries ( - *sysd, t, t.is_a<liba> (), iface_only, proc_lib, proc_opt); + *sysd, t, t.is_a<liba> (), proc_impl, proc_lib, proc_opt); } } }; @@ -1247,13 +1255,7 @@ namespace build2 } }; - // If it is not a C-common library, then it probably doesn't have any of - // the *.libs and we are done. - // - if (t == nullptr) - return; - - // If all we know it's a C-common library, then in both cases we only + // If all we know is it's a C-common library, then in both cases we only // look for cc.export.libs. // if (*t == "cc") @@ -1266,10 +1268,10 @@ namespace build2 bool same (*t == x); // Same as us. auto& vp (var_pool); - if (la && !iface_only) + if (impl) { - // Static: as discussed above, here we can have two situations: - // explicit export or default export. + // Interface and implementation: as discussed above, we can have two + // situations: overriden export or default export. // if (c_e_libs.defined () || x_e_libs.defined ()) { @@ -1297,8 +1299,7 @@ namespace build2 } else { - // Shared or iface_only: only add *.export.* (interface - // dependencies). + // Interface: only add *.export.* (interface dependencies). // if (proc_opt) proc_opt (l, *t, true, true); if (c_e_libs) proc_int (c_e_libs); @@ -1374,6 +1375,8 @@ namespace build2 void link:: append_libraries (strings& args, file& l, bool la) const { + auto imp = [] (file&, bool la) {return la;}; + auto lib = [&args] (file* f, const string& p, bool) { args.push_back (f != nullptr ? relative (f->path ()).string () : p); @@ -1381,22 +1384,29 @@ namespace build2 auto opt = [&args, this] (file& l, const string& t, bool com, bool exp) { - const variable& var ( - com - ? (exp ? c_export_loptions : c_loptions) - : (t == x - ? (exp ? x_export_loptions : x_loptions) - : var_pool[t + (exp ? ".export.loptions" : ".loptions")])); - - append_options (args, l, var); + // If we need an interface value, then use the group (lib{}). + // + if (target* g = exp && l.is_a<libs> () ? l.group : &l) + { + const variable& var ( + com + ? (exp ? c_export_loptions : c_loptions) + : (t == x + ? (exp ? x_export_loptions : x_loptions) + : var_pool[t + (exp ? ".export.loptions" : ".loptions")])); + + append_options (args, *g, var); + } }; - process_libraries (sys_lib_dirs, l, la, false, lib, opt); + process_libraries (sys_lib_dirs, l, la, imp, lib, opt); } void link:: hash_libraries (sha256& cs, file& l, bool la) const { + auto imp = [] (file&, bool la) {return la;}; + auto lib = [&cs] (file*, const string& p, bool) { cs.append (p); @@ -1404,17 +1414,20 @@ namespace build2 auto opt = [&cs, this] (file& l, const string& t, bool com, bool exp) { - const variable& var ( - com - ? (exp ? c_export_loptions : c_loptions) - : (t == x - ? (exp ? x_export_loptions : x_loptions) - : var_pool[t + (exp ? ".export.loptions" : ".loptions")])); - - hash_options (cs, l, var); + if (target* g = exp && l.is_a<libs> () ? l.group : &l) + { + const variable& var ( + com + ? (exp ? c_export_loptions : c_loptions) + : (t == x + ? (exp ? x_export_loptions : x_loptions) + : var_pool[t + (exp ? ".export.loptions" : ".loptions")])); + + hash_options (cs, *g, var); + } }; - process_libraries (sys_lib_dirs, l, la, false, lib, opt); + process_libraries (sys_lib_dirs, l, la, imp, lib, opt); } void link:: @@ -1437,6 +1450,23 @@ namespace build2 args.push_back ("-Wl,-rpath," + l.path ().directory ().string ()); } + auto imp = [for_install] (file&, bool la) + { + // If we are not installing, then we only need to rpath interface + // libraries (they will include rpath's for their implementations). + // Otherwise, we have to do this recursively. + // + // The rpath-link part is tricky: ideally we would like to get only + // implementations and only of shared libraries. We are not interested + // in interfaces because we are linking their libraries explicitly. + // However, in our model there is no such thing as "implementation + // only"; it is either interface or interface and implementation. So + // we are going to rpath-link all of them which should be harmless + // except for some noise on the command line. + // + return for_install ? !la : false; + }; + // Package the data to keep within the 2-pointer small std::function // optimization limit. // @@ -1498,11 +1528,7 @@ namespace build2 d.args.push_back (move (o)); }; - // If we are not installing, then we only need to rpath interface - // libraries (they will include rpath's for their implementations). - // Otherwise, we have to do this recursively. - // - process_libraries (sys_lib_dirs, l, la, !for_install, lib, nullptr); + process_libraries (sys_lib_dirs, l, la, imp, lib, nullptr); } // See windows-rpath.cxx. |