From 7a1be435eef977b88a2855df9bafc4ebeca1843e Mon Sep 17 00:00:00 2001 From: Arthur LAURENT Date: Fri, 31 Oct 2025 19:51:35 +0100 Subject: nfc(llvm) add a test for llvm builtins --- tests/projects/c++/modules/test_base.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests/projects/c++/modules/test_base.lua') diff --git a/tests/projects/c++/modules/test_base.lua b/tests/projects/c++/modules/test_base.lua index 6abbeecee..0a0d07dae 100644 --- a/tests/projects/c++/modules/test_base.lua +++ b/tests/projects/c++/modules/test_base.lua @@ -103,7 +103,7 @@ function build_tests(toolchain_name, opt) end os.exec("xmake clean -a") - os.exec("xmake f" .. platform .. "--toolchain=" .. toolchain_name .. runtimes .. "-cD --yes " .. policies .. flags) + os.exec("xmake f" .. platform .. "--toolchain=" .. toolchain_name .. runtimes .. "-c --yes " .. policies .. flags) if opt.build then opt.build() else -- cgit v1.3.1 From c765a2c1cac6ab126efc779eb4c823c5573dd25d Mon Sep 17 00:00:00 2001 From: Arthur LAURENT Date: Wed, 26 Nov 2025 15:29:03 +0100 Subject: (llvm) add runtime dirs to runenvs (for asan and libunwind) --- tests/projects/c++/modules/test_base.lua | 5 +- tests/projects/c/llvm_compiler_rt/test.lua | 7 +- xmake/modules/core/tools/clang.lua | 23 ++---- xmake/modules/private/utils/toolchain.lua | 111 ++++++++++++++++++----------- xmake/toolchains/clang/load.lua | 3 + xmake/toolchains/llvm/xmake.lua | 5 +- 6 files changed, 88 insertions(+), 66 deletions(-) (limited to 'tests/projects/c++/modules/test_base.lua') 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_.lib + -- when -DLLVM_ENABLE_TARGET_RUNTIME_DIR=OFF rtdir is windows/ and rtlink is clang_rt.builtins_.lib -- when ON rtdir is windows/ 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 -- cgit v1.3.1