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
109 changes: 109 additions & 0 deletions xmake/modules/detect/sdks/find_vstudio.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import("core.project.config")
import("lib.detect.find_file")
import("lib.detect.find_tool")
import("lib.detect.find_directory")
import("core.cache.global_detectcache")

-- init vc variables
Expand Down Expand Up @@ -97,6 +98,114 @@ 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 vs_toolset = opt.vs_toolset
if vs_toolset and os.isdir(path.join(sdkdir, "VC/Tools/MSVC", vs_toolset)) then
VCToolsVersion = vs_toolset
else
local dir = find_directory("14*", path.join(sdkdir, "VC/Tools/MSVC"))
if dir then
VCToolsVersion = path.filename(dir)
else
return
end
end
variables.VCToolsVersion = VCToolsVersion
variables.VCToolsInstallDir = path.join(sdkdir, "VC/Tools/MSVC", VCToolsVersion)

local WindowsSDKVersion
local vs_sdkver = opt.vs_sdkver
if vs_sdkver and os.isdir(path.join(sdkdir, "Windows Kits/10/Lib", vs_sdkver)) then
WindowsSDKVersion = vs_sdkver
else
local dir = find_directory("10*", path.join(sdkdir, "Windows Kits/10/Lib"))
if dir then
WindowsSDKVersion = path.filename(dir)
else
return
end
end
variables.WindowsSDKVersion = WindowsSDKVersion
variables.WindowsSDKDir = path.join(sdkdir, "Windows Kits/10")

local includedirs = {
path.join(variables.VCToolsInstallDir, "include"),
path.join(variables.VCToolsInstallDir, "atlmfc/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

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
55 changes: 46 additions & 9 deletions xmake/toolchains/clang-cl/check.lua
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ import("core.project.config")
import("detect.sdks.find_vstudio")
import("lib.detect.find_tool")

function _find_clang_cl(vcvars)
local paths
local pathenv = os.getenv("PATH")
if pathenv then
paths = path.splitenv(pathenv)
end
return find_tool("clang-cl.exe", {version = true, force = true, paths = paths, envs = vcvars})
end

-- attempt to check vs environment
function _check_vsenv(toolchain)

Expand Down Expand Up @@ -69,12 +78,7 @@ function _check_vsenv(toolchain)

-- check compiler
local program
local paths
local pathenv = os.getenv("PATH")
if pathenv then
paths = path.splitenv(pathenv)
end
local tool = find_tool("clang-cl.exe", {version = true, force = true, paths = paths, envs = vcvars})
local tool = _find_clang_cl(vcvars)
if tool then
program = tool.program
end
Expand Down Expand Up @@ -105,11 +109,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 clang_cl = _find_clang_cl(vcvars)
if clang_cl and clang_cl.version then
cprint("checking for LLVM Clang C/C++ Compiler (%s) version ... ${color.success}%s", toolchain:arch(), clang_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 @@ -118,7 +150,12 @@ function main(toolchain)
local cxx = path.basename(config.get("cxx") or "clang-cl"):lower()
local mrc = path.basename(config.get("mrc") or "rc"):lower()
if cc == "clang-cl" or cxx == "clang-cl" or mrc == "rc" then
return _check_vstudio(toolchain)
local sdkdir = toolchain:sdkdir()
if sdkdir then
return _check_vc_build_tools(toolchain, sdkdir)
else
return _check_vstudio(toolchain)
end
end
end

69 changes: 69 additions & 0 deletions xmake/toolchains/clang/check.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
--!A cross-platform build utility based on Lua
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-- Copyright (C) 2015-present, TBOOX Open Source Group.
--
-- @author ruki
-- @file xmake.lua
--

import("detect.sdks.find_vstudio")
import("lib.detect.find_tool")
import("core.project.config")

function _check_vc_build_tools(toolchain, sdkdir, suffix)
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 paths
local pathenv = os.getenv("PATH")
if pathenv then
paths = path.splitenv(pathenv)
end
local clang = find_tool("clang" .. suffix, {version = true, force = true, paths = paths, envs = vcvars})
if clang and clang.version then
cprint("checking for LLVM Clang C/C++ Compiler (%s) version ... ${color.success}%s", toolchain:arch(), clang.version)
end
return vcvars
end
end

function main(toolchain, suffix)

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

local sdkdir = toolchain:sdkdir()
if sdkdir then
return _check_vc_build_tools(toolchain, sdkdir, suffix)
end
end
Loading
Loading