diff options
| author | shuax <[email protected]> | 2022-03-30 21:43:09 +0800 |
|---|---|---|
| committer | shuax <[email protected]> | 2022-03-30 21:43:09 +0800 |
| commit | 38a8b1b5df206409c861b3f46efe9e99fd04e94f (patch) | |
| tree | e0629c0c3490bec72ef0b202d5ffcd351e569ef0 | |
| parent | 90e51e78a59569d939332837bd4189f830a7af93 (diff) | |
fix line endings
| -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 6e4b81dc8..c9dea0c34 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." .. 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
+--!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 aa886e715..a2623f226 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("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
+--!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 |
