Skip to content

Commit 6bb8b2f

Browse files
committed
(llvm) add runtime dirs to runenvs (for asan and libunwind)
1 parent 6b98095 commit 6bb8b2f

File tree

6 files changed

+99
-66
lines changed

6 files changed

+99
-66
lines changed

tests/projects/c++/modules/test_base.lua

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ MSVC_MIN_VER = "14.29"
1111
function _build(check_outdata)
1212
local flags = ""
1313
if ci_is_running() then
14-
flags = "-vD"
14+
flags = "-vD"
1515
end
1616
if check_outdata then
1717
local outdata
@@ -101,6 +101,9 @@ function build_tests(toolchain_name, opt)
101101
if opt.flags then
102102
flags = " " .. table.concat(opt.flags, " ")
103103
end
104+
if ci_is_running() then
105+
flags = flags .. " -vD"
106+
end
104107

105108
os.exec("xmake clean -a")
106109
os.exec("xmake f" .. platform .. "--toolchain=" .. toolchain_name .. runtimes .. "-c --yes " .. policies .. flags)

tests/projects/c/llvm_compiler_rt/test.lua

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import("lib.detect.find_tool")
22
import("core.tool.toolchain")
33
import("utils.ci.is_running", {alias = "ci_is_running"})
44

5-
function main(t)
5+
function run_test(toolchain_name)
66
local flags = ""
77
if ci_is_running() then
88
flags = "-vD"
@@ -17,3 +17,8 @@ function main(t)
1717
os.exec("xmake f --toolchain=llvm -c --yes " .. flags)
1818
os.run("xmake -r " .. flags)
1919
end
20+
21+
function main(t)
22+
run_test("llvm")
23+
run_test("clang")
24+
end

xmake/modules/core/tools/clang.lua

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -227,17 +227,7 @@ function nf_runtime(self, runtime, opt)
227227
-- @see https://discourse.llvm.org/t/improve-autolinking-of-compiler-rt-and-libc-on-windows-with-lld-link/71392/10
228228
-- and need manual setting of libc++ headerdirectory
229229
-- @see https://github.com/llvm/llvm-project/issues/79647
230-
local llvm_dirs = toolchain_utils.get_llvm_dirs(self)
231-
232-
if self:is_plat("windows") and runtime == "c++_shared" then
233-
if llvm_dirs.bin then
234-
self:add("runenvs", "PATHS", llvm_dirs.bin)
235-
end
236-
if llvm_dirs.rt then
237-
self:add("runenvs", "PATHS", llvm_dirs.rt)
238-
end
239-
end
240-
230+
local llvm_dirs = toolchain_utils.get_llvm_dirs(self:toolchain())
241231
-- we will set runtimes in android ndk toolchain
242232
if not self:is_plat("android") then
243233
maps = maps or {}
@@ -248,6 +238,7 @@ function nf_runtime(self, runtime, opt)
248238
maps["stdc++_shared"] = "-stdlib=libstdc++"
249239
if kind == "cxx" then
250240
-- force the toolchain libc++ headers to prevent clang picking the systems one
241+
-- @see https://github.com/llvm/llvm-project/issues/79647
251242
if llvm_dirs.cxxinclude then
252243
maps["c++_static"] = table.join(maps["c++_static"], "-cxx-isystem" .. llvm_dirs.cxxinclude)
253244
maps["c++_shared"] = table.join(maps["c++_shared"], "-cxx-isystem" .. llvm_dirs.cxxinclude)
@@ -271,23 +262,19 @@ function nf_runtime(self, runtime, opt)
271262
maps[name] = table.join("-resource-dir=" .. llvm_dirs.res, maps[name])
272263
end
273264
end
274-
275265
local is_cxx = target and (target.sourcekinds and table.contains(table.wrap(target:sourcekinds()), "cxx"))
276266
if is_cxx then
277267
if llvm_dirs.lib then
278268
maps["c++_static"] = table.join(maps["c++_static"], nf_linkdir(self, llvm_dirs.lib))
279269
maps["c++_shared"] = table.join(maps["c++_shared"], nf_linkdir(self, llvm_dirs.lib))
280-
maps["c++_shared"] = table.join(maps["c++_shared"], nf_rpathdir(self, llvm_dirs.lib))
270+
281271
-- sometimes llvm c++ runtimes are located in c++ subfolder (e.g homebrew llvm)
282272
if llvm_dirs.cxxlib then
283273
maps["c++_static"] = table.join(maps["c++_static"], nf_linkdir(self, llvm_dirs.cxxlib))
284274
maps["c++_shared"] = table.join(maps["c++_shared"], nf_linkdir(self, llvm_dirs.cxxlib))
285-
maps["c++_shared"] = table.join(maps["c++_shared"], nf_rpathdir(self, llvm_dirs.cxxlib))
286275
end
287-
if llvm_dirs.rt then
288-
maps["c++_shared"] = table.join(maps["c++_shared"], nf_rpathdir(self, llvm_dirs.rt))
289-
end
290-
-- add rpath to avoid the user need to set LD_LIBRARY_PATH by hand
276+
277+
-- add rpath to avoid the user need to set DYLD_LIBRARY_PATH by hand
291278
if target.is_shared and target:is_shared() and target.filename and self:is_plat("macosx", "iphoneos", "watchos") then
292279
maps["c++_shared"] = table.join(maps["c++_shared"], "-install_name")
293280
maps["c++_shared"] = table.join(maps["c++_shared"], "@rpath/" .. target:filename())

xmake/modules/private/utils/toolchain.lua

Lines changed: 80 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -183,25 +183,25 @@ end
183183

184184
-- get llvm sdk resource directory
185185
function _get_llvm_resourcedir(toolchain)
186-
local llvm_resourcedir = _g._LLVM_resourceDIR
186+
local llvm_resourcedir = _g._LLVM_RESOURCE_DIR
187187
if llvm_resourcedir == nil then
188-
local outdata = try { function() return os.iorunv(toolchain:get("cc"), {"-print-resource-dir"}, {envs = toolchain:runenvs()}) end }
188+
local outdata = try { function() return os.iorunv(toolchain:tool("cc"), {"-print-resource-dir"}) end }
189189
if outdata then
190190
llvm_resourcedir = path.normalize(outdata:trim())
191191
if not os.isdir(llvm_resourcedir) then
192192
llvm_resourcedir = nil
193193
end
194194
end
195-
_g._LLVM_resourceDIR = llvm_resourcedir or false
195+
_g._LLVM_RESOURCE_DIR = llvm_resourcedir or false
196196
end
197197
return llvm_resourcedir or nil
198198
end
199199

200200
-- get llvm sdk root directory
201-
function _get_llvm_rootdir(self)
201+
function _get_llvm_rootdir(toolchain)
202202
local llvm_rootdir = _g._LLVM_ROOTDIR
203203
if llvm_rootdir == nil then
204-
local resourcedir = _get_llvm_resourcedir(self)
204+
local resourcedir = _get_llvm_resourcedir(toolchain)
205205
if resourcedir then
206206
llvm_rootdir = path.normalize(path.join(resourcedir, "..", "..", ".."))
207207
if not os.isdir(llvm_rootdir) then
@@ -214,40 +214,49 @@ function _get_llvm_rootdir(self)
214214
end
215215

216216
-- find compiler-rt dir
217-
function _get_llvm_compiler_win_rtdir_and_link(self, target)
217+
function _get_llvm_compiler_rtdir_and_link(toolchain)
218218
import("lib.detect.find_tool")
219219

220-
local cc = self:get("cc")
220+
local cc = toolchain:tool("cc")
221221
local cc_tool = find_tool(cc, {version = true})
222222
if cc_tool and cc_tool.version then
223-
local resdir = _get_llvm_resourcedir(self)
223+
local resdir = _get_llvm_resourcedir(toolchain)
224224
if resdir then
225225
local res_libdir = path.join(resdir, "lib")
226-
-- when -DLLVM_ENABLE_TARGET_RUNTIME_DIR=OFF rtdir is windows/ and rtlink is clang_rt.builtinsi_<arch>.lib
226+
-- when -DLLVM_ENABLE_TARGET_RUNTIME_DIR=OFF rtdir is windows/ and rtlink is clang_rt.builtins_<arch>.lib
227227
-- when ON rtdir is windows/<target-triple> and rtlink is clang_rt.builtins.lib
228-
local target_triple = _get_llvm_target_triple(self)
228+
local target_triple = _get_llvm_target_triple(toolchain)
229229
local arch = target_triple and target_triple:split("-")[1]
230230

231+
local plat
232+
if toolchain:is_plat("windows") then
233+
plat = "windows"
234+
elseif toolchain:is_plat("linux") then
235+
plat = "linux"
236+
elseif toolchain:is_plat("macosx", "ios", "watchos", "appletvos", "applexros") then
237+
plat = "darwin"
238+
end
239+
231240
local tripletdir = target_triple and path.join(res_libdir, "windows", target_triple)
232241
tripletdir = os.isdir(tripletdir) or nil
233242

234-
local rtdir = tripletdir and path.join("windows", target_triple) or "windows"
235-
if os.isdir(path.join(res_libdir, rtdir)) then
243+
local rtdir = tripletdir and path.join(plat, target_triple) or plat
244+
if os.isdir(path.join(res_libdir, rtdir)) and toolchain:is_plat("windows") then
236245
local rtlink = "clang_rt.builtins" .. (tripletdir and ".lib" or ("-" .. arch .. ".lib"))
237246
if os.isfile(path.join(res_libdir, rtdir, rtlink)) then
238-
return res_libdir, path.join(rtdir, rtlink)
247+
return res_libdir, path.join(rtdir, rtlink), path.join(res_libdir, rtdir)
239248
end
240249
end
241-
return res_libdir
250+
return res_libdir, nil, path.join(res_libdir, rtdir)
242251
end
243252
end
244253
end
245254

246255
-- get llvm target triple
247-
function _get_llvm_target_triple(self)
256+
function _get_llvm_target_triple(toolchain)
248257
local llvm_targettriple = _g._LLVM_TARGETTRIPLE
249258
if llvm_targettriple == nil then
250-
local outdata = try { function() return os.iorunv(self:program(), {"-print-target-triple"}, {envs = self:runenvs()}) end }
259+
local outdata = try { function() return os.iorunv(toolchain:tool("cc"), {"-print-target-triple"}) end }
251260
if outdata then
252261
llvm_targettriple = outdata:trim()
253262
end
@@ -268,50 +277,79 @@ function get_llvm_dirs(toolchain)
268277
local bindir, libdir, cxxlibdir, includedir, cxxincludedir, resdir, rtdir, rtlink
269278
if rootdir then
270279
bindir = path.join(rootdir, "bin")
271-
if bindir then
272-
bindir = os.isdir(bindir) and bindir or nil
273-
end
280+
bindir = os.isdir(bindir) and bindir or nil
274281

275282
libdir = path.join(rootdir, "lib")
276-
if libdir then
277-
libdir = os.isdir(libdir) and libdir or nil
278-
end
283+
libdir = os.isdir(libdir) and libdir or nil
279284

280285
if libdir then
281-
cxxlibdir = libdir and path.join(libdir, "c++")
282-
if cxxlibdir then
286+
cxxlibdir = path.join(libdir, "c++")
287+
cxxlibdir = os.isdir(cxxlibdir) and cxxlibdir or nil
288+
if not cxxlibdir then
289+
cxxlibdir = path.join(libdir, _get_llvm_target_triple(toolchain))
283290
cxxlibdir = os.isdir(cxxlibdir) and cxxlibdir or nil
284291
end
285292
end
286293

287294
includedir = path.join(rootdir, "include")
288-
if includedir then
289-
includedir = os.isdir(includedir) and includedir or nil
290-
end
295+
includedir = os.isdir(includedir) and includedir or nil
291296

292297
if includedir then
293-
cxxincludedir = includedir and path.join(includedir, "c++", "v1") or nil
294-
if cxxincludedir then
295-
cxxincludedir = os.isdir(cxxincludedir) and cxxincludedir or nil
296-
end
298+
cxxincludedir = path.join(includedir, "c++", "v1")
299+
cxxincludedir = os.isdir(cxxincludedir) and cxxincludedir or nil
297300
end
298301

299302
resdir = _get_llvm_resourcedir(toolchain)
300-
if toolchain:is_plat("windows") then
301-
rtdir, rtlink = _get_llvm_compiler_win_rtdir_and_link(toolchain)
302-
end
303+
rtdir, rtlink, rtlib = _get_llvm_compiler_rtdir_and_link(toolchain)
303304
end
304305

305306
llvm_dirs = {root = rootdir,
306-
bin = bindir,
307-
lib = libdir,
308-
cxxlib = cxxlibdir,
309-
include = includedir,
310-
cxxinclude = cxxincludedir,
311-
res = resdir,
312-
rt = rtdir,
313-
rtlink = rtlink }
307+
bin = bindir,
308+
lib = libdir,
309+
cxxlib = cxxlibdir,
310+
include = includedir,
311+
cxxinclude = cxxincludedir,
312+
res = resdir,
313+
rt = rtdir,
314+
rtlib = rtlib,
315+
rtlink = rtlink }
314316
_g.llvm_dirs = llvm_dirs
315317
end
316318
return llvm_dirs
317319
end
320+
321+
-- set runenvs for llvm
322+
function set_llvm_runenvs(toolchain)
323+
local pathname = "PATH"
324+
if toolchain:is_plat("windows") then
325+
local curenvs = os.getenvs()
326+
for k, _ in pairs(curenvs) do
327+
if pathname:lower() == k:lower() then
328+
pathname = k
329+
break
330+
end
331+
end
332+
end
333+
334+
local dirs = get_llvm_dirs(toolchain)
335+
if dirs then
336+
if dirs.bin and toolchain:is_plat("windows") then
337+
toolchain:add("runenvs", pathname, dirs.bin)
338+
end
339+
for _, dir in ipairs({dirs.lib or false, dirs.cxxlib or false, dirs.rtlib or false}) do
340+
if dir then
341+
if toolchain:is_plat("windows") then
342+
toolchain:add("runenvs", pathname, dir)
343+
elseif toolchain:is_plat("linux", "bsd") then
344+
toolchain:add("runenvs", "LD_LIBRARY_PATH", dir)
345+
elseif toolchain:is_plat("macosx") then
346+
-- 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++)
347+
-- e.g dyld[5195]: Symbol not found: __ZnwmSt19__type_descriptor_t
348+
-- Referenced from: <378C7CC2-7CD6-3B88-9C66-FE198E30462B> /usr/local/Cellar/llvm/21.1.5/bin/clang-21
349+
-- Expected as weak-def export from some loaded dylibSymbol not found: __ZnamSt19__type_descriptor_t
350+
toolchain:add("runenvs", "DYLD_FALLBACK_LIBRARY_PATH", dir)
351+
end
352+
end
353+
end
354+
end
355+
end

xmake/toolchains/clang/load.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import("detect.sdks.find_vstudio")
2222
import("detect.sdks.find_mingw")
2323
import("core.project.config")
24+
import("private.utils.toolchain", {alias = "toolchain_utils"})
2425

2526
-- add the given vs environment
2627
function _add_vsenv(toolchain, name, curenvs)
@@ -66,6 +67,8 @@ function main(toolchain, suffix)
6667
target = "armv7"
6768
end
6869

70+
toolchain_utils.set_llvm_runenvs(toolchain)
71+
6972
if toolchain:is_plat("windows") then
7073
target = target .. "-windows-msvc"
7174

xmake/toolchains/llvm/xmake.lua

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,7 @@ toolchain("llvm")
5454
toolchain:add("runtimes", "MT", "MTd", "MD", "MDd")
5555
end
5656

57-
local dirs = toolchain_utils.get_llvm_dirs(toolchain)
58-
if dirs and dirs.rt then
59-
toolchain:add("runenvs", dirs.rt)
60-
end
57+
toolchain_utils.set_llvm_runenvs(toolchain)
6158

6259
-- add target flags
6360
local target

0 commit comments

Comments
 (0)