summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2024-11-20 10:35:27 +0800
committerGitHub <[email protected]>2024-11-20 10:35:27 +0800
commit6f2dc65a267c11c9dbe016e536fd8c756042884a (patch)
treec780783f6f485e736f39ed078fce08c4e1c52457
parent959106bc784e0a8c218c331970afc25bed52e9c6 (diff)
parent22e37a1f4e93e58c08d2cffa5e79a6dc1e6588b0 (diff)
Merge pull request #5823 from star-hengxing/msvc-build-tools
Support custom vc build tools
-rw-r--r--xmake/modules/detect/sdks/find_vstudio.lua109
-rw-r--r--xmake/modules/package/tools/cmake.lua8
-rw-r--r--xmake/plugins/project/clang/compile_commands.lua19
-rw-r--r--xmake/toolchains/clang-cl/check.lua55
-rw-r--r--xmake/toolchains/clang/check.lua69
-rw-r--r--xmake/toolchains/clang/load.lua96
-rw-r--r--xmake/toolchains/clang/xmake.lua12
-rw-r--r--xmake/toolchains/msvc/check.lua39
8 files changed, 385 insertions, 22 deletions
diff --git a/xmake/modules/detect/sdks/find_vstudio.lua b/xmake/modules/detect/sdks/find_vstudio.lua
index 41c019439..9bd120606 100644
--- a/xmake/modules/detect/sdks/find_vstudio.lua
+++ b/xmake/modules/detect/sdks/find_vstudio.lua
@@ -23,6 +23,7 @@ import("core.base.option")
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
@@ -98,6 +99,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 {}
diff --git a/xmake/modules/package/tools/cmake.lua b/xmake/modules/package/tools/cmake.lua
index 7db5b3441..2618246b6 100644
--- a/xmake/modules/package/tools/cmake.lua
+++ b/xmake/modules/package/tools/cmake.lua
@@ -474,7 +474,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
end
-- get configs for android
@@ -663,6 +667,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
diff --git a/xmake/plugins/project/clang/compile_commands.lua b/xmake/plugins/project/clang/compile_commands.lua
index fa32ea7ca..9996b4ed5 100644
--- a/xmake/plugins/project/clang/compile_commands.lua
+++ b/xmake/plugins/project/clang/compile_commands.lua
@@ -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
diff --git a/xmake/toolchains/clang-cl/check.lua b/xmake/toolchains/clang-cl/check.lua
index 515c3d639..b416a44ce 100644
--- a/xmake/toolchains/clang-cl/check.lua
+++ b/xmake/toolchains/clang-cl/check.lua
@@ -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)
@@ -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
@@ -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
@@ -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
diff --git a/xmake/toolchains/clang/check.lua b/xmake/toolchains/clang/check.lua
new file mode 100644
index 000000000..7c23a4f1c
--- /dev/null
+++ b/xmake/toolchains/clang/check.lua
@@ -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
diff --git a/xmake/toolchains/clang/load.lua b/xmake/toolchains/clang/load.lua
new file mode 100644
index 000000000..f8bf4eb4f
--- /dev/null
+++ b/xmake/toolchains/clang/load.lua
@@ -0,0 +1,96 @@
+--!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("detect.sdks.find_mingw")
+import("core.project.config")
+
+-- add the given vs environment
+function _add_vsenv(toolchain, name, curenvs)
+
+ -- get vcvars
+ local vcvars = toolchain:config("vcvars")
+ if not vcvars then
+ return
+ end
+
+ -- get the paths for the vs environment
+ local new = vcvars[name]
+ if new then
+ -- fix case naming conflict for cmake/msbuild between the new msvc envs and current environment, if we are running xmake in vs prompt.
+ -- @see https://github.com/xmake-io/xmake/issues/4751
+ for k, c in pairs(curenvs) do
+ if name:lower() == k:lower() and name ~= k then
+ name = k
+ break
+ end
+ end
+ if name == "INCLUDE" or name == "LIB" then
+ toolchain:add("runenvs", name, table.concat(path.splitenv(new), ";"))
+ else
+ toolchain:add("runenvs", name, table.unwrap(path.splitenv(new)))
+ end
+ end
+end
+
+function main(toolchain, suffix)
+ local target
+ if toolchain:is_arch("x86_64", "x64") then
+ target = "x86_64"
+ march = "-m64"
+ elseif toolchain:is_arch("i386", "x86") then
+ target = "i386"
+ march = "-m32"
+ elseif toolchain:is_arch("arm64") then
+ target = "arm64"
+ elseif toolchain:is_arch("arm") then
+ target = "arm"
+ end
+
+ if toolchain:is_plat("windows") then
+ target = target .. "-windows-msvc"
+
+ -- add vs environments
+ local expect_vars = {"PATH", "LIB", "INCLUDE", "LIBPATH"}
+ local curenvs = os.getenvs()
+ for _, name in ipairs(expect_vars) do
+ _add_vsenv(toolchain, name, curenvs)
+ end
+ for _, name in ipairs(find_vstudio.get_vcvars()) do
+ if not table.contains(expect_vars, name:upper()) then
+ _add_vsenv(toolchain, name, curenvs)
+ end
+ end
+
+ if is_host("linux") then
+ toolchain:add("ldflags", "-fuse-ld=lld-link" .. suffix)
+ toolchain:add("shflags", "-fuse-ld=lld-link" .. suffix)
+ end
+ elseif toolchain:is_plat("mingw") then
+ target = target .. "-windows-gnu"
+ end
+
+ if target then
+ toolchain:add("cxflags", "--target=" .. target)
+ toolchain:add("asflags", "--target=" .. target)
+ toolchain:add("ldflags", "--target=" .. target)
+ toolchain:add("shflags", "--target=" .. target)
+ end
+end
diff --git a/xmake/toolchains/clang/xmake.lua b/xmake/toolchains/clang/xmake.lua
index cc8da1d26..ea9406e5c 100644
--- a/xmake/toolchains/clang/xmake.lua
+++ b/xmake/toolchains/clang/xmake.lua
@@ -44,6 +44,14 @@ toolchain("clang" .. suffix)
set_toolset("mrc", "llvm-rc")
on_check(function (toolchain)
+ if toolchain:is_plat("windows") then
+ local rootdir = path.join(path.directory(os.scriptdir()), "clang")
+ local result = import("check", {rootdir = rootdir})(toolchain, suffix)
+ if result then
+ return result
+ end
+ end
+
return import("lib.detect.find_tool")("clang" .. suffix)
end)
@@ -64,6 +72,10 @@ toolchain("clang" .. suffix)
if toolchain:is_plat("windows") then
toolchain:add("runtimes", "MT", "MTd", "MD", "MDd")
end
+ if toolchain:is_plat("windows", "mingw") then
+ local rootdir = path.join(path.directory(os.scriptdir()), "clang")
+ import("load", {rootdir = rootdir})(toolchain, suffix)
+ end
end)
end
toolchain_clang()
diff --git a/xmake/toolchains/msvc/check.lua b/xmake/toolchains/msvc/check.lua
index 6d5772733..3c70d43c0 100644
--- a/xmake/toolchains/msvc/check.lua
+++ b/xmake/toolchains/msvc/check.lua
@@ -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
@@ -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 = toolchain:sdkdir()
+ if sdkdir then
+ return _check_vc_build_tools(toolchain, sdkdir)
+ else
+ return _check_vstudio(toolchain)
+ end
end
end