diff options
| author | ruki <[email protected]> | 2024-11-20 10:35:27 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-11-20 10:35:27 +0800 |
| commit | 6f2dc65a267c11c9dbe016e536fd8c756042884a (patch) | |
| tree | c780783f6f485e736f39ed078fce08c4e1c52457 | |
| parent | 959106bc784e0a8c218c331970afc25bed52e9c6 (diff) | |
| parent | 22e37a1f4e93e58c08d2cffa5e79a6dc1e6588b0 (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.lua | 109 | ||||
| -rw-r--r-- | xmake/modules/package/tools/cmake.lua | 8 | ||||
| -rw-r--r-- | xmake/plugins/project/clang/compile_commands.lua | 19 | ||||
| -rw-r--r-- | xmake/toolchains/clang-cl/check.lua | 55 | ||||
| -rw-r--r-- | xmake/toolchains/clang/check.lua | 69 | ||||
| -rw-r--r-- | xmake/toolchains/clang/load.lua | 96 | ||||
| -rw-r--r-- | xmake/toolchains/clang/xmake.lua | 12 | ||||
| -rw-r--r-- | xmake/toolchains/msvc/check.lua | 39 |
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 |
