fix(toolchain): pass -L as well as an rpath for a toolchain outside /usr
Inside the Flatpak the bundled toolchain compiled every bootstrap object, then glslang's configure failed its test link with `unable to find library -lc++`. clang searches its per-target runtime directory (lib/<triple>) and the system library paths for libc++, not <prefix>/lib, so with the classic layout a toolchain outside /usr needs the search path spelled out, just as its loader needs the rpath. LibcxxLinkFlags and build.sh now emit both, the same pair an explicit CRAFTER_BUILD_LIBCXX_DIR already got. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
a72d18eeab
commit
d22a8603df
4 changed files with 25 additions and 19 deletions
17
build.sh
17
build.sh
|
|
@ -14,12 +14,13 @@ if [ -n "${CRAFTER_BUILD_LLVM_DIR:-}" ]; then
|
|||
CC="$CRAFTER_BUILD_LLVM_DIR/bin/clang"
|
||||
AR="$CRAFTER_BUILD_LLVM_DIR/bin/llvm-ar"
|
||||
LLVM_CONFIG="$CRAFTER_BUILD_LLVM_DIR/bin/llvm-config"
|
||||
# A prefix other than the system one keeps its libc++ off the loader's
|
||||
# default path; the rpath is what lets the binary start.
|
||||
# A prefix other than the system one keeps its libc++ off both the
|
||||
# linker's search path (clang looks in lib/<triple> and the system dirs,
|
||||
# not <prefix>/lib) and the loader's; -L and an rpath cover the two.
|
||||
if [ "$CRAFTER_BUILD_LLVM_DIR" != /usr ]; then
|
||||
RPATH_FLAG="-Wl,-rpath,$CRAFTER_BUILD_LLVM_DIR/lib"
|
||||
LIBCXX_LINK_FLAGS="-L$CRAFTER_BUILD_LLVM_DIR/lib -Wl,-rpath,$CRAFTER_BUILD_LLVM_DIR/lib"
|
||||
else
|
||||
RPATH_FLAG=""
|
||||
LIBCXX_LINK_FLAGS=""
|
||||
fi
|
||||
if [ -f "$CRAFTER_BUILD_LLVM_DIR/share/libc++/v1/std.cppm" ]; then
|
||||
STD_CPPM="$CRAFTER_BUILD_LLVM_DIR/share/libc++/v1/std.cppm"
|
||||
|
|
@ -31,7 +32,7 @@ else
|
|||
CC=clang
|
||||
AR=llvm-ar
|
||||
LLVM_CONFIG=llvm-config
|
||||
RPATH_FLAG=""
|
||||
LIBCXX_LINK_FLAGS=""
|
||||
STD_CPPM=/usr/share/libc++/v1/std.cppm
|
||||
fi
|
||||
|
||||
|
|
@ -65,8 +66,8 @@ cmake -B build \
|
|||
-DCMAKE_C_COMPILER="$CC" \
|
||||
-DCMAKE_CXX_COMPILER="$CXX" \
|
||||
-DCMAKE_CXX_FLAGS="-stdlib=libc++" \
|
||||
-DCMAKE_EXE_LINKER_FLAGS="-stdlib=libc++ $RPATH_FLAG" \
|
||||
-DCMAKE_SHARED_LINKER_FLAGS="-stdlib=libc++ $RPATH_FLAG" \
|
||||
-DCMAKE_EXE_LINKER_FLAGS="-stdlib=libc++ $LIBCXX_LINK_FLAGS" \
|
||||
-DCMAKE_SHARED_LINKER_FLAGS="-stdlib=libc++ $LIBCXX_LINK_FLAGS" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_ARCHIVE_OUTPUT_DIRECTORY="$current_dir/build" \
|
||||
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY="$current_dir/build" \
|
||||
|
|
@ -117,7 +118,7 @@ rm -f ./lib/libcrafter-build.a
|
|||
"$AR" rcs ./lib/libcrafter-build.a $OBJECTS
|
||||
|
||||
"$CXX" --target="$TARGET" -std=c++26 -stdlib=libc++ -O3 -march="$MARCH" -mtune="$MTUNE" -fuse-ld=lld \
|
||||
-Wl,--export-dynamic $RPATH_FLAG \
|
||||
-Wl,--export-dynamic $LIBCXX_LINK_FLAGS \
|
||||
-L./build \
|
||||
$OBJECTS \
|
||||
./build/main.o \
|
||||
|
|
|
|||
|
|
@ -51,14 +51,17 @@ std::string Toolchain::LibcxxCompileFlags() const {
|
|||
}
|
||||
|
||||
std::string Toolchain::LibcxxLinkFlags() const {
|
||||
std::string flags;
|
||||
// clang searches its per-target runtime directory and the system library
|
||||
// paths for -lc++, not <prefix>/lib, so a toolchain outside /usr with the
|
||||
// classic layout needs the search path as well as the run-time path.
|
||||
fs::path lib;
|
||||
if (!libcxxDir.empty()) {
|
||||
fs::path lib = libcxxDir / "lib";
|
||||
flags += std::format(" -L{} -Wl,-rpath,{}", lib.string(), lib.string());
|
||||
lib = libcxxDir / "lib";
|
||||
} else if (!prefix.empty() && prefix != "/usr") {
|
||||
flags += std::format(" -Wl,-rpath,{}", (prefix / "lib").string());
|
||||
lib = prefix / "lib";
|
||||
}
|
||||
return flags;
|
||||
if (lib.empty()) return {};
|
||||
return std::format(" -L{} -Wl,-rpath,{}", lib.string(), lib.string());
|
||||
}
|
||||
|
||||
std::string Toolchain::Key() const {
|
||||
|
|
|
|||
|
|
@ -44,10 +44,12 @@ export namespace Crafter {
|
|||
|
||||
// Flags for compiling against libcxxDir; empty without one.
|
||||
std::string LibcxxCompileFlags() const;
|
||||
// Flags for linking against the libc++ the compiler will use: an
|
||||
// rpath into the prefix when that is not the system one (a bundled
|
||||
// toolchain's libc++.so.1 is not on the loader's default path), plus
|
||||
// -L and an rpath for an explicit libcxxDir.
|
||||
// Flags for linking against the libc++ the compiler will use: a -L
|
||||
// and an rpath for <prefix>/lib when the prefix is not the system one
|
||||
// (clang searches only its per-target runtime directory and the
|
||||
// system paths, and a bundled toolchain's libc++.so.1 is on neither
|
||||
// the linker's nor the loader's default path), or for an explicit
|
||||
// libcxxDir.
|
||||
std::string LibcxxLinkFlags() const;
|
||||
// Names this toolchain for cache directory names: the clang version
|
||||
// followed by a hash of what decides which headers and libraries a
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ int main() {
|
|||
Check(tc.stdCppm == full / "share/libc++/v1/std.cppm", "the prefix's std module source is used");
|
||||
Check(tc.wasiSysroot == full / "share/wasi-sysroot", "the prefix's wasi sysroot is used");
|
||||
Check(tc.LibcxxCompileFlags().empty(), "the compiler finds its own libc++ headers without flags");
|
||||
Check(Contains(tc.LibcxxLinkFlags(), std::format("-Wl,-rpath,{}", (full / "lib").string())), "binaries get an rpath into the prefix's lib dir");
|
||||
Check(Contains(tc.LibcxxLinkFlags(), std::format("-L{}", (full / "lib").string())) && Contains(tc.LibcxxLinkFlags(), std::format("-Wl,-rpath,{}", (full / "lib").string())), "binaries get -L and an rpath for the prefix's lib dir");
|
||||
}
|
||||
{
|
||||
ToolchainInputs in;
|
||||
|
|
@ -95,7 +95,7 @@ int main() {
|
|||
Check(tc.llvmIncludeDir.empty(), "no clang-c headers in the prefix: nothing added");
|
||||
Check(tc.stdCppm == "/usr/share/libc++/v1/std.cppm", "no std module in the prefix: the system copy");
|
||||
Check(tc.wasiSysroot == "/usr/share/wasi-sysroot", "no wasi sysroot in the prefix: the system one");
|
||||
Check(Contains(tc.LibcxxLinkFlags(), std::format("-Wl,-rpath,{}", (bare / "lib").string())), "the rpath follows the explicit prefix");
|
||||
Check(Contains(tc.LibcxxLinkFlags(), std::format("-L{}", (bare / "lib").string())) && Contains(tc.LibcxxLinkFlags(), std::format("-Wl,-rpath,{}", (bare / "lib").string())), "the link flags follow the explicit prefix");
|
||||
}
|
||||
{
|
||||
ToolchainInputs in;
|
||||
|
|
|
|||
Loading…
Reference in a new issue