aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2021-05-13 15:38:53 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2021-05-13 15:38:53 +0200
commit23827edd998db30dd1f0d6a14f09399aa7d07b69 (patch)
treead5d7669b167efde8e01894c72d091196f58bcdf
parentd92ea3a7cff0dae578005a914df799e1e11efc8e (diff)
Add ${c,cxx}.find_system_{header,library}() functions
-rw-r--r--libbuild2/cc/common.cxx4
-rw-r--r--libbuild2/cc/compile-rule.cxx15
-rw-r--r--libbuild2/cc/compile-rule.hxx4
-rw-r--r--libbuild2/cc/functions.cxx84
-rw-r--r--libbuild2/cc/link-rule.cxx131
-rw-r--r--libbuild2/cc/link-rule.hxx3
-rw-r--r--libbuild2/cc/types.cxx2
-rw-r--r--libbuild2/function.hxx2
8 files changed, 241 insertions, 4 deletions
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<size_t, bool>
{
@@ -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<path> 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<path>
+ 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<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<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<appended_libraries*> (ls), r, bs, a, l, la, li);
}});
+
+ // $<module>.find_system_header(<name>)
+ //
+ // 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 char*, names> (
+ [] (const scope* bs,
+ vector_view<value> vs,
+ const function_overload& f) -> value
+ {
+ const char* x (*reinterpret_cast<const char* const*> (&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<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<path> (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";
}});
+
+ // $<module>.find_system_library(<name>)
+ //
+ // 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 char*, names> (
+ [] (const scope* bs,
+ vector_view<value> vs,
+ const function_overload& f) -> value
+ {
+ const char* x (*reinterpret_cast<const char* const*> (&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<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<strings> (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<path> 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:<name>). Fall through to fail.
+ }
+ else
+ {
+ // Presumably a complete name.
+ //
+ n1 = move (s);
+ i++;
+ }
+ }
+ else
+ {
+ if (s[0] == '-')
+ {
+ // -l<name>, -l <name>
+ //
+ if (s[1] == 'l')
+ {
+ if (s.size () == 2) // -l <name>
+ {
+ if (i + 1 != e)
+ s = *++i;
+ else
+ s.clear ();
+ }
+ else // -l<name>
+ 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 <name> (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<path>
+ 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.
//