summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArthur LAURENT <[email protected]>2025-11-26 15:29:03 +0100
committerruki <[email protected]>2025-12-18 09:31:44 +0800
commitc765a2c1cac6ab126efc779eb4c823c5573dd25d (patch)
treece2489bbe8abc8b9cbc807512b641b82d4a506b3
parent5dcd669f6e3017d6939af6fd391803c13395406a (diff)
(llvm) add runtime dirs to runenvs (for asan and libunwind)
-rw-r--r--tests/projects/c++/modules/test_base.lua5
-rw-r--r--tests/projects/c/llvm_compiler_rt/test.lua7
-rw-r--r--xmake/modules/core/tools/clang.lua23
-rw-r--r--xmake/modules/private/utils/toolchain.lua111
-rw-r--r--xmake/toolchains/clang/load.lua3
-rw-r--r--xmake/toolchains/llvm/xmake.lua5
6 files changed, 88 insertions, 66 deletions
diff --git a/tests/projects/c++/modules/test_base.lua b/tests/projects/c++/modules/test_base.lua
index 0a0d07dae..466a59e98 100644
--- a/tests/projects/c++/modules/test_base.lua
+++ b/tests/projects/c++/modules/test_base.lua
@@ -11,7 +11,7 @@ MSVC_MIN_VER = "14.29"
function _build(check_outdata)
local flags = ""
if ci_is_running() then
- flags = "-vD"
+ flags = "-vD"
end
if check_outdata then
local outdata
@@ -101,6 +101,9 @@ function build_tests(toolchain_name, opt)
if opt.flags then
flags = " " .. table.concat(opt.flags, " ")
end
+ if ci_is_running() then
+ flags = flags .. " -vD"
+ end
os.exec("xmake clean -a")
os.exec("xmake f" .. platform .. "--toolchain=" .. toolchain_name .. runtimes .. "-c --yes " .. policies .. flags)
diff --git a/tests/projects/c/llvm_compiler_rt/test.lua b/tests/projects/c/llvm_compiler_rt/test.lua
index b2b39f1a8..ee0854e3a 100644
--- a/tests/projects/c/llvm_compiler_rt/test.lua
+++ b/tests/projects/c/llvm_compiler_rt/test.lua
@@ -2,7 +2,7 @@ import("lib.detect.find_tool")
import("core.tool.toolchain")
import("utils.ci.is_running", {alias = "ci_is_running"})
-function main(t)
+function run_test(toolchain_name)
local flags = ""
if ci_is_running() then
flags = "-vD"
@@ -17,3 +17,8 @@ function main(t)
os.exec("xmake f --toolchain=llvm -c --yes " .. flags)
os.run("xmake -r " .. flags)
end
+
+function main(t)
+ run_test("llvm")
+ run_test("clang")
+end
diff --git a/xmake/modules/core/tools/clang.lua b/xmake/modules/core/tools/clang.lua
index 75a165dbb..754516c59 100644
--- a/xmake/modules/core/tools/clang.lua
+++ b/xmake/modules/core/tools/clang.lua
@@ -227,17 +227,7 @@ function nf_runtime(self, runtime, opt)
-- @see https://discourse.llvm.org/t/improve-autolinking-of-compiler-rt-and-libc-on-windows-with-lld-link/71392/10
-- and need manual setting of libc++ headerdirectory
-- @see https://github.com/llvm/llvm-project/issues/79647
- local llvm_dirs = toolchain_utils.get_llvm_dirs(self)
-
- if self:is_plat("windows") and runtime == "c++_shared" then
- if llvm_dirs.bin then
- self:add("runenvs", "PATHS", llvm_dirs.bin)
- end
- if llvm_dirs.rt then
- self:add("runenvs", "PATHS", llvm_dirs.rt)
- end
- end
-
+ local llvm_dirs = toolchain_utils.get_llvm_dirs(self:toolchain())
-- we will set runtimes in android ndk toolchain
if not self:is_plat("android") then
maps = maps or {}
@@ -248,6 +238,7 @@ function nf_runtime(self, runtime, opt)
maps["stdc++_shared"] = "-stdlib=libstdc++"
if kind == "cxx" then
-- force the toolchain libc++ headers to prevent clang picking the systems one
+ -- @see https://github.com/llvm/llvm-project/issues/79647
if llvm_dirs.cxxinclude then
maps["c++_static"] = table.join(maps["c++_static"], "-cxx-isystem" .. llvm_dirs.cxxinclude)
maps["c++_shared"] = table.join(maps["c++_shared"], "-cxx-isystem" .. llvm_dirs.cxxinclude)
@@ -271,23 +262,19 @@ function nf_runtime(self, runtime, opt)
maps[name] = table.join("-resource-dir=" .. llvm_dirs.res, maps[name])
end
end
-
local is_cxx = target and (target.sourcekinds and table.contains(table.wrap(target:sourcekinds()), "cxx"))
if is_cxx then
if llvm_dirs.lib then
maps["c++_static"] = table.join(maps["c++_static"], nf_linkdir(self, llvm_dirs.lib))
maps["c++_shared"] = table.join(maps["c++_shared"], nf_linkdir(self, llvm_dirs.lib))
- maps["c++_shared"] = table.join(maps["c++_shared"], nf_rpathdir(self, llvm_dirs.lib))
+
-- sometimes llvm c++ runtimes are located in c++ subfolder (e.g homebrew llvm)
if llvm_dirs.cxxlib then
maps["c++_static"] = table.join(maps["c++_static"], nf_linkdir(self, llvm_dirs.cxxlib))
maps["c++_shared"] = table.join(maps["c++_shared"], nf_linkdir(self, llvm_dirs.cxxlib))
- maps["c++_shared"] = table.join(maps["c++_shared"], nf_rpathdir(self, llvm_dirs.cxxlib))
end
- if llvm_dirs.rt then
- maps["c++_shared"] = table.join(maps["c++_shared"], nf_rpathdir(self, llvm_dirs.rt))
- end
- -- add rpath to avoid the user need to set LD_LIBRARY_PATH by hand
+
+ -- add rpath to avoid the user need to set DYLD_LIBRARY_PATH by hand
if target.is_shared and target:is_shared() and target.filename and self:is_plat("macosx", "iphoneos", "watchos") then
maps["c++_shared"] = table.join(maps["c++_shared"], "-install_name")
maps["c++_shared"] = table.join(maps["c++_shared"], "@rpath/" .. target:filename())
diff --git a/xmake/modules/private/utils/toolchain.lua b/xmake/modules/private/utils/toolchain.lua
index 551209f2d..e1142945a 100644
--- a/xmake/modules/private/utils/toolchain.lua
+++ b/xmake/modules/private/utils/toolchain.lua
@@ -183,25 +183,25 @@ end
-- get llvm sdk resource directory
function _get_llvm_resourcedir(toolchain)
- local llvm_resourcedir = _g._LLVM_resourceDIR
+ local llvm_resourcedir = _g._LLVM_RESOURCE_DIR
if llvm_resourcedir == nil then
- local outdata = try { function() return os.iorunv(toolchain:get("cc"), {"-print-resource-dir"}, {envs = toolchain:runenvs()}) end }
+ local outdata = try { function() return os.iorunv(toolchain:tool("cc"), {"-print-resource-dir"}) end }
if outdata then
llvm_resourcedir = path.normalize(outdata:trim())
if not os.isdir(llvm_resourcedir) then
llvm_resourcedir = nil
end
end
- _g._LLVM_resourceDIR = llvm_resourcedir or false
+ _g._LLVM_RESOURCE_DIR = llvm_resourcedir or false
end
return llvm_resourcedir or nil
end
-- get llvm sdk root directory
-function _get_llvm_rootdir(self)
+function _get_llvm_rootdir(toolchain)
local llvm_rootdir = _g._LLVM_ROOTDIR
if llvm_rootdir == nil then
- local resourcedir = _get_llvm_resourcedir(self)
+ local resourcedir = _get_llvm_resourcedir(toolchain)
if resourcedir then
llvm_rootdir = path.normalize(path.join(resourcedir, "..", "..", ".."))
if not os.isdir(llvm_rootdir) then
@@ -214,40 +214,49 @@ function _get_llvm_rootdir(self)
end
-- find compiler-rt dir
-function _get_llvm_compiler_win_rtdir_and_link(self, target)
+function _get_llvm_compiler_rtdir_and_link(toolchain)
import("lib.detect.find_tool")
- local cc = self:get("cc")
+ local cc = toolchain:tool("cc")
local cc_tool = find_tool(cc, {version = true})
if cc_tool and cc_tool.version then
- local resdir = _get_llvm_resourcedir(self)
+ local resdir = _get_llvm_resourcedir(toolchain)
if resdir then
local res_libdir = path.join(resdir, "lib")
- -- when -DLLVM_ENABLE_TARGET_RUNTIME_DIR=OFF rtdir is windows/ and rtlink is clang_rt.builtinsi_<arch>.lib
+ -- when -DLLVM_ENABLE_TARGET_RUNTIME_DIR=OFF rtdir is windows/ and rtlink is clang_rt.builtins_<arch>.lib
-- when ON rtdir is windows/<target-triple> and rtlink is clang_rt.builtins.lib
- local target_triple = _get_llvm_target_triple(self)
+ local target_triple = _get_llvm_target_triple(toolchain)
local arch = target_triple and target_triple:split("-")[1]
+ local plat
+ if toolchain:is_plat("windows") then
+ plat = "windows"
+ elseif toolchain:is_plat("linux") then
+ plat = "linux"
+ elseif toolchain:is_plat("macosx", "ios", "watchos", "appletvos", "applexros") then
+ plat = "darwin"
+ end
+
local tripletdir = target_triple and path.join(res_libdir, "windows", target_triple)
tripletdir = os.isdir(tripletdir) or nil
- local rtdir = tripletdir and path.join("windows", target_triple) or "windows"
- if os.isdir(path.join(res_libdir, rtdir)) then
+ local rtdir = tripletdir and path.join(plat, target_triple) or plat
+ if os.isdir(path.join(res_libdir, rtdir)) and toolchain:is_plat("windows") then
local rtlink = "clang_rt.builtins" .. (tripletdir and ".lib" or ("-" .. arch .. ".lib"))
if os.isfile(path.join(res_libdir, rtdir, rtlink)) then
- return res_libdir, path.join(rtdir, rtlink)
+ return res_libdir, path.join(rtdir, rtlink), path.join(res_libdir, rtdir)
end
end
- return res_libdir
+ return res_libdir, nil, path.join(res_libdir, rtdir)
end
end
end
-- get llvm target triple
-function _get_llvm_target_triple(self)
+function _get_llvm_target_triple(toolchain)
local llvm_targettriple = _g._LLVM_TARGETTRIPLE
if llvm_targettriple == nil then
- local outdata = try { function() return os.iorunv(self:program(), {"-print-target-triple"}, {envs = self:runenvs()}) end }
+ local outdata = try { function() return os.iorunv(toolchain:tool("cc"), {"-print-target-triple"}) end }
if outdata then
llvm_targettriple = outdata:trim()
end
@@ -268,50 +277,68 @@ function get_llvm_dirs(toolchain)
local bindir, libdir, cxxlibdir, includedir, cxxincludedir, resdir, rtdir, rtlink
if rootdir then
bindir = path.join(rootdir, "bin")
- if bindir then
- bindir = os.isdir(bindir) and bindir or nil
- end
+ bindir = os.isdir(bindir) and bindir or nil
libdir = path.join(rootdir, "lib")
- if libdir then
- libdir = os.isdir(libdir) and libdir or nil
- end
+ libdir = os.isdir(libdir) and libdir or nil
if libdir then
- cxxlibdir = libdir and path.join(libdir, "c++")
- if cxxlibdir then
+ cxxlibdir = path.join(libdir, "c++")
+ cxxlibdir = os.isdir(cxxlibdir) and cxxlibdir or nil
+ if not cxxlibdir then
+ cxxlibdir = path.join(libdir, _get_llvm_target_triple(toolchain))
cxxlibdir = os.isdir(cxxlibdir) and cxxlibdir or nil
end
end
includedir = path.join(rootdir, "include")
- if includedir then
- includedir = os.isdir(includedir) and includedir or nil
- end
+ includedir = os.isdir(includedir) and includedir or nil
if includedir then
- cxxincludedir = includedir and path.join(includedir, "c++", "v1") or nil
- if cxxincludedir then
- cxxincludedir = os.isdir(cxxincludedir) and cxxincludedir or nil
- end
+ cxxincludedir = path.join(includedir, "c++", "v1")
+ cxxincludedir = os.isdir(cxxincludedir) and cxxincludedir or nil
end
resdir = _get_llvm_resourcedir(toolchain)
- if toolchain:is_plat("windows") then
- rtdir, rtlink = _get_llvm_compiler_win_rtdir_and_link(toolchain)
- end
+ rtdir, rtlink, rtlib = _get_llvm_compiler_rtdir_and_link(toolchain)
end
llvm_dirs = {root = rootdir,
- bin = bindir,
- lib = libdir,
- cxxlib = cxxlibdir,
- include = includedir,
- cxxinclude = cxxincludedir,
- res = resdir,
- rt = rtdir,
- rtlink = rtlink }
+ bin = bindir,
+ lib = libdir,
+ cxxlib = cxxlibdir,
+ include = includedir,
+ cxxinclude = cxxincludedir,
+ res = resdir,
+ rt = rtdir,
+ rtlib = rtlib,
+ rtlink = rtlink }
_g.llvm_dirs = llvm_dirs
end
return llvm_dirs
end
+
+-- set runenvs for llvm
+function set_llvm_runenvs(toolchain)
+ local dirs = get_llvm_dirs(toolchain)
+ if dirs then
+ if dirs.bin and toolchain:is_plat("windows") then
+ toolchain:add("runenvs", "PATH", dirs.bin)
+ end
+ for _, dir in ipairs({dirs.lib or false, dirs.cxxlib or false, dirs.rtlib or false}) do
+ if dir then
+ if toolchain:is_plat("windows") then
+ toolchain:add("runenvs", "PATH", dir)
+ elseif toolchain:is_plat("linux", "bsd") then
+ toolchain:add("runenvs", "LD_LIBRARY_PATH", dir)
+ elseif toolchain:is_plat("macosx") then
+ -- using use DYLD_FALLBACK_LIBRARY_PATH instead of DYLD_LIBRARY_PATH to avoid symbols error when running homebrew llvm (which is linked to system libc++)
+ -- e.g dyld[5195]: Symbol not found: __ZnwmSt19__type_descriptor_t
+ -- Referenced from: <378C7CC2-7CD6-3B88-9C66-FE198E30462B> /usr/local/Cellar/llvm/21.1.5/bin/clang-21
+ -- Expected as weak-def export from some loaded dylibSymbol not found: __ZnamSt19__type_descriptor_t
+ toolchain:add("runenvs", "DYLD_FALLBACK_LIBRARY_PATH", dir)
+ end
+ end
+ end
+ end
+end
diff --git a/xmake/toolchains/clang/load.lua b/xmake/toolchains/clang/load.lua
index 74b04e867..aef891dfd 100644
--- a/xmake/toolchains/clang/load.lua
+++ b/xmake/toolchains/clang/load.lua
@@ -21,6 +21,7 @@
import("detect.sdks.find_vstudio")
import("detect.sdks.find_mingw")
import("core.project.config")
+import("private.utils.toolchain", {alias = "toolchain_utils"})
-- add the given vs environment
function _add_vsenv(toolchain, name, curenvs)
@@ -91,6 +92,8 @@ function main(toolchain, suffix)
target = target .. "-linux-gnu"
end
+ toolchain_utils.set_llvm_runenvs(toolchain)
+
if target then
toolchain:add("cxflags", "--target=" .. target)
toolchain:add("asflags", "--target=" .. target)
diff --git a/xmake/toolchains/llvm/xmake.lua b/xmake/toolchains/llvm/xmake.lua
index 61288f1bd..7de57be22 100644
--- a/xmake/toolchains/llvm/xmake.lua
+++ b/xmake/toolchains/llvm/xmake.lua
@@ -57,10 +57,7 @@ toolchain("llvm")
toolchain:add("runtimes", "MT", "MTd", "MD", "MDd")
end
- local dirs = toolchain_utils.get_llvm_dirs(toolchain)
- if dirs and dirs.rt then
- toolchain:add("runenvs", dirs.rt)
- end
+ toolchain_utils.set_llvm_runenvs(toolchain)
-- add target flags
local target