diff options
| author | shuax <[email protected]> | 2022-03-30 21:34:17 +0800 |
|---|---|---|
| committer | shuax <[email protected]> | 2022-03-30 21:34:17 +0800 |
| commit | 90e51e78a59569d939332837bd4189f830a7af93 (patch) | |
| tree | c53afffee6e15f8e2fff4792fa811b91dba38639 | |
| parent | 0dab3adc402d63422384b7c3618118848f6bec2b (diff) | |
Improve group name uuid
| -rw-r--r-- | xmake/plugins/project/vstudio/impl/vs201x_solution.lua | 344 | ||||
| -rw-r--r-- | xmake/plugins/project/vsxmake/getinfo.lua | 1048 |
2 files changed, 696 insertions, 696 deletions
diff --git a/xmake/plugins/project/vstudio/impl/vs201x_solution.lua b/xmake/plugins/project/vstudio/impl/vs201x_solution.lua index 7d285c154..6e4b81dc8 100644 --- a/xmake/plugins/project/vstudio/impl/vs201x_solution.lua +++ b/xmake/plugins/project/vstudio/impl/vs201x_solution.lua @@ -1,172 +1,172 @@ ---!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 vs201x_solution.lua --- - --- imports -import("core.project.project") -import("vsfile") - --- get vs arch -function _vs_arch(arch) - if arch == 'x86' or arch == 'i386' then return "Win32" end - if arch == 'x86_64' then return "x64" end - if arch:startswith('arm64') then return "ARM64" end - if arch:startswith('arm') then return "ARM" end - return arch -end - --- make header -function _make_header(slnfile, vsinfo) - slnfile:print("Microsoft Visual Studio Solution File, Format Version %s.00", vsinfo.solution_version) - slnfile:print("# Visual Studio %s", vsinfo.vstudio_version) -end - --- make projects -function _make_projects(slnfile, vsinfo) - - -- make all targets - local groups = {} - local targets = {} - local vctool = "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942" - for targetname, target in pairs(project.targets()) do - -- we need set startup project for default or binary target - -- @see https://github.com/xmake-io/xmake/issues/1249 - if target:get("default") == true then - table.insert(targets, 1, target) - elseif target:is_binary() then - local first_target = targets[1] - if not first_target or first_target:is_default() then - table.insert(targets, 1, target) - else - table.insert(targets, target) - end - else - table.insert(targets, target) - end - end - for _, target in ipairs(targets) do - local targetname = target:name() - slnfile:enter("Project(\"{%s}\") = \"%s\", \"%s\\%s.vcxproj\", \"{%s}\"", vctool, targetname, targetname, targetname, hash.uuid4(targetname)) - for _, dep in ipairs(target:get("deps")) do - slnfile:enter("ProjectSection(ProjectDependencies) = postProject") - slnfile:print("{%s} = {%s}", hash.uuid4(dep), hash.uuid4(dep)) - slnfile:leave("EndProjectSection") - end - slnfile:leave("EndProject") - local group_path = target:get("group") - if group_path then - for _, group_name in ipairs(path.split(group_path)) do - groups[group_name] = hash.uuid4(group_name) - end - end - end - - -- make all groups - local project_group_uuid = "2150E333-8FDC-42A3-9474-1A3956D46DE8" - for group_name, group_uuid in pairs(groups) do - slnfile:enter("Project(\"{%s}\") = \"%s\", \"%s\", \"{%s}\"", project_group_uuid, group_name, group_name, group_uuid) - slnfile:leave("EndProject") - end -end - --- make global -function _make_global(slnfile, vsinfo) - - -- enter global - slnfile:enter("Global") - - -- add solution configuration platforms - slnfile:enter("GlobalSection(SolutionConfigurationPlatforms) = preSolution") - for _, mode in ipairs(vsinfo.modes) do - for _, arch in ipairs(vsinfo.archs) do - slnfile:print("%s|%s = %s|%s", mode, arch, mode, arch) - end - end - slnfile:leave("EndGlobalSection") - - -- add project configuration platforms - slnfile:enter("GlobalSection(ProjectConfigurationPlatforms) = postSolution") - for targetname, target in pairs(project.targets()) do - for _, mode in ipairs(vsinfo.modes) do - for _, arch in ipairs(vsinfo.archs) do - local vs_arch = _vs_arch(arch) - slnfile:print("{%s}.%s|%s.ActiveCfg = %s|%s", hash.uuid4(targetname), mode, arch, mode, vs_arch) - slnfile:print("{%s}.%s|%s.Build.0 = %s|%s", hash.uuid4(targetname), mode, arch, mode, vs_arch) - end - end - end - slnfile:leave("EndGlobalSection") - - -- add solution properties - slnfile:enter("GlobalSection(SolutionProperties) = preSolution") - slnfile:print("HideSolutionNode = FALSE") - slnfile:leave("EndGlobalSection") - - -- add project groups - slnfile:enter("GlobalSection(NestedProjects) = preSolution") - local subgroups = {} - for targetname, target in pairs(project.targets()) do - local group_path = target:get("group") - if group_path then - -- target -> group - local group_name = path.filename(group_path) - slnfile:print("{%s} = {%s}", hash.uuid4(targetname), hash.uuid4(group_name)) - -- group -> group -> ... - local group_names = path.split(group_path) - for idx, group_name in ipairs(group_names) do - local key = group_name .. (group_name_sub or "") - local group_name_sub = group_names[idx + 1] - if group_name_sub and not subgroups[key] then - slnfile:print("{%s} = {%s}", hash.uuid4(group_name_sub), hash.uuid4(group_name)) - subgroups[key] = true - end - end - end - end - slnfile:leave("EndGlobalSection") - - -- leave global - slnfile:leave("EndGlobal") -end - --- make solution -function make(vsinfo) - - -- init solution name - vsinfo.solution_name = project.name() or ("vs" .. vsinfo.vstudio_version) - - -- open solution file - local slnpath = path.join(vsinfo.solution_dir, vsinfo.solution_name .. ".sln") - local slnfile = vsfile.open(slnpath, "w") - - -- init indent character - vsfile.indentchar('\t') - - -- make header - _make_header(slnfile, vsinfo) - - -- make projects - _make_projects(slnfile, vsinfo) - - -- make global - _make_global(slnfile, vsinfo) - - -- exit solution file - slnfile:close() -end +--!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 vs201x_solution.lua
+--
+
+-- imports
+import("core.project.project")
+import("vsfile")
+
+-- get vs arch
+function _vs_arch(arch)
+ if arch == 'x86' or arch == 'i386' then return "Win32" end
+ if arch == 'x86_64' then return "x64" end
+ if arch:startswith('arm64') then return "ARM64" end
+ if arch:startswith('arm') then return "ARM" end
+ return arch
+end
+
+-- make header
+function _make_header(slnfile, vsinfo)
+ slnfile:print("Microsoft Visual Studio Solution File, Format Version %s.00", vsinfo.solution_version)
+ slnfile:print("# Visual Studio %s", vsinfo.vstudio_version)
+end
+
+-- make projects
+function _make_projects(slnfile, vsinfo)
+
+ -- make all targets
+ local groups = {}
+ local targets = {}
+ local vctool = "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942"
+ for targetname, target in pairs(project.targets()) do
+ -- we need set startup project for default or binary target
+ -- @see https://github.com/xmake-io/xmake/issues/1249
+ if target:get("default") == true then
+ table.insert(targets, 1, target)
+ elseif target:is_binary() then
+ local first_target = targets[1]
+ if not first_target or first_target:is_default() then
+ table.insert(targets, 1, target)
+ else
+ table.insert(targets, target)
+ end
+ else
+ table.insert(targets, target)
+ end
+ end
+ for _, target in ipairs(targets) do
+ local targetname = target:name()
+ slnfile:enter("Project(\"{%s}\") = \"%s\", \"%s\\%s.vcxproj\", \"{%s}\"", vctool, targetname, targetname, targetname, hash.uuid4(targetname))
+ for _, dep in ipairs(target:get("deps")) do
+ slnfile:enter("ProjectSection(ProjectDependencies) = postProject")
+ slnfile:print("{%s} = {%s}", hash.uuid4(dep), hash.uuid4(dep))
+ slnfile:leave("EndProjectSection")
+ end
+ slnfile:leave("EndProject")
+ local group_path = target:get("group")
+ if group_path then
+ for _, group_name in ipairs(path.split(group_path)) do
+ groups[group_name] = hash.uuid4("group." .. group_name)
+ end
+ end
+ end
+
+ -- make all groups
+ local project_group_uuid = "2150E333-8FDC-42A3-9474-1A3956D46DE8"
+ for group_name, group_uuid in pairs(groups) do
+ slnfile:enter("Project(\"{%s}\") = \"%s\", \"%s\", \"{%s}\"", project_group_uuid, group_name, group_name, group_uuid)
+ slnfile:leave("EndProject")
+ end
+end
+
+-- make global
+function _make_global(slnfile, vsinfo)
+
+ -- enter global
+ slnfile:enter("Global")
+
+ -- add solution configuration platforms
+ slnfile:enter("GlobalSection(SolutionConfigurationPlatforms) = preSolution")
+ for _, mode in ipairs(vsinfo.modes) do
+ for _, arch in ipairs(vsinfo.archs) do
+ slnfile:print("%s|%s = %s|%s", mode, arch, mode, arch)
+ end
+ end
+ slnfile:leave("EndGlobalSection")
+
+ -- add project configuration platforms
+ slnfile:enter("GlobalSection(ProjectConfigurationPlatforms) = postSolution")
+ for targetname, target in pairs(project.targets()) do
+ for _, mode in ipairs(vsinfo.modes) do
+ for _, arch in ipairs(vsinfo.archs) do
+ local vs_arch = _vs_arch(arch)
+ slnfile:print("{%s}.%s|%s.ActiveCfg = %s|%s", hash.uuid4(targetname), mode, arch, mode, vs_arch)
+ slnfile:print("{%s}.%s|%s.Build.0 = %s|%s", hash.uuid4(targetname), mode, arch, mode, vs_arch)
+ end
+ end
+ end
+ slnfile:leave("EndGlobalSection")
+
+ -- add solution properties
+ slnfile:enter("GlobalSection(SolutionProperties) = preSolution")
+ slnfile:print("HideSolutionNode = FALSE")
+ slnfile:leave("EndGlobalSection")
+
+ -- add project groups
+ slnfile:enter("GlobalSection(NestedProjects) = preSolution")
+ local subgroups = {}
+ for targetname, target in pairs(project.targets()) do
+ local group_path = target:get("group")
+ if group_path then
+ -- target -> group
+ local group_name = path.filename(group_path)
+ slnfile:print("{%s} = {%s}", hash.uuid4(targetname), hash.uuid4("group." .. group_name))
+ -- group -> group -> ...
+ local group_names = path.split(group_path)
+ for idx, group_name in ipairs(group_names) do
+ local key = group_name .. (group_name_sub or "")
+ local group_name_sub = group_names[idx + 1]
+ if group_name_sub and not subgroups[key] then
+ slnfile:print("{%s} = {%s}", hash.uuid4(group_name_sub), hash.uuid4("group." .. group_name))
+ subgroups[key] = true
+ end
+ end
+ end
+ end
+ slnfile:leave("EndGlobalSection")
+
+ -- leave global
+ slnfile:leave("EndGlobal")
+end
+
+-- make solution
+function make(vsinfo)
+
+ -- init solution name
+ vsinfo.solution_name = project.name() or ("vs" .. vsinfo.vstudio_version)
+
+ -- open solution file
+ local slnpath = path.join(vsinfo.solution_dir, vsinfo.solution_name .. ".sln")
+ local slnfile = vsfile.open(slnpath, "w")
+
+ -- init indent character
+ vsfile.indentchar('\t')
+
+ -- make header
+ _make_header(slnfile, vsinfo)
+
+ -- make projects
+ _make_projects(slnfile, vsinfo)
+
+ -- make global
+ _make_global(slnfile, vsinfo)
+
+ -- exit solution file
+ slnfile:close()
+end
diff --git a/xmake/plugins/project/vsxmake/getinfo.lua b/xmake/plugins/project/vsxmake/getinfo.lua index a9a5c1f9c..aa886e715 100644 --- a/xmake/plugins/project/vsxmake/getinfo.lua +++ b/xmake/plugins/project/vsxmake/getinfo.lua @@ -1,524 +1,524 @@ ---!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 OpportunityLiu --- @file getinfo.lua --- - --- imports -import("core.base.option") -import("core.base.semver") -import("core.base.hashset") -import("core.project.config") -import("core.project.project") -import("core.platform.platform") -import("core.tool.compiler") -import("core.tool.linker") -import("core.cache.memcache") -import("core.cache.localcache") -import("lib.detect.find_tool") -import("private.action.run.make_runenvs") -import("private.action.require.install", {alias = "install_requires"}) -import("actions.config.configheader", {alias = "generate_configheader", rootdir = os.programdir()}) -import("actions.config.configfiles", {alias = "generate_configfiles", rootdir = os.programdir()}) - --- escape special chars in msbuild file -function _escape(str) - if not str then - return nil - end - - local map = - { - ["%"] = "%25" -- Referencing metadata - , ["$"] = "%24" -- Referencing properties - , ["@"] = "%40" -- Referencing item lists - , ["'"] = "%27" -- Conditions and other expressions - , [";"] = "%3B" -- List separator - , ["?"] = "%3F" -- Wildcard character for file names in Include and Exclude attributes - , ["*"] = "%2A" -- Wildcard character for use in file names in Include and Exclude attributes - -- html entities - , ["\""] = """ - , ["<"] = "<" - , [">"] = ">" - , ["&"] = "&" - } - - return (string.gsub(str, "[%%%$@';%?%*\"<>&]", function (c) return assert(map[c]) end)) -end - -function _vs_arch(arch) - if arch == 'x86' or arch == 'i386' then return "Win32" end - if arch == 'x86_64' then return "x64" end - if arch:startswith('arm64') then return "ARM64" end - if arch:startswith('arm') then return "ARM" end - return arch -end - --- strip dot directories, e.g. ..\..\.. => .. --- @see https://github.com/xmake-io/xmake/issues/2039 -function _strip_dotdirs(dir) - local count - dir, count = dir:gsub("%.%.[\\/]%.%.", "..") - if count > 0 then - dir = _strip_dotdirs(dir) - end - return dir -end - -function _make_dirs(dir) - if dir == nil then - return "" - end - if type(dir) == "string" then - dir = path.translate(dir) - if dir == "" then - return "" - end - if path.is_absolute(dir) then - if dir:startswith(project.directory()) then - return path.join("$(XmakeProjectDir)", _escape(path.relative(dir, project.directory()))) - end - return _escape(dir) - end - return path.join("$(XmakeProjectDir)", _escape(dir)) - end - local r = {} - for k, v in ipairs(dir) do - r[k] = _make_dirs(v) - end - r = table.unique(r) - return path.joinenv(r) -end - -function _make_arrs(arr) - if arr == nil then - return "" - end - if type(arr) == "string" then - return _escape(arr) - end - local r = {} - for k, v in ipairs(arr) do - r[k] = _make_arrs(v) - end - r = table.unique(r) - return table.concat(r, ";") -end - --- get values from target -function _get_values_from_target(target, name) - local values = table.wrap(target:get(name)) - table.join2(values, target:get_from_opts(name)) - table.join2(values, target:get_from_pkgs(name)) - table.join2(values, target:get_from_deps(name, {interface = true})) - return table.unique(values) -end - --- make target info -function _make_targetinfo(mode, arch, target) - - -- init target info - local targetinfo = - { - mode = mode - , arch = arch - , plat = config.get("plat") - , vsarch = _vs_arch(arch) - , sdkver = config.get("vs_sdkver") - } - - -- write only if not default - -- use target:get("xxx") rather than target:xxx() - - -- save target kind - targetinfo.kind = target:kind() - - -- is default? - targetinfo.default = tostring(target:is_default()) - - -- save target file - targetinfo.basename = _escape(target:get("basename")) - targetinfo.filename = _escape(target:get("filename")) - - -- save dirs - targetinfo.targetdir = _make_dirs(target:get("targetdir")) - targetinfo.buildir = _make_dirs(config.get("buildir")) - targetinfo.rundir = _make_dirs(target:get("rundir")) - targetinfo.configdir = _make_dirs(os.getenv("XMAKE_CONFIGDIR")) - targetinfo.configfiledir = _make_dirs(target:get("configdir")) - targetinfo.includedirs = _make_dirs(table.join(_get_values_from_target(target, "includedirs") or {}, _get_values_from_target(target, "sysincludedirs"))) - targetinfo.linkdirs = _make_dirs(_get_values_from_target(target, "linkdirs")) - targetinfo.sourcedirs = _make_dirs(_get_values_from_target(target, "values.project.vsxmake.sourcedirs")) - targetinfo.pcheaderfile = target:pcheaderfile("cxx") or target:pcheaderfile("c") - - -- save defines - targetinfo.defines = _make_arrs(_get_values_from_target(target, "defines")) - - -- save languages - targetinfo.languages = _make_arrs(_get_values_from_target(target, "languages")) - if targetinfo.languages then - -- fix c++17 to cxx17 for Xmake.props - targetinfo.languages = targetinfo.languages:replace("c++", "cxx", {plain = true}) - end - if target:is_phony() or target:is_headeronly() then - return targetinfo - end - - -- save subsystem - local linkflags = linker.linkflags(target:kind(), target:sourcekinds(), {target = target}) - for _, linkflag in ipairs(linkflags) do - if linkflag:lower():find("[%-/]subsystem:windows") then - targetinfo.subsystem = "windows" - end - end - if not targetinfo.subsystem then - targetinfo.subsystem = "console" - end - - -- save runenvs - local runenvs = {} - local addrunenvs, setrunenvs = make_runenvs(target) - for k, v in pairs(target:pkgenvs()) do - addrunenvs = addrunenvs or {} - addrunenvs[k] = table.join(table.wrap(addrunenvs[k]), path.splitenv(v)) - end - for _, dep in ipairs(target:orderdeps()) do - for k, v in pairs(dep:pkgenvs()) do - addrunenvs = addrunenvs or {} - addrunenvs[k] = table.join(table.wrap(addrunenvs[k]), path.splitenv(v)) - end - end - for k, v in pairs(addrunenvs) do - if k:upper() == "PATH" then - runenvs[k] = _make_dirs(v) .. ";$([System.Environment]::GetEnvironmentVariable('" .. k .. "'))" - else - runenvs[k] = path.joinenv(v) .. ";$([System.Environment]::GetEnvironmentVariable('" .. k .."'))" - end - end - for k, v in pairs(setrunenvs) do - if #v == 1 then - v = v[1] - if path.is_absolute(v) and v:startswith(project.directory()) then - runenvs[k] = _make_dirs(v) - else - runenvs[k] = v[1] - end - else - runenvs[k] = path.joinenv(v) - end - end - local runenvstr = {} - for k, v in pairs(runenvs) do - table.insert(runenvstr, k .. "=" .. v) - end - targetinfo.runenvs = table.concat(runenvstr, "\n") - - -- use mfc? save the mfc runtime kind - if target:rule("win.sdk.mfc.shared_app") or target:rule("win.sdk.mfc.shared") then - targetinfo.mfckind = "Dynamic" - elseif target:rule("win.sdk.mfc.static_app") or target:rule("win.sdk.mfc.static") then - targetinfo.mfckind = "Static" - end - - -- use cuda? save the cuda runtime version - if target:rule("cuda") then - local nvcc = find_tool("nvcc", { version = true }) - local ver = semver.new(nvcc.version) - targetinfo.cudaver = ver:major() .. "." .. ver:minor() - end - return targetinfo -end - -function _make_vsinfo_modes() - local vsinfo_modes = {} - local modes = option.get("modes") - if modes then - if not modes:find("\"") then - modes = modes:gsub(",", path.envsep()) - end - for _, mode in ipairs(path.splitenv(modes)) do - table.insert(vsinfo_modes, mode:trim()) - end - else - vsinfo_modes = project.modes() - end - if not vsinfo_modes or #vsinfo_modes == 0 then - vsinfo_modes = { config.mode() } - end - return vsinfo_modes -end - -function _make_vsinfo_archs() - local vsinfo_archs = {} - local archs = option.get("archs") - if archs then - if not archs:find("\"") then - archs = archs:gsub(",", path.envsep()) - end - for _, arch in ipairs(path.splitenv(archs)) do - table.insert(vsinfo_archs, arch:trim()) - end - else - -- we use it first if global set_arch("xx") is setted in xmake.lua - vsinfo_archs = project.get("target.arch") - if not vsinfo_archs then - -- for set_allowedarchs() - local allowed_archs = project.allowed_archs(config.plat()) - if allowed_archs then - vsinfo_archs = allowed_archs:to_array() - end - end - if not vsinfo_archs then - vsinfo_archs = platform.archs() - end - end - if not vsinfo_archs or #vsinfo_archs == 0 then - vsinfo_archs = { config.arch() } - end - return vsinfo_archs -end - -function _make_vsinfo_groups() - local groups = {} - local group_deps = {} - for targetname, target in pairs(project.targets()) do - if not target:is_phony() then - local group_path = target:get("group") - if group_path then - local group_name = path.filename(group_path) - local group_names = path.split(group_path) - for idx, name in ipairs(group_names) do - local group = groups["group." .. name] or {} - group.group = name - group.group_id = hash.uuid4(name) - if idx > 1 then - group_deps["group_dep." .. name] = {current_id = group.group_id, parent_id = hash.uuid4(group_names[idx - 1])} - end - groups["group." .. name] = group - end - group_deps["group_dep.target." .. targetname] = {current_id = hash.uuid4(targetname), parent_id = groups["group." .. group_name].group_id} - end - end - end - return groups, group_deps -end - --- config target -function _config_target(target) - for _, rule in ipairs(target:orderules()) do - local on_config = rule:script("config") - if on_config then - on_config(target) - end - end - local on_config = target:script("config") - if on_config then - on_config(target) - end -end - --- config targets -function _config_targets() - for _, target in ipairs(project.ordertargets()) do - if target:is_enabled() then - _config_target(target) - end - end -end - --- make vstudio project -function main(outputdir, vsinfo) - - -- enter project directory - local oldir = os.cd(project.directory()) - - -- init solution directory - vsinfo.solution_dir = path.absolute(path.join(outputdir, "vsxmake" .. vsinfo.vstudio_version)) - vsinfo.programdir = _make_dirs(xmake.programdir()) - vsinfo.projectdir = project.directory() - vsinfo.sln_projectfile = path.relative(project.rootfile(), vsinfo.solution_dir) - local projectfile = path.filename(project.rootfile()) - vsinfo.slnfile = project.name() or path.filename(project.directory()) - -- write only if not default - if projectfile ~= "xmake.lua" then - vsinfo.projectfile = projectfile - end - - vsinfo.xmake_info = format("xmake version %s", xmake.version()) - vsinfo.solution_id = hash.uuid4(project.directory() .. vsinfo.solution_dir) - vsinfo.vs_version = vsinfo.project_version .. ".0" - - -- init modes - vsinfo.modes = _make_vsinfo_modes() - - -- init archs - vsinfo.archs = _make_vsinfo_archs() - - -- init groups - local groups, group_deps = _make_vsinfo_groups() - vsinfo.groups = table.keys(groups) - vsinfo.group_deps = table.keys(group_deps) - vsinfo._groups = groups - vsinfo._group_deps = group_deps - - -- init config flags - local flags = {} - for k, v in pairs(localcache.get("config", "options")) do - if k ~= "plat" and k ~= "mode" and k ~= "arch" and k ~= "clean" and k ~= "buildir" then - table.insert(flags, "--" .. k .. "=" .. tostring(v)) - end - end - vsinfo.configflags = os.args(flags) - - -- load targets - local targets = {} - vsinfo._arch_modes = {} - for _, mode in ipairs(vsinfo.modes) do - vsinfo._arch_modes[mode] = {} - for _, arch in ipairs(vsinfo.archs) do - vsinfo._arch_modes[mode][arch] = { mode = mode, arch = arch } - - -- trace - print("checking for %s.%s ...", mode, arch) - - -- reload config, project and platform - -- modify config - config.set("as", nil, {force = true}) -- force to re-check as for ml/ml64 - config.set("mode", mode, {readonly = true, force = true}) - config.set("arch", arch, {readonly = true, force = true}) - - -- clear all options - for _, opt in ipairs(project.options()) do - opt:clear() - end - - -- clear cache - memcache.clear() - localcache.clear("detect") - localcache.clear("option") - localcache.clear("package") - localcache.clear("toolchain") - - -- check platform - platform.load(config.plat(), arch):check() - - -- check project options - project.check() - - -- install and update requires - install_requires() - - -- config targets - _config_targets() - - -- update config files - generate_configfiles() - generate_configheader() - - -- ensure to enter project directory - os.cd(project.directory()) - - -- save targets - for targetname, target in pairs(project.targets()) do - -- make target with the given mode and arch - targets[targetname] = targets[targetname] or {} - local _target = targets[targetname] - - -- init target info - _target.target = targetname - _target.vcxprojdir = path.join(vsinfo.solution_dir, targetname) - _target.target_id = hash.uuid4(targetname) - _target.kind = target:kind() - _target.absscriptdir = target:scriptdir() - _target.scriptdir = path.relative(target:scriptdir(), _target.vcxprojdir) - _target.projectdir = path.relative(project.directory(), _target.vcxprojdir) - local targetdir = target:get("targetdir") - if targetdir then _target.targetdir = path.relative(targetdir, _target.vcxprojdir) end - _target._targets = _target._targets or {} - _target._targets[mode] = _target._targets[mode] or {} - local targetinfo = _make_targetinfo(mode, arch, target) - _target._targets[mode][arch] = targetinfo - _target.sdkver = targetinfo.sdkver - - -- save all sourcefiles and headerfiles - _target.sourcefiles = table.unique(table.join(_target.sourcefiles or {}, (target:sourcefiles()))) - _target.headerfiles = table.unique(table.join(_target.headerfiles or {}, (target:headerfiles()))) - - -- save deps - _target.deps = table.unique(table.join(_target.deps or {}, table.keys(target:deps()), nil)) - end - end - end - os.cd(oldir) - for _, target in pairs(targets) do - target._paths = {} - local dirs = {} - local projectdir = project.directory() - local root = target.absscriptdir or projectdir - target.sourcefiles = table.imap(target.sourcefiles, function(_, v) return path.relative(v, projectdir) end) - target.headerfiles = table.imap(target.headerfiles, function(_, v) return path.relative(v, projectdir) end) - for _, f in ipairs(table.join(target.sourcefiles, target.headerfiles)) do - local dir = path.directory(path.relative(f, root)) - local escaped_f = _escape(f) - -- @see https://github.com/xmake-io/xmake/issues/2039 - dir = _strip_dotdirs(dir) - target._paths[f] = - { - -- @see https://github.com/xmake-io/xmake/issues/2077 - path = path.is_absolute(escaped_f) and escaped_f or "$(XmakeProjectDir)\\" .. escaped_f, - dir = _escape(dir) - } - while dir ~= "." do - if not dirs[dir] then - dirs[dir] = - { - dir = _escape(dir), - dir_id = hash.uuid4(dir) - } - end - dir = path.directory(dir) - end - end - target._dirs = dirs - target.dirs = table.keys(dirs) - target._deps = {} - for _, v in ipairs(target.deps) do - target._deps[v] = targets[v] - end - end - - -- we need set startup project for default or binary target - -- @see https://github.com/xmake-io/xmake/issues/1249 - local targetnames = {} - for targetname, target in pairs(project.targets()) do - if target:get("default") == true then - table.insert(targetnames, 1, targetname) - elseif target:is_binary() then - local first_target = targetnames[1] and project.target(targetnames[1]) - if not first_target or first_target:is_default() then - table.insert(targetnames, 1, targetname) - else - table.insert(targetnames, targetname) - end - else - table.insert(targetnames, targetname) - end - end - vsinfo.targets = targetnames - vsinfo._targets = targets - return vsinfo -end +--!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 OpportunityLiu
+-- @file getinfo.lua
+--
+
+-- imports
+import("core.base.option")
+import("core.base.semver")
+import("core.base.hashset")
+import("core.project.config")
+import("core.project.project")
+import("core.platform.platform")
+import("core.tool.compiler")
+import("core.tool.linker")
+import("core.cache.memcache")
+import("core.cache.localcache")
+import("lib.detect.find_tool")
+import("private.action.run.make_runenvs")
+import("private.action.require.install", {alias = "install_requires"})
+import("actions.config.configheader", {alias = "generate_configheader", rootdir = os.programdir()})
+import("actions.config.configfiles", {alias = "generate_configfiles", rootdir = os.programdir()})
+
+-- escape special chars in msbuild file
+function _escape(str)
+ if not str then
+ return nil
+ end
+
+ local map =
+ {
+ ["%"] = "%25" -- Referencing metadata
+ , ["$"] = "%24" -- Referencing properties
+ , ["@"] = "%40" -- Referencing item lists
+ , ["'"] = "%27" -- Conditions and other expressions
+ , [";"] = "%3B" -- List separator
+ , ["?"] = "%3F" -- Wildcard character for file names in Include and Exclude attributes
+ , ["*"] = "%2A" -- Wildcard character for use in file names in Include and Exclude attributes
+ -- html entities
+ , ["\""] = """
+ , ["<"] = "<"
+ , [">"] = ">"
+ , ["&"] = "&"
+ }
+
+ return (string.gsub(str, "[%%%$@';%?%*\"<>&]", function (c) return assert(map[c]) end))
+end
+
+function _vs_arch(arch)
+ if arch == 'x86' or arch == 'i386' then return "Win32" end
+ if arch == 'x86_64' then return "x64" end
+ if arch:startswith('arm64') then return "ARM64" end
+ if arch:startswith('arm') then return "ARM" end
+ return arch
+end
+
+-- strip dot directories, e.g. ..\..\.. => ..
+-- @see https://github.com/xmake-io/xmake/issues/2039
+function _strip_dotdirs(dir)
+ local count
+ dir, count = dir:gsub("%.%.[\\/]%.%.", "..")
+ if count > 0 then
+ dir = _strip_dotdirs(dir)
+ end
+ return dir
+end
+
+function _make_dirs(dir)
+ if dir == nil then
+ return ""
+ end
+ if type(dir) == "string" then
+ dir = path.translate(dir)
+ if dir == "" then
+ return ""
+ end
+ if path.is_absolute(dir) then
+ if dir:startswith(project.directory()) then
+ return path.join("$(XmakeProjectDir)", _escape(path.relative(dir, project.directory())))
+ end
+ return _escape(dir)
+ end
+ return path.join("$(XmakeProjectDir)", _escape(dir))
+ end
+ local r = {}
+ for k, v in ipairs(dir) do
+ r[k] = _make_dirs(v)
+ end
+ r = table.unique(r)
+ return path.joinenv(r)
+end
+
+function _make_arrs(arr)
+ if arr == nil then
+ return ""
+ end
+ if type(arr) == "string" then
+ return _escape(arr)
+ end
+ local r = {}
+ for k, v in ipairs(arr) do
+ r[k] = _make_arrs(v)
+ end
+ r = table.unique(r)
+ return table.concat(r, ";")
+end
+
+-- get values from target
+function _get_values_from_target(target, name)
+ local values = table.wrap(target:get(name))
+ table.join2(values, target:get_from_opts(name))
+ table.join2(values, target:get_from_pkgs(name))
+ table.join2(values, target:get_from_deps(name, {interface = true}))
+ return table.unique(values)
+end
+
+-- make target info
+function _make_targetinfo(mode, arch, target)
+
+ -- init target info
+ local targetinfo =
+ {
+ mode = mode
+ , arch = arch
+ , plat = config.get("plat")
+ , vsarch = _vs_arch(arch)
+ , sdkver = config.get("vs_sdkver")
+ }
+
+ -- write only if not default
+ -- use target:get("xxx") rather than target:xxx()
+
+ -- save target kind
+ targetinfo.kind = target:kind()
+
+ -- is default?
+ targetinfo.default = tostring(target:is_default())
+
+ -- save target file
+ targetinfo.basename = _escape(target:get("basename"))
+ targetinfo.filename = _escape(target:get("filename"))
+
+ -- save dirs
+ targetinfo.targetdir = _make_dirs(target:get("targetdir"))
+ targetinfo.buildir = _make_dirs(config.get("buildir"))
+ targetinfo.rundir = _make_dirs(target:get("rundir"))
+ targetinfo.configdir = _make_dirs(os.getenv("XMAKE_CONFIGDIR"))
+ targetinfo.configfiledir = _make_dirs(target:get("configdir"))
+ targetinfo.includedirs = _make_dirs(table.join(_get_values_from_target(target, "includedirs") or {}, _get_values_from_target(target, "sysincludedirs")))
+ targetinfo.linkdirs = _make_dirs(_get_values_from_target(target, "linkdirs"))
+ targetinfo.sourcedirs = _make_dirs(_get_values_from_target(target, "values.project.vsxmake.sourcedirs"))
+ targetinfo.pcheaderfile = target:pcheaderfile("cxx") or target:pcheaderfile("c")
+
+ -- save defines
+ targetinfo.defines = _make_arrs(_get_values_from_target(target, "defines"))
+
+ -- save languages
+ targetinfo.languages = _make_arrs(_get_values_from_target(target, "languages"))
+ if targetinfo.languages then
+ -- fix c++17 to cxx17 for Xmake.props
+ targetinfo.languages = targetinfo.languages:replace("c++", "cxx", {plain = true})
+ end
+ if target:is_phony() or target:is_headeronly() then
+ return targetinfo
+ end
+
+ -- save subsystem
+ local linkflags = linker.linkflags(target:kind(), target:sourcekinds(), {target = target})
+ for _, linkflag in ipairs(linkflags) do
+ if linkflag:lower():find("[%-/]subsystem:windows") then
+ targetinfo.subsystem = "windows"
+ end
+ end
+ if not targetinfo.subsystem then
+ targetinfo.subsystem = "console"
+ end
+
+ -- save runenvs
+ local runenvs = {}
+ local addrunenvs, setrunenvs = make_runenvs(target)
+ for k, v in pairs(target:pkgenvs()) do
+ addrunenvs = addrunenvs or {}
+ addrunenvs[k] = table.join(table.wrap(addrunenvs[k]), path.splitenv(v))
+ end
+ for _, dep in ipairs(target:orderdeps()) do
+ for k, v in pairs(dep:pkgenvs()) do
+ addrunenvs = addrunenvs or {}
+ addrunenvs[k] = table.join(table.wrap(addrunenvs[k]), path.splitenv(v))
+ end
+ end
+ for k, v in pairs(addrunenvs) do
+ if k:upper() == "PATH" then
+ runenvs[k] = _make_dirs(v) .. ";$([System.Environment]::GetEnvironmentVariable('" .. k .. "'))"
+ else
+ runenvs[k] = path.joinenv(v) .. ";$([System.Environment]::GetEnvironmentVariable('" .. k .."'))"
+ end
+ end
+ for k, v in pairs(setrunenvs) do
+ if #v == 1 then
+ v = v[1]
+ if path.is_absolute(v) and v:startswith(project.directory()) then
+ runenvs[k] = _make_dirs(v)
+ else
+ runenvs[k] = v[1]
+ end
+ else
+ runenvs[k] = path.joinenv(v)
+ end
+ end
+ local runenvstr = {}
+ for k, v in pairs(runenvs) do
+ table.insert(runenvstr, k .. "=" .. v)
+ end
+ targetinfo.runenvs = table.concat(runenvstr, "\n")
+
+ -- use mfc? save the mfc runtime kind
+ if target:rule("win.sdk.mfc.shared_app") or target:rule("win.sdk.mfc.shared") then
+ targetinfo.mfckind = "Dynamic"
+ elseif target:rule("win.sdk.mfc.static_app") or target:rule("win.sdk.mfc.static") then
+ targetinfo.mfckind = "Static"
+ end
+
+ -- use cuda? save the cuda runtime version
+ if target:rule("cuda") then
+ local nvcc = find_tool("nvcc", { version = true })
+ local ver = semver.new(nvcc.version)
+ targetinfo.cudaver = ver:major() .. "." .. ver:minor()
+ end
+ return targetinfo
+end
+
+function _make_vsinfo_modes()
+ local vsinfo_modes = {}
+ local modes = option.get("modes")
+ if modes then
+ if not modes:find("\"") then
+ modes = modes:gsub(",", path.envsep())
+ end
+ for _, mode in ipairs(path.splitenv(modes)) do
+ table.insert(vsinfo_modes, mode:trim())
+ end
+ else
+ vsinfo_modes = project.modes()
+ end
+ if not vsinfo_modes or #vsinfo_modes == 0 then
+ vsinfo_modes = { config.mode() }
+ end
+ return vsinfo_modes
+end
+
+function _make_vsinfo_archs()
+ local vsinfo_archs = {}
+ local archs = option.get("archs")
+ if archs then
+ if not archs:find("\"") then
+ archs = archs:gsub(",", path.envsep())
+ end
+ for _, arch in ipairs(path.splitenv(archs)) do
+ table.insert(vsinfo_archs, arch:trim())
+ end
+ else
+ -- we use it first if global set_arch("xx") is setted in xmake.lua
+ vsinfo_archs = project.get("target.arch")
+ if not vsinfo_archs then
+ -- for set_allowedarchs()
+ local allowed_archs = project.allowed_archs(config.plat())
+ if allowed_archs then
+ vsinfo_archs = allowed_archs:to_array()
+ end
+ end
+ if not vsinfo_archs then
+ vsinfo_archs = platform.archs()
+ end
+ end
+ if not vsinfo_archs or #vsinfo_archs == 0 then
+ vsinfo_archs = { config.arch() }
+ end
+ return vsinfo_archs
+end
+
+function _make_vsinfo_groups()
+ local groups = {}
+ local group_deps = {}
+ for targetname, target in pairs(project.targets()) do
+ if not target:is_phony() then
+ local group_path = target:get("group")
+ if group_path then
+ local group_name = path.filename(group_path)
+ local group_names = path.split(group_path)
+ for idx, name in ipairs(group_names) do
+ local group = groups["group." .. name] or {}
+ group.group = name
+ group.group_id = hash.uuid4("group." .. name)
+ if idx > 1 then
+ group_deps["group_dep." .. name] = {current_id = group.group_id, parent_id = hash.uuid4(group_names[idx - 1])}
+ end
+ groups["group." .. name] = group
+ end
+ group_deps["group_dep.target." .. targetname] = {current_id = hash.uuid4(targetname), parent_id = groups["group." .. group_name].group_id}
+ end
+ end
+ end
+ return groups, group_deps
+end
+
+-- config target
+function _config_target(target)
+ for _, rule in ipairs(target:orderules()) do
+ local on_config = rule:script("config")
+ if on_config then
+ on_config(target)
+ end
+ end
+ local on_config = target:script("config")
+ if on_config then
+ on_config(target)
+ end
+end
+
+-- config targets
+function _config_targets()
+ for _, target in ipairs(project.ordertargets()) do
+ if target:is_enabled() then
+ _config_target(target)
+ end
+ end
+end
+
+-- make vstudio project
+function main(outputdir, vsinfo)
+
+ -- enter project directory
+ local oldir = os.cd(project.directory())
+
+ -- init solution directory
+ vsinfo.solution_dir = path.absolute(path.join(outputdir, "vsxmake" .. vsinfo.vstudio_version))
+ vsinfo.programdir = _make_dirs(xmake.programdir())
+ vsinfo.projectdir = project.directory()
+ vsinfo.sln_projectfile = path.relative(project.rootfile(), vsinfo.solution_dir)
+ local projectfile = path.filename(project.rootfile())
+ vsinfo.slnfile = project.name() or path.filename(project.directory())
+ -- write only if not default
+ if projectfile ~= "xmake.lua" then
+ vsinfo.projectfile = projectfile
+ end
+
+ vsinfo.xmake_info = format("xmake version %s", xmake.version())
+ vsinfo.solution_id = hash.uuid4(project.directory() .. vsinfo.solution_dir)
+ vsinfo.vs_version = vsinfo.project_version .. ".0"
+
+ -- init modes
+ vsinfo.modes = _make_vsinfo_modes()
+
+ -- init archs
+ vsinfo.archs = _make_vsinfo_archs()
+
+ -- init groups
+ local groups, group_deps = _make_vsinfo_groups()
+ vsinfo.groups = table.keys(groups)
+ vsinfo.group_deps = table.keys(group_deps)
+ vsinfo._groups = groups
+ vsinfo._group_deps = group_deps
+
+ -- init config flags
+ local flags = {}
+ for k, v in pairs(localcache.get("config", "options")) do
+ if k ~= "plat" and k ~= "mode" and k ~= "arch" and k ~= "clean" and k ~= "buildir" then
+ table.insert(flags, "--" .. k .. "=" .. tostring(v))
+ end
+ end
+ vsinfo.configflags = os.args(flags)
+
+ -- load targets
+ local targets = {}
+ vsinfo._arch_modes = {}
+ for _, mode in ipairs(vsinfo.modes) do
+ vsinfo._arch_modes[mode] = {}
+ for _, arch in ipairs(vsinfo.archs) do
+ vsinfo._arch_modes[mode][arch] = { mode = mode, arch = arch }
+
+ -- trace
+ print("checking for %s.%s ...", mode, arch)
+
+ -- reload config, project and platform
+ -- modify config
+ config.set("as", nil, {force = true}) -- force to re-check as for ml/ml64
+ config.set("mode", mode, {readonly = true, force = true})
+ config.set("arch", arch, {readonly = true, force = true})
+
+ -- clear all options
+ for _, opt in ipairs(project.options()) do
+ opt:clear()
+ end
+
+ -- clear cache
+ memcache.clear()
+ localcache.clear("detect")
+ localcache.clear("option")
+ localcache.clear("package")
+ localcache.clear("toolchain")
+
+ -- check platform
+ platform.load(config.plat(), arch):check()
+
+ -- check project options
+ project.check()
+
+ -- install and update requires
+ install_requires()
+
+ -- config targets
+ _config_targets()
+
+ -- update config files
+ generate_configfiles()
+ generate_configheader()
+
+ -- ensure to enter project directory
+ os.cd(project.directory())
+
+ -- save targets
+ for targetname, target in pairs(project.targets()) do
+ -- make target with the given mode and arch
+ targets[targetname] = targets[targetname] or {}
+ local _target = targets[targetname]
+
+ -- init target info
+ _target.target = targetname
+ _target.vcxprojdir = path.join(vsinfo.solution_dir, targetname)
+ _target.target_id = hash.uuid4(targetname)
+ _target.kind = target:kind()
+ _target.absscriptdir = target:scriptdir()
+ _target.scriptdir = path.relative(target:scriptdir(), _target.vcxprojdir)
+ _target.projectdir = path.relative(project.directory(), _target.vcxprojdir)
+ local targetdir = target:get("targetdir")
+ if targetdir then _target.targetdir = path.relative(targetdir, _target.vcxprojdir) end
+ _target._targets = _target._targets or {}
+ _target._targets[mode] = _target._targets[mode] or {}
+ local targetinfo = _make_targetinfo(mode, arch, target)
+ _target._targets[mode][arch] = targetinfo
+ _target.sdkver = targetinfo.sdkver
+
+ -- save all sourcefiles and headerfiles
+ _target.sourcefiles = table.unique(table.join(_target.sourcefiles or {}, (target:sourcefiles())))
+ _target.headerfiles = table.unique(table.join(_target.headerfiles or {}, (target:headerfiles())))
+
+ -- save deps
+ _target.deps = table.unique(table.join(_target.deps or {}, table.keys(target:deps()), nil))
+ end
+ end
+ end
+ os.cd(oldir)
+ for _, target in pairs(targets) do
+ target._paths = {}
+ local dirs = {}
+ local projectdir = project.directory()
+ local root = target.absscriptdir or projectdir
+ target.sourcefiles = table.imap(target.sourcefiles, function(_, v) return path.relative(v, projectdir) end)
+ target.headerfiles = table.imap(target.headerfiles, function(_, v) return path.relative(v, projectdir) end)
+ for _, f in ipairs(table.join(target.sourcefiles, target.headerfiles)) do
+ local dir = path.directory(path.relative(f, root))
+ local escaped_f = _escape(f)
+ -- @see https://github.com/xmake-io/xmake/issues/2039
+ dir = _strip_dotdirs(dir)
+ target._paths[f] =
+ {
+ -- @see https://github.com/xmake-io/xmake/issues/2077
+ path = path.is_absolute(escaped_f) and escaped_f or "$(XmakeProjectDir)\\" .. escaped_f,
+ dir = _escape(dir)
+ }
+ while dir ~= "." do
+ if not dirs[dir] then
+ dirs[dir] =
+ {
+ dir = _escape(dir),
+ dir_id = hash.uuid4(dir)
+ }
+ end
+ dir = path.directory(dir)
+ end
+ end
+ target._dirs = dirs
+ target.dirs = table.keys(dirs)
+ target._deps = {}
+ for _, v in ipairs(target.deps) do
+ target._deps[v] = targets[v]
+ end
+ end
+
+ -- we need set startup project for default or binary target
+ -- @see https://github.com/xmake-io/xmake/issues/1249
+ local targetnames = {}
+ for targetname, target in pairs(project.targets()) do
+ if target:get("default") == true then
+ table.insert(targetnames, 1, targetname)
+ elseif target:is_binary() then
+ local first_target = targetnames[1] and project.target(targetnames[1])
+ if not first_target or first_target:is_default() then
+ table.insert(targetnames, 1, targetname)
+ else
+ table.insert(targetnames, targetname)
+ end
+ else
+ table.insert(targetnames, targetname)
+ end
+ end
+ vsinfo.targets = targetnames
+ vsinfo._targets = targets
+ return vsinfo
+end
|
