diff --git a/xmake/modules/detect/sdks/find_vstudio.lua b/xmake/modules/detect/sdks/find_vstudio.lua index b58e9cb911..1c4e905c8b 100644 --- a/xmake/modules/detect/sdks/find_vstudio.lua +++ b/xmake/modules/detect/sdks/find_vstudio.lua @@ -97,6 +97,123 @@ 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 + break + end + end + + if not VCToolsVersion and #VCToolsVersionDirs ~= 0 then + VCToolsVersion = path.filename(VCToolsVersionDirs[1]) + 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/*")) + 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 host_dir = "Host" .. vcvars.VSCMD_ARG_HOST_ARCH + local buidl_tools_bin = { + path.join(vcvars.VCToolsInstallDir, "bin", host_dir, target_arch), + path.join(vcvars.WindowsSDKDir, "bin", WindowsSDKVersion), + path.join(vcvars.WindowsSDKDir, "bin", WindowsSDKVersion, "ucrt"), + } + + 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 {} diff --git a/xmake/plugins/project/clang/compile_commands.lua b/xmake/plugins/project/clang/compile_commands.lua index fa32ea7ca3..9996b4ed57 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/msvc/check.lua b/xmake/toolchains/msvc/check.lua index 6d57727333..37eb452554 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 = option.get("sdk") or toolchain:config("sdk") or config.get("sdk") + if sdkdir then + return _check_vc_build_tools(toolchain, sdkdir) + else + return _check_vstudio(toolchain) + end end end