From 7197d069cb82286f9789a8ce987fe5f0f5b6f05d Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 10 Jan 2024 12:02:13 +0200 Subject: Add ability to specify alternative sysroot for pkg-config files (GC issue #59) Specifically, the new config.cc.pkgconfig.sysroot variable provides roughly equivalent functionality to PKG_CONFIG_SYSROOT_DIR in pkg-config. For details and limitations, see "Rewriting Installed Libraries System Root (sysroot)" in the manual for details. --- doc/manual.cli | 49 ++++++++++++++++++++++++++++++++++++++++++++ libbuild2/cc/init.cxx | 18 ++++++++++++++-- libbuild2/cc/pkgconfig.cxx | 51 ++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 114 insertions(+), 4 deletions(-) diff --git a/doc/manual.cli b/doc/manual.cli index f24b429..66d0ffb 100644 --- a/doc/manual.cli +++ b/doc/manual.cli @@ -7585,6 +7585,11 @@ config.cc.libs config.cc.internal.scope cc.internal.scope + +config.cc.reprocess + cc.reprocess + +config.cc.pkgconfig.sysroot \ Note that the compiler mode options are \"cross-hinted\" between \c{config.c} @@ -7946,6 +7951,50 @@ prerequisite library, resolved using the above algorithm, and linked. In other words, in this case we end up with a binless library \c{lib{znonsense\}} that depends on \c{lib{z\}} instead of a single \c{lib{z\}} library. +\h2#cc-import-installed-sysroot|Rewriting Installed Libraries System Root (sysroot)| + +Sometimes the installed libraries are moved to a different location after the +installation. This is especially common in embedded development where the code +is normally cross-compiled and the libraries for the target platform are +placed into a host directory, called system root or \i{sysroot}, that doesn't +match where these libraries were originally installed to. For example, the +libraries might have been installed into \c{/usr/} but on the host machine +they may reside in \c{/opt/target/usr/}. In this example, \c{/opt/target/} is +the sysroot. + +While such relocations usually do not affect the library headers or binaries, +they do break the \c{pkg-config}'s \c{.pc} files which often contain \c{-I} +and \c{-L} options with absolute paths. Continue with the above example, a +\c{.pc} file as originally installed may contain \c{-I/usr/include} and +\c{-L/usr/lib} while now, that the libraries have been relocated to +\c{/opt/target/}, they somehow need to be adjusted to +\c{-I/opt/target/usr/include} and \c{-L/opt/target/usr/lib}. + +While it is possible (and perhaps correct) to accomplish this by fixing the +\c{.pc} files to match the new location, it is not always possible or easy. +As a result, \c{build2} provides a mechanism for automatically adjusting the +system root in the \c{-I} and \c{-L} options extracted from \c{.pc} files. + +\N|This functionality is roughly equivalent to that provided with the +\c{PKG_CONFIG_SYSROOT_DIR} environment variable by the \c{pkg-config} +utility.| + +Specifically, the \c{config.cc.pkgconfig.sysroot} variable can be used to +specify an alternative system root. When specified, all absolute paths in the +\c{-I} and \c{-L} options that are not already in this directory will be +rewritten to start with this sysroot. + +\N|Note that this mechanism is a workaround rather than a proper solution since +it is limited to the \c{-I} and \c{-L} options. In particular, it does not +handle any other options that may contain absolute paths nor \c{pkg-config} +variables that may be queried. + +As a result, it should only be used for dealing with issues in third-party +\c{.pc} files that do not handle relocation (for example, using the +\c{${pcfiledir\}} built-in \c{pkg-config} variable). In particular, for +\c{build2}-generated \c{.pc} files a \l{#install-reloc relocatable +installation} should be used instead.| + \h#cc-gcc|GCC Compiler Toolchain| diff --git a/libbuild2/cc/init.cxx b/libbuild2/cc/init.cxx index d766b30..1bddbb2 100644 --- a/libbuild2/cc/init.cxx +++ b/libbuild2/cc/init.cxx @@ -100,13 +100,19 @@ namespace build2 vp.insert ("config.cc.loptions"); vp.insert ("config.cc.aoptions"); vp.insert ("config.cc.libs"); - vp.insert ("config.cc.internal.scope"); + + vp.insert ("config.cc.internal.scope"); + + vp.insert ("config.cc.reprocess"); // See cc.preprocess below. + + vp.insert ("config.cc.pkgconfig.sysroot"); vp.insert ("cc.poptions"); vp.insert ("cc.coptions"); vp.insert ("cc.loptions"); vp.insert ("cc.aoptions"); vp.insert ("cc.libs"); + vp.insert ("cc.internal.scope"); vp.insert ("cc.internal.libs"); @@ -177,7 +183,6 @@ namespace build2 // Ability to disable using preprocessed output for compilation. // - vp.insert ("config.cc.reprocess"); vp.insert ("cc.reprocess"); // Register scope operation callback. @@ -337,6 +342,15 @@ namespace build2 if (lookup l = lookup_config (rs, "config.cc.reprocess")) rs.assign ("cc.reprocess") = *l; + // config.cc.pkgconfig.sysroot + // + // Let's look it up instead of just marking for saving to make sure the + // path is valid. + // + // Note: save omitted. + // + lookup_config (rs, "config.cc.pkgconfig.sysroot"); + // Load the bin.config module. // if (!cast_false (rs["bin.config.loaded"])) diff --git a/libbuild2/cc/pkgconfig.cxx b/libbuild2/cc/pkgconfig.cxx index b0b9675..ff84dc4 100644 --- a/libbuild2/cc/pkgconfig.cxx +++ b/libbuild2/cc/pkgconfig.cxx @@ -316,9 +316,15 @@ namespace build2 assert (!ap.empty () || !sp.empty ()); - // Append -I or -L option suppressing duplicates. + const scope& rs (*s.root_scope ()); + + const dir_path* sysroot ( + cast_null (rs["config.cc.pkgconfig.sysroot"])); + + // Append -I or -L option suppressing duplicates. Also handle + // the sysroot rewrite. // - auto append_dir = [] (strings& ops, string&& o) + auto append_dir = [sysroot] (strings& ops, string&& o) { char c (o[1]); @@ -337,6 +343,47 @@ namespace build2 // Note that we do normalize -L paths in the usrd logic later // (but not when setting as *.export.loptions). + if (sysroot != nullptr) + { + // Notes: + // + // - The path might not be absolute (we only rewrite absolute ones). + // + // - Do this before duplicate suppression since options in ops + // already have the sysroot rewritten. + // + // - Check if the path already starts with sysroot since some .pc + // files might already be in a good shape (e.g., because they use + // ${pcfiledir} to support relocation properly). + // + const char* op (o.c_str () + 2); + size_t on (o.size () - 2); + + if (path_traits::absolute (op, on)) + { + const string& s (sysroot->string ()); + + const char* sp (s.c_str ()); + size_t sn (s.size ()); + + if (!path_traits::sub (op, on, sp, sn)) // Already in sysroot. + { + // Find the first directory seperator that seperates the root + // component from the rest of the path (think /usr/include, + // c:\install\include). We need to replace the root component + // with sysroot. If there is no separator (say, -Ic:) or the + // path after the separator is empty (say, -I/), then we replace + // the entire path. + // + size_t p (path_traits::find_separator (o, 2)); + if (p == string::npos || p + 1 == o.size ()) + p = o.size (); + + o.replace (2, p - 2, s); + } + } + } + for (const string& x: ops) { if (x.size () > 2 && x[0] == '-' && x[1] == c) -- cgit v1.1