Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support custom vc build tools #5823

Merged
merged 13 commits into from
Nov 20, 2024
121 changes: 121 additions & 0 deletions xmake/modules/detect/sdks/find_vstudio.lua
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,127 @@ function get_vcvars()
return realvcvars
end

function find_build_tools(opt)
opt = opt or {}

local sdkdir = opt.sdkdir
if not sdkdir or not os.isdir(sdkdir) then
return
end

local variables = {}
local VCToolsVersion
local VCToolsVersionDirs = os.dirs(path.join(sdkdir, "VC/Tools/MSVC/*"))
for _, dir in ipairs(VCToolsVersionDirs) do
local ver = path.filename(dir)
if ver == opt.vs_toolset then
VCToolsVersion = ver
star-hengxing marked this conversation as resolved.
Show resolved Hide resolved
break
end
end

if not VCToolsVersion and #VCToolsVersionDirs ~= 0 then
VCToolsVersion = path.filename(VCToolsVersionDirs[1])
star-hengxing marked this conversation as resolved.
Show resolved Hide resolved
else
return
end
variables.VCToolsVersion = VCToolsVersion
variables.VCToolsInstallDir = path.join(sdkdir, "VC/Tools/MSVC", VCToolsVersion)

local tmp_version
local WindowsSDKVersion
local WindowsSDKVersionsDirs = os.dirs(path.join(sdkdir, "Windows Kits/10/bin/*"))
star-hengxing marked this conversation as resolved.
Show resolved Hide resolved
for _, dir in ipairs(WindowsSDKVersionsDirs) do
local ver = path.filename(dir)
if ver == opt.vs_sdkver then
WindowsSDKVersion = ver
break
end

if ver:startswith("10") then
tmp_version = ver
end
end

if not WindowsSDKVersion and #WindowsSDKVersionsDirs ~= 0 then
WindowsSDKVersion = tmp_version
else
return
end
variables.WindowsSDKVersion = WindowsSDKVersion
variables.WindowsSDKDir = path.join(sdkdir, "Windows Kits/10")

local includedirs = {
path.join(variables.VCToolsInstallDir, "include"),
path.join(variables.WindowsSDKDir, "Include", WindowsSDKVersion, "ucrt"),
path.join(variables.WindowsSDKDir, "Include", WindowsSDKVersion, "shared"),
path.join(variables.WindowsSDKDir, "Include", WindowsSDKVersion, "um"),
path.join(variables.WindowsSDKDir, "Include", WindowsSDKVersion, "winrt"),
path.join(variables.WindowsSDKDir, "Include", WindowsSDKVersion, "cppwinrt"),
}

local linkdirs = {
path.join(variables.VCToolsInstallDir, "lib"),
path.join(variables.WindowsSDKDir, "Lib", WindowsSDKVersion, "ucrt"),
path.join(variables.WindowsSDKDir, "Lib", WindowsSDKVersion, "um"),
}

local archs = {
"x86",
"x64",
"arm",
"arm64",
}

local vcvarsall = {}
for _, target_arch in ipairs(archs) do
local lib = {}
for _, lib_dir in ipairs(linkdirs) do
local dir = path.join(lib_dir, target_arch)
if os.isdir(dir) then
table.insert(lib, dir)
end
end

if #lib ~= 0 then
local vcvars = {
BUILD_TOOLS_ROOT = sdkdir,
INCLUDE = path.joinenv(includedirs),
WindowsSDKDir = variables.WindowsSDKDir,
WindowsSDKVersion = WindowsSDKVersion,
VCToolsInstallDir = variables.VCToolsInstallDir,
VSCMD_ARG_HOST_ARCH = "x64",
}

local buidl_tools_bin = {}
local host_dir = "Host" .. vcvars.VSCMD_ARG_HOST_ARCH
if is_host("windows") then
table.insert(buidl_tools_bin, path.join(vcvars.VCToolsInstallDir, "bin", host_dir, target_arch))
table.insert(buidl_tools_bin, path.join(vcvars.WindowsSDKDir, "bin", WindowsSDKVersion))
table.insert(buidl_tools_bin, path.join(vcvars.WindowsSDKDir, "bin", WindowsSDKVersion, "ucrt"))
elseif is_host("linux") then
-- for msvc-wine
table.insert(buidl_tools_bin, path.join(sdkdir, "bin", target_arch))
end

vcvars.VSCMD_ARG_TGT_ARCH = target_arch
vcvars.LIB = path.joinenv(lib)
vcvars.BUILD_TOOLS_BIN = path.joinenv(buidl_tools_bin)

local PATH = buidl_tools_bin
table.join2(PATH, path.splitenv(os.getenv("PATH")))
vcvars.PATH = path.joinenv(PATH)

vcvarsall[target_arch] = vcvars
end
end
-- for _, host_arch in ipairs(archs) do
-- local host_dir = "Host" .. arch
-- end

return vcvarsall
end

-- load vcvarsall environment variables
function _load_vcvarsall(vcvarsall, vsver, arch, opt)
opt = opt or {}
Expand Down
8 changes: 7 additions & 1 deletion xmake/modules/package/tools/cmake.lua
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,11 @@ function _get_configs_for_windows(package, configs, opt)
if not opt._configs_str:find("CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY") then
table.insert(configs, "-DCMAKE_COMPILE_PDB_OUTPUT_DIRECTORY=pdb")
end
_get_configs_for_generic(package, configs, opt)
if package:is_cross() then
_get_configs_for_cross(package, configs, opt)
else
_get_configs_for_generic(package, configs, opt)
end
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

貌似 windows 平台使用了交叉编译 configs 反而才是对的,不过可能会 break 一些包。
比如在交叉编译下,CMAKE_SYSTEM_VERSION 这个值是空的,需要手动传参

end

-- get configs for android
Expand Down Expand Up @@ -659,6 +663,8 @@ function _get_configs_for_cross(package, configs, opt)
local system_name = package:targetos() or "Linux"
if system_name == "linux" then
system_name = "Linux"
elseif system_name == "windows" then
system_name = "Windows"
end
envs.CMAKE_SYSTEM_NAME = system_name
end
Expand Down
19 changes: 10 additions & 9 deletions xmake/plugins/project/clang/compile_commands.lua
Original file line number Diff line number Diff line change
Expand Up @@ -60,27 +60,28 @@ function _get_windows_sdk_arguments(target)
local args = {}
local msvc = target:toolchain("msvc")
if msvc then
local includedirs = {}
local envs = msvc:runenvs()
local WindowsSdkDir = envs.WindowsSdkDir
local WindowsSDKVersion = envs.WindowsSDKVersion
local VCToolsInstallDir = envs.VCToolsInstallDir
if WindowsSdkDir and WindowsSDKVersion then
local includedirs = os.dirs(path.join(WindowsSdkDir, "Include", envs.WindowsSDKVersion, "*"))
table.join2(includedirs, os.dirs(path.join(WindowsSdkDir, "Include", envs.WindowsSDKVersion, "*")))
for _, tool in ipairs({"atlmfc", "diasdk"}) do
local tool_dir = path.join(WindowsSdkDir, tool, "include")
if os.isdir(tool_dir) then
table.insert(includedirs, tool_dir)
end
end
end

if VCToolsInstallDir then
table.insert(includedirs, path.join(VCToolsInstallDir, "include"))
end
local VCToolsInstallDir = envs.VCToolsInstallDir
if VCToolsInstallDir then
table.insert(includedirs, path.join(VCToolsInstallDir, "include"))
end

for _, dir in ipairs(includedirs) do
table.insert(args, "-imsvc")
table.insert(args, dir)
end
for _, dir in ipairs(includedirs) do
table.insert(args, "-imsvc")
table.insert(args, dir)
end
end
return args
Expand Down
39 changes: 36 additions & 3 deletions xmake/toolchains/msvc/check.lua
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,39 @@ function _check_vstudio(toolchain)
return vs
end

function _check_vc_build_tools(toolchain, sdkdir)
local opt = {}
opt.sdkdir = sdkdir
opt.vs_toolset = toolchain:config("vs_toolset") or config.get("vs_toolset")
opt.vs_sdkver = toolchain:config("vs_sdkver") or config.get("vs_sdkver")

local vcvarsall = find_vstudio.find_build_tools(opt)
if not vcvarsall then
return
end

local vcvars = vcvarsall[toolchain:arch()]
if vcvars and vcvars.PATH and vcvars.INCLUDE and vcvars.LIB then
-- save vcvars
toolchain:config_set("vcvars", vcvars)
toolchain:config_set("vcarchs", table.orderkeys(vcvarsall))
toolchain:config_set("vs_toolset", vcvars.VCToolsVersion)
toolchain:config_set("vs_sdkver", vcvars.WindowsSDKVersion)

-- check compiler
local cl = find_tool("cl.exe", {version = true, force = true, envs = vcvars})
if cl and cl.version then
cprint("checking for Microsoft C/C++ Compiler (%s) version ... ${color.success}%s", toolchain:arch(), cl.version)
end
return vcvars
end
end

-- main entry
function main(toolchain)

-- only for windows
if not is_host("windows") then
-- only for windows or linux (msvc-wine)
if not is_host("windows", "linux") then
return
end

Expand All @@ -113,7 +141,12 @@ function main(toolchain)
local cxx = path.basename(config.get("cxx") or "cl"):lower()
local mrc = path.basename(config.get("mrc") or "rc"):lower()
if cc == "cl" or cxx == "cl" or mrc == "rc" then
return _check_vstudio(toolchain)
local sdkdir = option.get("sdk") or toolchain:config("sdk") or config.get("sdk")
star-hengxing marked this conversation as resolved.
Show resolved Hide resolved
if sdkdir then
return _check_vc_build_tools(toolchain, sdkdir)
else
return _check_vstudio(toolchain)
end
end
end

Loading