From 23827edd998db30dd1f0d6a14f09399aa7d07b69 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 13 May 2021 15:38:53 +0200 Subject: Add ${c,cxx}.find_system_{header,library}() functions --- libbuild2/cc/common.cxx | 4 ++ libbuild2/cc/compile-rule.cxx | 15 +++++ libbuild2/cc/compile-rule.hxx | 4 ++ libbuild2/cc/functions.cxx | 84 ++++++++++++++++++++++++++- libbuild2/cc/link-rule.cxx | 131 ++++++++++++++++++++++++++++++++++++++++++ libbuild2/cc/link-rule.hxx | 3 + libbuild2/cc/types.cxx | 2 +- libbuild2/function.hxx | 2 +- 8 files changed, 241 insertions(+), 4 deletions(-) (limited to 'libbuild2') diff --git a/libbuild2/cc/common.cxx b/libbuild2/cc/common.cxx index 245109b..3130afa 100644 --- a/libbuild2/cc/common.cxx +++ b/libbuild2/cc/common.cxx @@ -322,6 +322,8 @@ namespace build2 // 2 - argument and next element (-l pthread, -framework CoreServices) // 0 - unrecognized/until the end (-Wl,--whole-archive ...) // + // See similar code in find_system_library(). + // auto sense_fragment = [&sys_simple, this] (const string& l) -> pair { @@ -627,6 +629,8 @@ namespace build2 // Note that pk's scope should not be NULL (even if dir is absolute). // + // Note: see similar logic in find_system_library(). + // target* common:: search_library (action act, const dir_paths& sysd, diff --git a/libbuild2/cc/compile-rule.cxx b/libbuild2/cc/compile-rule.cxx index f8529fb..90a6024 100644 --- a/libbuild2/cc/compile-rule.cxx +++ b/libbuild2/cc/compile-rule.cxx @@ -175,6 +175,21 @@ namespace build2 throw invalid_argument ("invalid preprocessed value '" + s + "'"); } + optional compile_rule:: + find_system_header (const path& f) const + { + path p; // Reuse the buffer. + for (const dir_path& d: sys_inc_dirs) + { + if (file_exists ((p = d, p /= f), + true /* follow_symlinks */, + true /* ignore_errors */)) + return p; + } + + return nullopt; + } + struct compile_rule::match_data { explicit diff --git a/libbuild2/cc/compile-rule.hxx b/libbuild2/cc/compile-rule.hxx index 917acd1..e80c36a 100644 --- a/libbuild2/cc/compile-rule.hxx +++ b/libbuild2/cc/compile-rule.hxx @@ -60,6 +60,10 @@ namespace build2 append_library_options (appended_libraries&, strings&, const scope&, action, const file&, bool, linfo) const; + + optional + find_system_header (const path&) const; + protected: static void functions (function_family&, const char*); // functions.cxx diff --git a/libbuild2/cc/functions.cxx b/libbuild2/cc/functions.cxx index 760a332..0394524 100644 --- a/libbuild2/cc/functions.cxx +++ b/libbuild2/cc/functions.cxx @@ -53,7 +53,7 @@ namespace build2 const module* m (rs->find_module (d.x)); if (m == nullptr) - fail << f.name << " called without " << d.x << " module being loaded"; + fail << f.name << " called without " << d.x << " module loaded"; // We can assume these are present due to function's types signature. // @@ -108,7 +108,7 @@ namespace build2 const module* m (rs->find_module (d.x)); if (m == nullptr) - fail << f.name << " called without " << d.x << " module being loaded"; + fail << f.name << " called without " << d.x << " module loaded"; // We can assume these are present due to function's types signature. // @@ -226,6 +226,45 @@ namespace build2 m.append_library_options ( *static_cast (ls), r, bs, a, l, la, li); }}); + + // $.find_system_header() + // + // Return the header path if the specified header exists in one of the + // system header search directories and NULL otherwise. System header + // search directories are those that the compiler searches by default + // plus directories specified as part of the compiler mode options (but + // not *.poptions). + // + // Note that this function is not pure. + // + f.insert (".find_system_header", false). + insert ( + [] (const scope* bs, + vector_view vs, + const function_overload& f) -> value + { + const char* x (*reinterpret_cast (&f.data)); + + if (bs == nullptr) + fail << f.name << " called out of scope"; + + const scope* rs (bs->root_scope ()); + + if (rs == nullptr) + fail << f.name << " called out of project"; + + const module* m (rs->find_module (x)); + + if (m == nullptr) + fail << f.name << " called without " << x << " module loaded"; + + // We can assume the argument is present due to function's types + // signature. + // + auto r (m->find_system_header (convert (move (vs[0])))); + return r ? value (move (*r)) : value (nullptr); + }, + x); } void link_rule:: @@ -357,6 +396,47 @@ namespace build2 else fail << t << " is not an object file target"; }}); + + // $.find_system_library() + // + // Return the library path if the specified library exists in one of the + // system library search directories. System library search directories + // are those that the compiler searches by default plus directories + // specified as part of the compiler mode options (but not *.loptions). + // + // The library can be specified in the same form as expected by the + // linker (-lfoo for POSIX, foo.lib for MSVC) or as a complete name. + // + // Note that this function is not pure. + // + f.insert (".find_system_library", false). + insert ( + [] (const scope* bs, + vector_view vs, + const function_overload& f) -> value + { + const char* x (*reinterpret_cast (&f.data)); + + if (bs == nullptr) + fail << f.name << " called out of scope"; + + const scope* rs (bs->root_scope ()); + + if (rs == nullptr) + fail << f.name << " called out of project"; + + const module* m (rs->find_module (x)); + + if (m == nullptr) + fail << f.name << " called without " << x << " module loaded"; + + // We can assume the argument is present due to function's types + // signature. + // + auto r (m->find_system_library (convert (move (vs[0])))); + return r ? value (move (*r)) : value (nullptr); + }, + x); } } } diff --git a/libbuild2/cc/link-rule.cxx b/libbuild2/cc/link-rule.cxx index 96e243d..05a4da8 100644 --- a/libbuild2/cc/link-rule.cxx +++ b/libbuild2/cc/link-rule.cxx @@ -34,6 +34,137 @@ namespace build2 using namespace bin; using build2::to_string; + optional link_rule:: + find_system_library (const strings& l) const + { + assert (!l.empty ()); + + // Figure out what we are looking for. + // + // See similar code in process_libraries(). + // + // @@ TODO: should we take the link order into account (but do we do + // this when we link system libraries)? + // + string n1, n2; + { + auto i (l.begin ()), e (l.end ()); + + string s (*i); + + if (tsys == "win32-msvc") + { + if (s[0] == '/') + { + // Some option (e.g., /WHOLEARCHIVE:). Fall through to fail. + } + else + { + // Presumably a complete name. + // + n1 = move (s); + i++; + } + } + else + { + if (s[0] == '-') + { + // -l, -l + // + if (s[1] == 'l') + { + if (s.size () == 2) // -l + { + if (i + 1 != e) + s = *++i; + else + s.clear (); + } + else // -l + s.erase (0, 2); + + if (!s.empty ()) + { + i++; + + // Here we need to be consistent with search_library(). Maybe + // one day we should generalize it to be usable here (though + // here we don't need library name guessing). + // + const char* p (""); + const char* e1 (nullptr); + const char* e2 (nullptr); + + if (tclass == "windows") + { + if (tsys == "mingw32") + { + p = "lib"; + e1 = ".dll.a"; + e2 = ".a"; + } + else + { + e1 = ".dll.lib"; + e2 = ".lib"; + } + } + else + { + p = "lib"; + e1 = (tclass == "macos" ? ".dylib" : ".so"); + e2 = ".a"; + } + + n1 = p + s + e1; + n2 = e2 != nullptr ? p + s + e2 : string (); + } + } +#if 0 + // -framework (Mac OS) + // + else if (tsys == "darwin" && l == "-framework") + { + // @@ TODO: maybe one day. + } +#endif + else + { + // Some other option (e.g., -Wl,--whole-archive). Fall through + // to fail. + } + } + else + { + // Presumably a complete name. + // + n1 = move (s); + i++; + } + } + + if (i != e) + fail << "unexpected library name '" << *i << "'"; + } + + path p; // Reuse the buffer. + for (const dir_path& d: sys_lib_dirs) + { + auto exists = [&p, &d] (const string& n) + { + return file_exists ((p = d, p /= n), + true /* follow_symlinks */, + true /* ignore_errors */); + }; + + if (exists (n1) || (!n2.empty () && exists (n2))) + return p; + } + + return nullopt; + } + link_rule:: link_rule (data&& d) : common (move (d)), diff --git a/libbuild2/cc/link-rule.hxx b/libbuild2/cc/link-rule.hxx index c49d20f..c68466a 100644 --- a/libbuild2/cc/link-rule.hxx +++ b/libbuild2/cc/link-rule.hxx @@ -169,6 +169,9 @@ namespace build2 append_binless_modules (sha256&, const scope&, action, const file&) const; + optional + find_system_library (const strings&) const; + protected: static void functions (function_family&, const char*); // functions.cxx diff --git a/libbuild2/cc/types.cxx b/libbuild2/cc/types.cxx index 666b048..bd68147 100644 --- a/libbuild2/cc/types.cxx +++ b/libbuild2/cc/types.cxx @@ -68,7 +68,7 @@ namespace build2 { path f (s, 1, s.size () - 2); - path p; + path p; // Reuse the buffer. for (const dir_path& d: sys_inc_dirs) { if (file_exists ((p = d, p /= f), diff --git a/libbuild2/function.hxx b/libbuild2/function.hxx index 6654257..81ece89 100644 --- a/libbuild2/function.hxx +++ b/libbuild2/function.hxx @@ -950,7 +950,7 @@ namespace build2 typename cast::data {&cast::thunk, dm})); } - // Low-level interface that can be used to register additional data. + // Low-level interface that can be used to pass additional data. // // Note that the call to this function sidesteps the thunk. // -- cgit v1.1