diff options
| author | ruki <[email protected]> | 2026-08-04 22:40:52 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2026-08-04 22:40:52 +0800 |
| commit | 1bd903ce8eb567ddb1847c119e21665255c879bb (patch) | |
| tree | a78b16274f769898a2e4bdb2d5774742a7c78a43 | |
| parent | 2c1dd455654e0811305183510d0c40adb2d70488 (diff) | |
improve clang static libc++ runtimes
| -rw-r--r-- | xmake/languages/c++/xmake.lua | 12 | ||||
| -rw-r--r-- | xmake/modules/core/tools/clang.lua | 58 |
2 files changed, 63 insertions, 7 deletions
diff --git a/xmake/languages/c++/xmake.lua b/xmake/languages/c++/xmake.lua index b94a073b8..42ddc2884 100644 --- a/xmake/languages/c++/xmake.lua +++ b/xmake/languages/c++/xmake.lua @@ -60,8 +60,7 @@ language("c++") , "toolchain.sysincludedirs" } , binary = { - "target.runtimes" - , "config.linkdirs" + "config.linkdirs" , "config.frameworkdirs" , "target.linkdirs" , "target.frameworkdirs" @@ -79,13 +78,16 @@ language("c++") , "config.frameworks" , "target.frameworks" , "toolchain.frameworks" + -- runtimes may link libc++.a/libc++abi.a explicitly, so it must come after the + -- object files and user links, but before the syslinks it depends on (e.g. pthread) + -- @see https://github.com/xmake-io/xmake/issues/7442 + , "target.runtimes" , "config.syslinks" , "target.syslinks" , "toolchain.syslinks" } , shared = { - "target.runtimes" - , "config.linkdirs" + "config.linkdirs" , "config.frameworkdirs" , "target.linkdirs" , "target.frameworkdirs" @@ -103,6 +105,8 @@ language("c++") , "config.frameworks" , "target.frameworks" , "toolchain.frameworks" + -- @see https://github.com/xmake-io/xmake/issues/7442 + , "target.runtimes" , "config.syslinks" , "target.syslinks" , "toolchain.syslinks" diff --git a/xmake/modules/core/tools/clang.lua b/xmake/modules/core/tools/clang.lua index d9d6512ee..a79e67142 100644 --- a/xmake/modules/core/tools/clang.lua +++ b/xmake/modules/core/tools/clang.lua @@ -192,6 +192,40 @@ function _has_static_libstdcxx(self) return has_static_libstdcxx end +-- has -nostdlib++? (disable the automatic c++ runtime link, so we can link libc++/libc++abi explicitly) +function _has_nostdlibxx(self) + local has_nostdlibxx = _g._HAS_NOSTDLIBXX + if has_nostdlibxx == nil then + if self:has_flags("-nostdlib++ -Werror", "ldflags", {flagskey = "clang_nostdlibxx"}) then + has_nostdlibxx = true + end + has_nostdlibxx = has_nostdlibxx or false + _g._HAS_NOSTDLIBXX = has_nostdlibxx + end + return has_nostdlibxx +end + +-- find the static libc++.a / libc++abi.a archives under the llvm library dirs +function _get_static_cxxlibs(llvm_dirs) + local libdirs = {} + if llvm_dirs.cxxlibdir then + table.insert(libdirs, llvm_dirs.cxxlibdir) + end + if llvm_dirs.libdir then + table.insert(libdirs, llvm_dirs.libdir) + end + local libcxx, libcxxabi + for _, dir in ipairs(libdirs) do + if not libcxx and os.isfile(path.join(dir, "libc++.a")) then + libcxx = path.join(dir, "libc++.a") + end + if not libcxxabi and os.isfile(path.join(dir, "libc++abi.a")) then + libcxxabi = path.join(dir, "libc++abi.a") + end + end + return libcxx, libcxxabi +end + -- make the runtime flag -- @see https://github.com/xmake-io/xmake/issues/3546 function nf_runtime(self, runtime, opt) @@ -284,9 +318,27 @@ function nf_runtime(self, runtime, opt) end end end - if runtime:endswith("_static") and _has_static_libstdcxx(self) then - maps["c++_static"] = table.join(maps["c++_static"], "-static-libstdc++") - maps["stdc++_static"] = table.join(maps["stdc++_static"], "-static-libstdc++") + if runtime:endswith("_static") then + -- -static-libstdc++ only pulls in libc++.a, not libc++abi.a, so libc++abi + -- symbols (typeinfo, __cxa_*) stay undefined and the link fails, especially + -- once c++ modules reference more of libc++. + -- + -- if we can locate both static archives, link them explicitly in the correct + -- order (libc++.a before libc++abi.a) and disable the driver's automatic c++ + -- runtime with -nostdlib++, otherwise fall back to -static-libstdc++. + -- + -- note: target.runtimes is ordered right before the syslinks in the c++ link + -- order, so these archives are placed after the object files / user links. + -- @see https://github.com/xmake-io/xmake/issues/7442 + local libcxx, libcxxabi = _get_static_cxxlibs(llvm_dirs) + if libcxx and libcxxabi and _has_nostdlibxx(self) then + maps["c++_static"] = table.join(maps["c++_static"], "-nostdlib++", libcxx, libcxxabi) + elseif _has_static_libstdcxx(self) then + maps["c++_static"] = table.join(maps["c++_static"], "-static-libstdc++") + end + if _has_static_libstdcxx(self) then + maps["stdc++_static"] = table.join(maps["stdc++_static"], "-static-libstdc++") + end end end end |
