From d3a3a4d45e92a4b6af0438e0df81dce9d0bd4dc4 Mon Sep 17 00:00:00 2001 From: star9029 Date: Sat, 20 Dec 2025 23:30:23 +0800 Subject: Refactor windows asan --- xmake/core/package/package.lua | 40 ++++++++++++++++++++++++-- xmake/modules/package/tools/cmake.lua | 4 +++ xmake/rules/c++/config/sanitizer.lua | 53 +++++++++++++++++++++++++++-------- xmake/toolchains/clang-cl/load.lua | 4 --- 4 files changed, 83 insertions(+), 18 deletions(-) diff --git a/xmake/core/package/package.lua b/xmake/core/package/package.lua index 4a32bbdf7..75e134b2a 100644 --- a/xmake/core/package/package.lua +++ b/xmake/core/package/package.lua @@ -2460,17 +2460,51 @@ function _instance:_generate_sanitizer_configs(checkmode, sourcekind) -- add cflags local configs = {} - if sourcekind and self:has_tool(sourcekind, "cl", "clang", "clangxx", "gcc", "gxx") then + if sourcekind and self:has_tool(sourcekind, "cl", "clang", "clangxx", "clang_cl", "gcc", "gxx") then local cflag = sourcekind == "cxx" and "cxxflags" or "cflags" configs[cflag] = "-fsanitize=" .. checkmode end + local ldflags = {} -- add ldflags and shflags -- msvc does not have an fsanitize linker flag, so the 'link' tool is excluded if self:has_tool("ld", "clang", "clangxx", "gcc", "gxx") then - configs.ldflags = "-fsanitize=" .. checkmode - configs.shflags = "-fsanitize=" .. checkmode + table.insert(ldflags, "-fsanitize=" .. checkmode) end + + if self:is_plat("windows") and checkmode == "address" and not self:has_tool("cxx", "cl") then + assert(self:has_runtime("MD", "MT"), "clang asan only support MD/MT runtime on windows") + if self:has_tool("cxx", "clang", "clangxx") then + if self:has_runtime("MT") then + table.insert(ldflags, "-D_MT") + elseif self:has_runtime("MD") then + table.join2(ldflags, {"-D_MT", "-D_DLL"}) + end + elseif self:has_tool("cxx", "clang_cl") then + -- TODO: This is hack, try to find a way to let cmake use clang++ for link + -- @see https://gitlab.kitware.com/cmake/cmake/-/issues/26430 + local outdata, errdata = assert(os.iorunv(self:build_getenv("cc"), {"-print-resource-dir"})) + local libdir = path.join(errdata:trim(), "lib/windows") + + local kind + if self:has_runtime("MD") then + kind = "dynamic" + elseif self:has_runtime("MT") then + kind = "static" + end + + local driver = self:has_tool("ld", "lld-link", "link") and "" or "-Wl," + local thunk = path.join(libdir, string.format("clang_rt.asan_%s_runtime_thunk-x86_64.lib", kind)) + table.join2(ldflags, { + path.unix(path.join(libdir, "clang_rt.asan_dynamic-x86_64.lib")), + driver .. "/WHOLEARCHIVE:" .. path.unix(thunk), + driver .. "/INFERASANLIBS:NO", + }) + end + end + + configs.ldflags = ldflags + configs.shflags = ldflags return configs end diff --git a/xmake/modules/package/tools/cmake.lua b/xmake/modules/package/tools/cmake.lua index 6745ee5bb..7bf9b8b31 100644 --- a/xmake/modules/package/tools/cmake.lua +++ b/xmake/modules/package/tools/cmake.lua @@ -426,6 +426,10 @@ function _get_configs_for_generic(package, configs, opt) if package:is_library() then envs.BUILD_SHARED_LIBS = package:config("shared") and "ON" or "OFF" end + -- https://cmake.org/cmake/help/latest/variable/CMAKE_LINKER_TYPE.html + if package:has_tool("ld", "link") then + envs.CMAKE_LINKER_TYPE = "MSVC" + end _fix_zigcc_linker_cmake(package, envs) _insert_configs_from_envs(configs, envs, opt) end diff --git a/xmake/rules/c++/config/sanitizer.lua b/xmake/rules/c++/config/sanitizer.lua index aeea8492f..e6606efe9 100644 --- a/xmake/rules/c++/config/sanitizer.lua +++ b/xmake/rules/c++/config/sanitizer.lua @@ -22,6 +22,12 @@ import("core.project.project") import("lib.detect.find_tool") import("core.base.semver") +import("private.utils.toolchain", {alias = "toolchain_utils"}) + +function _get_clang_asan_library_dir(target) + local toolchain = target:toolchain("clang-cl") or target:toolchain("clang") + return path.join(toolchain_utils.get_llvm_resourcedir(toolchain), "lib/windows") +end -- add build sanitizer function _add_build_sanitizer(target, sourcekind, checkmode) @@ -44,6 +50,39 @@ function _add_build_sanitizer(target, sourcekind, checkmode) target:add("ldflags", "-fsanitize=" .. checkmode, {force = true}) target:add("shflags", "-fsanitize=" .. checkmode, {force = true}) end + + if target:is_plat("windows") and checkmode == "address" and not target:has_tool("cxx", "cl") then + assert(target:has_runtime("MD", "MT"), "clang asan only support MD/MT runtime on windows") + + local ldflags = {} + if target:has_tool("ld", "clang", "clangxx") then + if target:has_runtime("MT") then + table.insert(ldflags, "-D_MT") + elseif target:has_runtime("MD") then + table.join2(ldflags, {"-D_MT", "-D_DLL"}) + end + else + -- cmake unsupported use clang++ as linker with clang-cl compiler, so we keep using lld-link/link as linker + -- @see https://gitlab.kitware.com/cmake/cmake/-/issues/26430 + local kind + if target:has_runtime("MD") then + kind = "dynamic" + elseif target:has_runtime("MT") then + kind = "static" + end + + local libdir = _get_clang_asan_library_dir(target) + local driver = target:has_tool("ld", "lld-link", "link") and "" or "-Wl," + local thunk = path.join(libdir, string.format("clang_rt.asan_%s_runtime_thunk-x86_64.lib", kind)) + table.join2(ldflags, { + path.unix(path.join(libdir, "clang_rt.asan_dynamic-x86_64.lib")), + driver .. "/WHOLEARCHIVE:" .. path.unix(thunk), + driver .. "/INFERASANLIBS:NO", + }) + end + target:add("ldflags", ldflags, {force = true}) + target:add("shflags", ldflags, {force = true}) + end end function main(target, sourcekind) @@ -68,17 +107,7 @@ function main(target, sourcekind) -- we need to load runenvs for msvc -- @see https://github.com/xmake-io/xmake/issues/4176 if target:is_plat("windows") and target:is_binary() then - if target:has_tool("cxx", "clang_cl") then - local clang_cl = target:toolchain("clang-cl") - if clang_cl then - local envs = clang_cl:runenvs() - local vscmd_ver = envs and envs.VSCMD_VER - if vscmd_ver and semver.match(vscmd_ver):ge("17.7") then - local clang_cl_tool = assert(find_tool("clang-cl", {envs = envs}), "clang-cl not found!") - target:add("runenvs", "PATH", path.directory(clang_cl_tool.program)) - end - end - else + if target:has_tool("cxx", "cl") then local msvc = target:toolchain("msvc") if msvc then local envs = msvc:runenvs() @@ -88,6 +117,8 @@ function main(target, sourcekind) target:add("runenvs", "PATH", path.directory(cl.program)) end end + else + target:add("runenvs", "PATH", _get_clang_asan_library_dir(target)) end end end diff --git a/xmake/toolchains/clang-cl/load.lua b/xmake/toolchains/clang-cl/load.lua index 8dab94d4a..fb95724b9 100644 --- a/xmake/toolchains/clang-cl/load.lua +++ b/xmake/toolchains/clang-cl/load.lua @@ -41,10 +41,6 @@ function main(toolchain) toolchain:set("toolset", "ld", "lld-link") toolchain:set("toolset", "sh", "lld-link") toolchain:set("toolset", "ar", "llvm-ar") - elseif project.policy("build.sanitizer.address") then - toolchain:set("toolset", "ld", "clang++") - toolchain:set("toolset", "sh", "clang++") - toolchain:set("toolset", "ar", "llvm-ar") else toolchain:set("toolset", "ld", "link.exe") toolchain:set("toolset", "sh", "link.exe") -- cgit v1.3.1 From 3c6c162da56f3fe7b9b99dd3f1194e0a545c68f7 Mon Sep 17 00:00:00 2001 From: star9029 Date: Sun, 21 Dec 2025 17:01:53 +0800 Subject: fix has_tool lld-link --- xmake/core/package/package.lua | 2 +- xmake/rules/c++/config/sanitizer.lua | 2 +- xmake/rules/platform/windows/subsystem/xmake.lua | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/xmake/core/package/package.lua b/xmake/core/package/package.lua index 75e134b2a..b658b09f6 100644 --- a/xmake/core/package/package.lua +++ b/xmake/core/package/package.lua @@ -2493,7 +2493,7 @@ function _instance:_generate_sanitizer_configs(checkmode, sourcekind) kind = "static" end - local driver = self:has_tool("ld", "lld-link", "link") and "" or "-Wl," + local driver = self:has_tool("ld", "lld_link", "link") and "" or "-Wl," local thunk = path.join(libdir, string.format("clang_rt.asan_%s_runtime_thunk-x86_64.lib", kind)) table.join2(ldflags, { path.unix(path.join(libdir, "clang_rt.asan_dynamic-x86_64.lib")), diff --git a/xmake/rules/c++/config/sanitizer.lua b/xmake/rules/c++/config/sanitizer.lua index e6606efe9..1862d3e9b 100644 --- a/xmake/rules/c++/config/sanitizer.lua +++ b/xmake/rules/c++/config/sanitizer.lua @@ -72,7 +72,7 @@ function _add_build_sanitizer(target, sourcekind, checkmode) end local libdir = _get_clang_asan_library_dir(target) - local driver = target:has_tool("ld", "lld-link", "link") and "" or "-Wl," + local driver = target:has_tool("ld", "lld_link", "link") and "" or "-Wl," local thunk = path.join(libdir, string.format("clang_rt.asan_%s_runtime_thunk-x86_64.lib", kind)) table.join2(ldflags, { path.unix(path.join(libdir, "clang_rt.asan_dynamic-x86_64.lib")), diff --git a/xmake/rules/platform/windows/subsystem/xmake.lua b/xmake/rules/platform/windows/subsystem/xmake.lua index 87204e64f..b4985a3e1 100644 --- a/xmake/rules/platform/windows/subsystem/xmake.lua +++ b/xmake/rules/platform/windows/subsystem/xmake.lua @@ -40,7 +40,7 @@ rule("platform.windows.subsystem") if target:has_tool("ld", "clang", "clangxx", "clang_cl") then target:add("ldflags", {"-Xlinker", "-subsystem:" .. subsystem}, {force = true, expand = false}) - elseif target:has_tool("ld", "link", "lld-link") then + elseif target:has_tool("ld", "link", "lld_link") then target:add("ldflags", "/SUBSYSTEM:" .. subsystem:upper(), {force = true}) elseif target:has_tool("ld", "gcc", "gxx") then target:add("ldflags", "-m" .. subsystem, {force = true}) -- cgit v1.3.1 From a9e51834621aedeb6e8aa5aec0880af28ac4200d Mon Sep 17 00:00:00 2001 From: star9029 Date: Mon, 22 Dec 2025 11:42:39 +0800 Subject: clean code to toolchain_utils --- xmake/core/package/package.lua | 43 ++++++------------------------- xmake/modules/private/utils/toolchain.lua | 40 +++++++++++++++++++++++++++- xmake/rules/c++/config/sanitizer.lua | 40 +++------------------------- xmake/toolchains/clang-cl/load.lua | 3 ++- xmake/toolchains/clang/load.lua | 2 -- 5 files changed, 53 insertions(+), 75 deletions(-) diff --git a/xmake/core/package/package.lua b/xmake/core/package/package.lua index b658b09f6..bdd09ed5a 100644 --- a/xmake/core/package/package.lua +++ b/xmake/core/package/package.lua @@ -2457,8 +2457,6 @@ end -- generate sanitizer configs function _instance:_generate_sanitizer_configs(checkmode, sourcekind) - - -- add cflags local configs = {} if sourcekind and self:has_tool(sourcekind, "cl", "clang", "clangxx", "clang_cl", "gcc", "gxx") then local cflag = sourcekind == "cxx" and "cxxflags" or "cflags" @@ -2466,45 +2464,20 @@ function _instance:_generate_sanitizer_configs(checkmode, sourcekind) end local ldflags = {} - -- add ldflags and shflags -- msvc does not have an fsanitize linker flag, so the 'link' tool is excluded if self:has_tool("ld", "clang", "clangxx", "gcc", "gxx") then table.insert(ldflags, "-fsanitize=" .. checkmode) end if self:is_plat("windows") and checkmode == "address" and not self:has_tool("cxx", "cl") then - assert(self:has_runtime("MD", "MT"), "clang asan only support MD/MT runtime on windows") - if self:has_tool("cxx", "clang", "clangxx") then - if self:has_runtime("MT") then - table.insert(ldflags, "-D_MT") - elseif self:has_runtime("MD") then - table.join2(ldflags, {"-D_MT", "-D_DLL"}) - end - elseif self:has_tool("cxx", "clang_cl") then - -- TODO: This is hack, try to find a way to let cmake use clang++ for link - -- @see https://gitlab.kitware.com/cmake/cmake/-/issues/26430 - local outdata, errdata = assert(os.iorunv(self:build_getenv("cc"), {"-print-resource-dir"})) - local libdir = path.join(errdata:trim(), "lib/windows") - - local kind - if self:has_runtime("MD") then - kind = "dynamic" - elseif self:has_runtime("MT") then - kind = "static" - end - - local driver = self:has_tool("ld", "lld_link", "link") and "" or "-Wl," - local thunk = path.join(libdir, string.format("clang_rt.asan_%s_runtime_thunk-x86_64.lib", kind)) - table.join2(ldflags, { - path.unix(path.join(libdir, "clang_rt.asan_dynamic-x86_64.lib")), - driver .. "/WHOLEARCHIVE:" .. path.unix(thunk), - driver .. "/INFERASANLIBS:NO", - }) - end - end - - configs.ldflags = ldflags - configs.shflags = ldflags + local toolchain_utils = sandbox_module.import("private.utils.toolchain", {anonymous = true}) + table.join2(ldflags, toolchain_utils.add_llvm_asan_flags(self)) + end + + if #ldflags ~= 0 then + configs.ldflags = ldflags + configs.shflags = ldflags + end return configs end diff --git a/xmake/modules/private/utils/toolchain.lua b/xmake/modules/private/utils/toolchain.lua index c0cec7f74..864d2d76e 100644 --- a/xmake/modules/private/utils/toolchain.lua +++ b/xmake/modules/private/utils/toolchain.lua @@ -467,7 +467,9 @@ function add_llvm_runenvs(toolchain) for _, dir in ipairs({dirs.libdir or false, dirs.cxxlibdir or false, dirs.rtlibdir or false}) do if dir then if toolchain:is_plat("windows") or is_host("windows") then - toolchain:add("runenvs", "PATH", dir) + -- clang asan path must be first + local envs = toolchain:get("runenvs")["PATH"] + table.insert(envs, 1 , dir) elseif toolchain:is_plat("linux", "bsd") then toolchain:add("runenvs", "LD_LIBRARY_PATH", dir) elseif toolchain:is_plat("macosx") then @@ -481,3 +483,39 @@ function add_llvm_runenvs(toolchain) end end end + +-- add address sanitizer flags for llvm +function add_llvm_asan_flags(target) + assert(target:has_runtime("MD", "MT"), "clang asan only support MD/MT runtime on windows") + + local ldflags = {} + if target:has_tool("cxx", "clang", "clangxx") then + if target:has_runtime("MT") then + table.insert(ldflags, "-D_MT") + elseif target:has_runtime("MD") then + table.join2(ldflags, {"-D_MT", "-D_DLL"}) + end + elseif target:has_tool("cxx", "clang_cl") then + -- TODO: This is hack, try to find a way to let cmake use clang++ for link + -- @see https://gitlab.kitware.com/cmake/cmake/-/issues/26430 + local toolchain = target:toolchain("clang-cl") or target:toolchain("clang") + local libdir = assert(get_llvm_dirs(toolchain).rtlibdir, "clang resource directory not found") + + local kind + if target:has_runtime("MD") then + kind = "dynamic" + elseif target:has_runtime("MT") then + kind = "static" + end + + local driver = target:has_tool("ld", "lld_link", "link") and "" or "-Wl," + local thunk = path.join(libdir, string.format("clang_rt.asan_%s_runtime_thunk-x86_64.lib", kind)) + table.join2(ldflags, { + path.unix(path.join(libdir, "clang_rt.asan_dynamic-x86_64.lib")), + driver .. "/WHOLEARCHIVE:" .. path.unix(thunk), + driver .. "/INFERASANLIBS:NO", + }) + end + + return ldflags +end diff --git a/xmake/rules/c++/config/sanitizer.lua b/xmake/rules/c++/config/sanitizer.lua index 1862d3e9b..646197c0c 100644 --- a/xmake/rules/c++/config/sanitizer.lua +++ b/xmake/rules/c++/config/sanitizer.lua @@ -24,11 +24,6 @@ import("lib.detect.find_tool") import("core.base.semver") import("private.utils.toolchain", {alias = "toolchain_utils"}) -function _get_clang_asan_library_dir(target) - local toolchain = target:toolchain("clang-cl") or target:toolchain("clang") - return path.join(toolchain_utils.get_llvm_resourcedir(toolchain), "lib/windows") -end - -- add build sanitizer function _add_build_sanitizer(target, sourcekind, checkmode) -- add cflags @@ -52,36 +47,11 @@ function _add_build_sanitizer(target, sourcekind, checkmode) end if target:is_plat("windows") and checkmode == "address" and not target:has_tool("cxx", "cl") then - assert(target:has_runtime("MD", "MT"), "clang asan only support MD/MT runtime on windows") - - local ldflags = {} - if target:has_tool("ld", "clang", "clangxx") then - if target:has_runtime("MT") then - table.insert(ldflags, "-D_MT") - elseif target:has_runtime("MD") then - table.join2(ldflags, {"-D_MT", "-D_DLL"}) - end - else - -- cmake unsupported use clang++ as linker with clang-cl compiler, so we keep using lld-link/link as linker - -- @see https://gitlab.kitware.com/cmake/cmake/-/issues/26430 - local kind - if target:has_runtime("MD") then - kind = "dynamic" - elseif target:has_runtime("MT") then - kind = "static" - end - - local libdir = _get_clang_asan_library_dir(target) - local driver = target:has_tool("ld", "lld_link", "link") and "" or "-Wl," - local thunk = path.join(libdir, string.format("clang_rt.asan_%s_runtime_thunk-x86_64.lib", kind)) - table.join2(ldflags, { - path.unix(path.join(libdir, "clang_rt.asan_dynamic-x86_64.lib")), - driver .. "/WHOLEARCHIVE:" .. path.unix(thunk), - driver .. "/INFERASANLIBS:NO", - }) + local ldflags = toolchain_utils.add_llvm_asan_flags(target) + if #ldflags ~= 0 then + target:add("ldflags", ldflags, {force = true}) + target:add("shflags", ldflags, {force = true}) end - target:add("ldflags", ldflags, {force = true}) - target:add("shflags", ldflags, {force = true}) end end @@ -117,8 +87,6 @@ function main(target, sourcekind) target:add("runenvs", "PATH", path.directory(cl.program)) end end - else - target:add("runenvs", "PATH", _get_clang_asan_library_dir(target)) end end end diff --git a/xmake/toolchains/clang-cl/load.lua b/xmake/toolchains/clang-cl/load.lua index fb95724b9..908f31be9 100644 --- a/xmake/toolchains/clang-cl/load.lua +++ b/xmake/toolchains/clang-cl/load.lua @@ -47,9 +47,10 @@ function main(toolchain) toolchain:set("toolset", "ar", "link.exe") end - -- add vs environments toolchain_utils.add_vsenvs(toolchain) + toolchain_utils.add_llvm_runenvs(toolchain) + local flags = toolchain_utils.get_clang_target_flags(toolchain) if flags then toolchain:add("cxflags", flags) diff --git a/xmake/toolchains/clang/load.lua b/xmake/toolchains/clang/load.lua index 4b66ef5d6..80123d5c5 100644 --- a/xmake/toolchains/clang/load.lua +++ b/xmake/toolchains/clang/load.lua @@ -57,9 +57,7 @@ function main(toolchain, suffix) _load_windows(toolchain, suffix) end - -- set llvm runtimes toolchain_utils.set_llvm_runtimes(toolchain) - -- add llvm runenvs toolchain_utils.add_llvm_runenvs(toolchain) end -- cgit v1.3.1 From 05ad043eaf740be73dd0b95b6d5ab97a4d82ac59 Mon Sep 17 00:00:00 2001 From: star9029 Date: Mon, 22 Dec 2025 16:54:25 +0800 Subject: add get_llvm_asan_flags --- xmake/core/package/package.lua | 2 +- xmake/modules/private/utils/toolchain.lua | 16 +++++++++++----- xmake/rules/c++/config/sanitizer.lua | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/xmake/core/package/package.lua b/xmake/core/package/package.lua index bdd09ed5a..6c2742c80 100644 --- a/xmake/core/package/package.lua +++ b/xmake/core/package/package.lua @@ -2471,7 +2471,7 @@ function _instance:_generate_sanitizer_configs(checkmode, sourcekind) if self:is_plat("windows") and checkmode == "address" and not self:has_tool("cxx", "cl") then local toolchain_utils = sandbox_module.import("private.utils.toolchain", {anonymous = true}) - table.join2(ldflags, toolchain_utils.add_llvm_asan_flags(self)) + table.join2(ldflags, toolchain_utils.get_llvm_asan_flags(self)) end if #ldflags ~= 0 then diff --git a/xmake/modules/private/utils/toolchain.lua b/xmake/modules/private/utils/toolchain.lua index 864d2d76e..25ada449c 100644 --- a/xmake/modules/private/utils/toolchain.lua +++ b/xmake/modules/private/utils/toolchain.lua @@ -467,9 +467,15 @@ function add_llvm_runenvs(toolchain) for _, dir in ipairs({dirs.libdir or false, dirs.cxxlibdir or false, dirs.rtlibdir or false}) do if dir then if toolchain:is_plat("windows") or is_host("windows") then - -- clang asan path must be first - local envs = toolchain:get("runenvs")["PATH"] - table.insert(envs, 1 , dir) + -- The dynamic libraries (DLLs) for Clang ASan and MSVC ASan share the same filename, making them incompatible. + -- Currently, runenvs maybe have Visual Studio environment variables. + -- If the Clang path is not prioritized (placed first), the system incorrectly loads the MSVC ASan DLL, resulting in a runtime failure. + local runenvs = toolchain:get("runenvs") + if runenvs and runenvs["PATH"]then + table.insert(runenvs["PATH"], 1 , dir) + else + toolchain:add("runenvs", "PATH", dir) + end elseif toolchain:is_plat("linux", "bsd") then toolchain:add("runenvs", "LD_LIBRARY_PATH", dir) elseif toolchain:is_plat("macosx") then @@ -484,8 +490,8 @@ function add_llvm_runenvs(toolchain) end end --- add address sanitizer flags for llvm -function add_llvm_asan_flags(target) +-- get address sanitizer flags for llvm +function get_llvm_asan_flags(target) assert(target:has_runtime("MD", "MT"), "clang asan only support MD/MT runtime on windows") local ldflags = {} diff --git a/xmake/rules/c++/config/sanitizer.lua b/xmake/rules/c++/config/sanitizer.lua index 646197c0c..3293a6808 100644 --- a/xmake/rules/c++/config/sanitizer.lua +++ b/xmake/rules/c++/config/sanitizer.lua @@ -47,7 +47,7 @@ function _add_build_sanitizer(target, sourcekind, checkmode) end if target:is_plat("windows") and checkmode == "address" and not target:has_tool("cxx", "cl") then - local ldflags = toolchain_utils.add_llvm_asan_flags(target) + local ldflags = toolchain_utils.get_llvm_asan_flags(target) if #ldflags ~= 0 then target:add("ldflags", ldflags, {force = true}) target:add("shflags", ldflags, {force = true}) -- cgit v1.3.1 From 78c5465cdbc234d7d7be3bfc76b6304767aefa44 Mon Sep 17 00:00:00 2001 From: star9029 Date: Mon, 22 Dec 2025 17:40:34 +0800 Subject: Fix runenvs --- xmake/modules/private/utils/toolchain.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xmake/modules/private/utils/toolchain.lua b/xmake/modules/private/utils/toolchain.lua index 25ada449c..8ccaf05d1 100644 --- a/xmake/modules/private/utils/toolchain.lua +++ b/xmake/modules/private/utils/toolchain.lua @@ -471,7 +471,8 @@ function add_llvm_runenvs(toolchain) -- Currently, runenvs maybe have Visual Studio environment variables. -- If the Clang path is not prioritized (placed first), the system incorrectly loads the MSVC ASan DLL, resulting in a runtime failure. local runenvs = toolchain:get("runenvs") - if runenvs and runenvs["PATH"]then + if runenvs and runenvs["PATH"] then + runenvs["PATH"] = table.wrap(runenvs["PATH"]) table.insert(runenvs["PATH"], 1 , dir) else toolchain:add("runenvs", "PATH", dir) -- cgit v1.3.1 From c3733aac1f1eb0a958446b0fcdd6c33861ce48f3 Mon Sep 17 00:00:00 2001 From: ruki Date: Mon, 22 Dec 2025 19:39:18 +0800 Subject: Refactor sanitizer flag addition in sanitizer.lua Refactor the _add_build_sanitizer function to streamline the addition of sanitizer flags and remove redundant code for adding cflags and ldflags. --- xmake/rules/c++/config/sanitizer.lua | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/xmake/rules/c++/config/sanitizer.lua b/xmake/rules/c++/config/sanitizer.lua index 3293a6808..79c88661a 100644 --- a/xmake/rules/c++/config/sanitizer.lua +++ b/xmake/rules/c++/config/sanitizer.lua @@ -26,32 +26,10 @@ import("private.utils.toolchain", {alias = "toolchain_utils"}) -- add build sanitizer function _add_build_sanitizer(target, sourcekind, checkmode) - -- add cflags - local _, cc = target:tool(sourcekind) - local flagnames = { - cc = "cflags", - cxx = "cxxflags", - mm = "mflags", - mxx = "mxflags" - } - local flagname = flagnames[sourcekind] - if flagname and target:has_tool(sourcekind, "cl", "clang", "clangxx", "clang_cl", "gcc", "gxx") then - target:add(flagname, "-fsanitize=" .. checkmode, {force = true}) - end - - -- add ldflags and shflags - -- msvc does not have an fsanitize linker flag, so the 'link' tool is excluded - if target:has_tool("ld", "clang", "clangxx", "gcc", "gxx") then - target:add("ldflags", "-fsanitize=" .. checkmode, {force = true}) - target:add("shflags", "-fsanitize=" .. checkmode, {force = true}) - end - - if target:is_plat("windows") and checkmode == "address" and not target:has_tool("cxx", "cl") then - local ldflags = toolchain_utils.get_llvm_asan_flags(target) - if #ldflags ~= 0 then - target:add("ldflags", ldflags, {force = true}) - target:add("shflags", ldflags, {force = true}) - end + -- add sanitizer flags + local flags = toolchain_utils.get_sanitizer_flags(target, {checkmode = checkmode, sourcekind = sourcekind}) + for name, value in pairs(flags) do + target:add(name, value, {force = true}) end end -- cgit v1.3.1 From dd5d93e1e0c7fe23290ad2e83f94cffb9362d524 Mon Sep 17 00:00:00 2001 From: ruki Date: Mon, 22 Dec 2025 19:39:46 +0800 Subject: Refactor sanitizer flags handling in toolchain.lua --- xmake/modules/private/utils/toolchain.lua | 93 +++++++++++++++++++++---------- 1 file changed, 64 insertions(+), 29 deletions(-) diff --git a/xmake/modules/private/utils/toolchain.lua b/xmake/modules/private/utils/toolchain.lua index 8ccaf05d1..de5d4916f 100644 --- a/xmake/modules/private/utils/toolchain.lua +++ b/xmake/modules/private/utils/toolchain.lua @@ -491,38 +491,73 @@ function add_llvm_runenvs(toolchain) end end --- get address sanitizer flags for llvm -function get_llvm_asan_flags(target) - assert(target:has_runtime("MD", "MT"), "clang asan only support MD/MT runtime on windows") +-- get sanitizer flags +-- +-- @param target the target or package +-- @param opt the options, e.g. {checkmode = "address", sourcekind = "cxx"} +-- +-- @return the sanitizer flags, e.g. {cflags = {}, ldflags = {}} +-- +function get_sanitizer_flags(target, opt) + opt = opt or {} + local checkmode = opt.checkmode + local sourcekind = opt.sourcekind + + -- add cflags + local result = {} + local flagnames = { + cc = "cflags", + cxx = "cxxflags", + mm = "mflags", + mxx = "mxxflags" + } + local flagname = flagnames[sourcekind] + if flagname and target:has_tool(sourcekind, "cl", "clang", "clangxx", "clang_cl", "gcc", "gxx") then + result[flagname] = "-fsanitize=" .. checkmode + end + -- add ldflags local ldflags = {} - if target:has_tool("cxx", "clang", "clangxx") then - if target:has_runtime("MT") then - table.insert(ldflags, "-D_MT") - elseif target:has_runtime("MD") then - table.join2(ldflags, {"-D_MT", "-D_DLL"}) - end - elseif target:has_tool("cxx", "clang_cl") then - -- TODO: This is hack, try to find a way to let cmake use clang++ for link - -- @see https://gitlab.kitware.com/cmake/cmake/-/issues/26430 - local toolchain = target:toolchain("clang-cl") or target:toolchain("clang") - local libdir = assert(get_llvm_dirs(toolchain).rtlibdir, "clang resource directory not found") - - local kind - if target:has_runtime("MD") then - kind = "dynamic" - elseif target:has_runtime("MT") then - kind = "static" - end + -- msvc does not have an fsanitize linker flag, so the 'link' tool is excluded + if target:has_tool("ld", "clang", "clangxx", "gcc", "gxx") then + table.insert(ldflags, "-fsanitize=" .. checkmode) + end + + -- add windows ldflags + if target:is_plat("windows") and checkmode == "address" and not target:has_tool("cxx", "cl") then + assert(target:has_runtime("MD", "MT"), "clang asan only support MD/MT runtime on windows") + if target:has_tool("cxx", "clang", "clangxx") then + if target:has_runtime("MT") then + table.insert(ldflags, "-D_MT") + elseif target:has_runtime("MD") then + table.join2(ldflags, {"-D_MT", "-D_DLL"}) + end + elseif target:has_tool("cxx", "clang_cl") then + -- TODO: This is hack, try to find a way to let cmake use clang++ for link + -- @see https://gitlab.kitware.com/cmake/cmake/-/issues/26430 + local toolchain = target:toolchain("clang-cl") or target:toolchain("clang") + local libdir = assert(get_llvm_dirs(toolchain).rtlibdir, "clang resource directory not found") + + local kind + if target:has_runtime("MD") then + kind = "dynamic" + elseif target:has_runtime("MT") then + kind = "static" + end - local driver = target:has_tool("ld", "lld_link", "link") and "" or "-Wl," - local thunk = path.join(libdir, string.format("clang_rt.asan_%s_runtime_thunk-x86_64.lib", kind)) - table.join2(ldflags, { - path.unix(path.join(libdir, "clang_rt.asan_dynamic-x86_64.lib")), - driver .. "/WHOLEARCHIVE:" .. path.unix(thunk), - driver .. "/INFERASANLIBS:NO", - }) + local driver = target:has_tool("ld", "lld_link", "link") and "" or "-Wl," + local thunk = path.join(libdir, string.format("clang_rt.asan_%s_runtime_thunk-x86_64.lib", kind)) + table.join2(ldflags, { + path.unix(path.join(libdir, "clang_rt.asan_dynamic-x86_64.lib")), + driver .. "/WHOLEARCHIVE:" .. path.unix(thunk), + driver .. "/INFERASANLIBS:NO", + }) + end end - return ldflags + if #ldflags > 0 then + result.ldflags = ldflags + result.shflags = ldflags + end + return result end -- cgit v1.3.1 From 1b6b7d629d464c4640660889695b98c93faaff37 Mon Sep 17 00:00:00 2001 From: ruki Date: Mon, 22 Dec 2025 19:40:12 +0800 Subject: Refactor sanitizer config generation logic --- xmake/core/package/package.lua | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/xmake/core/package/package.lua b/xmake/core/package/package.lua index 6c2742c80..b287ab360 100644 --- a/xmake/core/package/package.lua +++ b/xmake/core/package/package.lua @@ -2457,28 +2457,8 @@ end -- generate sanitizer configs function _instance:_generate_sanitizer_configs(checkmode, sourcekind) - local configs = {} - if sourcekind and self:has_tool(sourcekind, "cl", "clang", "clangxx", "clang_cl", "gcc", "gxx") then - local cflag = sourcekind == "cxx" and "cxxflags" or "cflags" - configs[cflag] = "-fsanitize=" .. checkmode - end - - local ldflags = {} - -- msvc does not have an fsanitize linker flag, so the 'link' tool is excluded - if self:has_tool("ld", "clang", "clangxx", "gcc", "gxx") then - table.insert(ldflags, "-fsanitize=" .. checkmode) - end - - if self:is_plat("windows") and checkmode == "address" and not self:has_tool("cxx", "cl") then - local toolchain_utils = sandbox_module.import("private.utils.toolchain", {anonymous = true}) - table.join2(ldflags, toolchain_utils.get_llvm_asan_flags(self)) - end - - if #ldflags ~= 0 then - configs.ldflags = ldflags - configs.shflags = ldflags - end - return configs + local toolchain_utils = sandbox_module.import("private.utils.toolchain", {anonymous = true}) + return toolchain_utils.get_sanitizer_flags(self, {checkmode = checkmode, sourcekind = sourcekind}) end -- generate building configs for has_xxx/check_xxx -- cgit v1.3.1 From 035e548d39f6061f35c6ec3478299b4e3180dc58 Mon Sep 17 00:00:00 2001 From: ruki Date: Mon, 22 Dec 2025 19:42:35 +0800 Subject: Update load.lua --- xmake/toolchains/clang/load.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/xmake/toolchains/clang/load.lua b/xmake/toolchains/clang/load.lua index 80123d5c5..14bffea51 100644 --- a/xmake/toolchains/clang/load.lua +++ b/xmake/toolchains/clang/load.lua @@ -18,7 +18,7 @@ -- @file xmake.lua -- -import("detect.sdks.find_mingw") +-- imports import("core.project.config") import("core.project.project") import("private.utils.toolchain", {alias = "toolchain_utils"}) @@ -57,7 +57,9 @@ function main(toolchain, suffix) _load_windows(toolchain, suffix) end + -- set llvm runtimes toolchain_utils.set_llvm_runtimes(toolchain) + -- add llvm runenvs toolchain_utils.add_llvm_runenvs(toolchain) end -- cgit v1.3.1 From 2f90958cf42bdaa35047826904085d1f796b2a05 Mon Sep 17 00:00:00 2001 From: ruki Date: Mon, 22 Dec 2025 19:44:20 +0800 Subject: Update load.lua --- xmake/toolchains/clang-cl/load.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xmake/toolchains/clang-cl/load.lua b/xmake/toolchains/clang-cl/load.lua index 908f31be9..dbc6c5bed 100644 --- a/xmake/toolchains/clang-cl/load.lua +++ b/xmake/toolchains/clang-cl/load.lua @@ -47,10 +47,13 @@ function main(toolchain) toolchain:set("toolset", "ar", "link.exe") end - toolchain_utils.add_vsenvs(toolchain) + -- set llvm runtimes + toolchain_utils.set_llvm_runtimes(toolchain) + -- add llvm runenvs toolchain_utils.add_llvm_runenvs(toolchain) + -- add target flags local flags = toolchain_utils.get_clang_target_flags(toolchain) if flags then toolchain:add("cxflags", flags) -- cgit v1.3.1 From be30fc210ba8de106e9ab7b361d05c0ad28cf57d Mon Sep 17 00:00:00 2001 From: ruki Date: Mon, 22 Dec 2025 19:46:14 +0800 Subject: Update load.lua --- xmake/toolchains/clang-cl/load.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xmake/toolchains/clang-cl/load.lua b/xmake/toolchains/clang-cl/load.lua index dbc6c5bed..f69b98cb3 100644 --- a/xmake/toolchains/clang-cl/load.lua +++ b/xmake/toolchains/clang-cl/load.lua @@ -47,9 +47,9 @@ function main(toolchain) toolchain:set("toolset", "ar", "link.exe") end - -- set llvm runtimes - toolchain_utils.set_llvm_runtimes(toolchain) - + -- add vs environments + toolchain_utils.add_vsenvs(toolchain) + -- add llvm runenvs toolchain_utils.add_llvm_runenvs(toolchain) -- cgit v1.3.1 From d72d0378c40faa23a3063bacfc47e08b919c4031 Mon Sep 17 00:00:00 2001 From: ruki Date: Mon, 22 Dec 2025 19:48:26 +0800 Subject: Update toolchain.lua --- xmake/modules/private/utils/toolchain.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xmake/modules/private/utils/toolchain.lua b/xmake/modules/private/utils/toolchain.lua index de5d4916f..cd2f20736 100644 --- a/xmake/modules/private/utils/toolchain.lua +++ b/xmake/modules/private/utils/toolchain.lua @@ -473,7 +473,7 @@ function add_llvm_runenvs(toolchain) local runenvs = toolchain:get("runenvs") if runenvs and runenvs["PATH"] then runenvs["PATH"] = table.wrap(runenvs["PATH"]) - table.insert(runenvs["PATH"], 1 , dir) + table.insert(runenvs["PATH"], 1, dir) else toolchain:add("runenvs", "PATH", dir) end -- cgit v1.3.1