summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2022-02-26 22:42:51 +0800
committerGitHub <[email protected]>2022-02-26 22:42:51 +0800
commit534e8608d5867ef766cf6b2836ccbe2b72fbdfee (patch)
tree97aaf33757319366ea13925c01a23d850a583dd2
parentf527dbaf01ee10efb14cf0b12aca00b25debc011 (diff)
parentf8a510b9e8b24283b3fbe3edc839cc3edac9bb65 (diff)
Merge pull request #2093 from xq114/dev
support cuda for vs generator
-rw-r--r--xmake/plugins/project/cmake/cmakelists.lua3
-rw-r--r--xmake/plugins/project/vstudio/impl/vs201x.lua46
-rw-r--r--xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua427
-rw-r--r--xmake/plugins/project/vstudio/impl/vs201x_vcxproj_filters.lua11
-rw-r--r--xmake/plugins/project/vstudio/impl/vsutils.lua44
-rw-r--r--xmake/plugins/project/vstudio/vs.lua11
-rw-r--r--xmake/plugins/project/vsxmake/getinfo.lua2
7 files changed, 451 insertions, 93 deletions
diff --git a/xmake/plugins/project/cmake/cmakelists.lua b/xmake/plugins/project/cmake/cmakelists.lua
index 925a4659c..7b1fe3167 100644
--- a/xmake/plugins/project/cmake/cmakelists.lua
+++ b/xmake/plugins/project/cmake/cmakelists.lua
@@ -65,8 +65,7 @@ end
function _get_project_languages(targets)
local languages = {}
for _, target in pairs(targets) do
- for _, sourcebatch in pairs(target:sourcebatches()) do
- local sourcekind = sourcebatch.sourcekind
+ for _, sourcekind in ipairs(target:sourcekinds()) do
if sourcekind == "cc" then table.insert(languages, "C")
elseif sourcekind == "cxx" then table.insert(languages, "CXX")
elseif sourcekind == "as" then table.insert(languages, "ASM")
diff --git a/xmake/plugins/project/vstudio/impl/vs201x.lua b/xmake/plugins/project/vstudio/impl/vs201x.lua
index b7186dab5..fa0240c4e 100644
--- a/xmake/plugins/project/vstudio/impl/vs201x.lua
+++ b/xmake/plugins/project/vstudio/impl/vs201x.lua
@@ -30,6 +30,7 @@ import("core.tool.toolchain")
import("vs201x_solution")
import("vs201x_vcxproj")
import("vs201x_vcxproj_filters")
+import("vsutils")
import("core.cache.memcache")
import("core.cache.localcache")
import("private.action.require.install", {alias = "install_requires"})
@@ -38,31 +39,6 @@ import("actions.config.configfiles", {alias = "generate_configfiles", rootdir =
import("actions.config.configheader", {alias = "generate_configheader", rootdir = os.programdir()})
import("private.utils.batchcmds")
--- 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
- , ["\""] = "&quot;"
- , ["<"] = "&lt;"
- , [">"] = "&gt;"
- , ["&"] = "&amp;"
- }
-
- return (string.gsub(str, "[%%%$@';%?%*\"<>&]", function (c) return assert(map[c]) end))
-end
-
function _make_dirs(dir, vcxprojdir)
if dir == nil then
return ""
@@ -74,11 +50,11 @@ function _make_dirs(dir, vcxprojdir)
end
if path.is_absolute(dir) then
if dir:startswith(project.directory()) then
- return _escape(path.relative(dir, vcxprojdir))
+ return vsutils.escape(path.relative(dir, vcxprojdir))
end
- return _escape(dir)
+ return vsutils.escape(dir)
else
- return _escape(path.relative(path.absolute(dir), vcxprojdir))
+ return vsutils.escape(path.relative(path.absolute(dir), vcxprojdir))
end
end
local r = {}
@@ -274,6 +250,9 @@ function _make_targetinfo(mode, arch, target, vcxprojdir)
-- save sourcebatches
targetinfo.sourcebatches = target:sourcebatches()
+ -- save sourcekinds
+ targetinfo.sourcekinds = target:sourcekinds()
+
-- save target dir
targetinfo.targetdir = target:targetdir()
@@ -289,7 +268,7 @@ function _make_targetinfo(mode, arch, target, vcxprojdir)
if sourcekind then
for idx, sourcefile in ipairs(sourcebatch.sourcefiles) do
local compflags = compiler.compflags(sourcefile, {target = target})
- if not firstcompflags and (sourcekind == "cc" or sourcekind == "cxx") then
+ if not firstcompflags and (sourcekind == "cc" or sourcekind == "cxx" or sourcekind == "cu") then
firstcompflags = compflags
end
targetinfo.compflags[sourcefile] = compflags
@@ -302,6 +281,15 @@ function _make_targetinfo(mode, arch, target, vcxprojdir)
local linkflags = linker.linkflags(target:kind(), target:sourcekinds(), {target = target})
targetinfo.linkflags = linkflags
+ if table.contains(target:sourcekinds(), "cu") then
+ -- save cuda linker flags
+ local linkinst = linker.load("gpucode", "cu", {target = target})
+ targetinfo.culinkflags = linkinst:linkflags({target = target})
+
+ -- save cuda devlink status
+ targetinfo.cudevlink = target:values("cuda.build.devlink")
+ end
+
-- save execution dir (when executed from VS)
targetinfo.rundir = target:rundir()
diff --git a/xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua b/xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua
index 9317312a0..f1154cb34 100644
--- a/xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua
+++ b/xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua
@@ -26,7 +26,9 @@ import("core.project.project")
import("core.language.language")
import("core.tool.toolchain")
import("private.utils.batchcmds")
+import("detect.sdks.find_cuda")
import("vsfile")
+import("vsutils")
function _make_dirs(dir, vcxprojdir)
dir = dir:trim()
@@ -40,6 +42,24 @@ function _make_dirs(dir, vcxprojdir)
return dir
end
+-- check for CUDA
+function _check_cuda(target)
+ local cuda
+ for _, targetinfo in ipairs(target.info) do
+ if table.contains(targetinfo.sourcekinds, "cu") then
+ cuda = find_cuda()
+ break
+ end
+ end
+ if cuda then
+ if cuda.msbuildextensionsdir and cuda.version and os.isfile(path.join(cuda.msbuildextensionsdir, format("CUDA %s.props", cuda.version))) then
+ return cuda
+ else
+ os.raise("The Visual Studio Integration for CUDA %s is not found. Please check your CUDA installation.", cuda.version)
+ end
+ end
+end
+
-- get toolset version
function _get_toolset_ver(targetinfo, vsinfo)
@@ -70,6 +90,54 @@ function _get_platform_sdkver(target, vsinfo)
return sdkver or vsinfo.sdk_version
end
+-- combine two successive flags
+function _combine_flags(flags, patterns)
+ local newflags = {}
+ local temparg
+ for _, arg in ipairs(flags) do
+ if temparg then
+ table.insert(newflags, temparg .. " " .. arg)
+ temparg = nil
+ else
+ for _, pattern in ipairs(patterns) do
+ if arg:match(pattern) then
+ temparg = arg
+ end
+ end
+ if not temparg then
+ table.insert(newflags, arg)
+ end
+ end
+ end
+ return newflags
+end
+
+-- exclude patterns from flags
+function _exclude_flags(flags, excludes)
+ local newflags = {}
+ for _, flag in ipairs(flags) do
+ local excluded = false
+ for _, exclude in ipairs(excludes) do
+ if flag:find("^[%-/]" .. exclude) then
+ excluded = true
+ break
+ end
+ end
+ if not excluded then
+ table.insert(newflags, vsutils.escape(flag))
+ end
+ end
+ return newflags
+end
+
+-- try split from nvcc -code flag
+-- e.g. nvcc -arch=compute_86 -code=\"sm_86,compute_86\"
+-- nvcc -gencode arch=compute_86,code=[sm_86,compute_86]
+function _split_gpucodes(flag)
+ flag = flag:gsub("[%[\"]?(.-)[%]\"]?", "%1")
+ return flag:split(",")
+end
+
-- make compiling command
function _make_compcmd(compargv, sourcefile, objectfile, vcxprojdir)
local argv = {}
@@ -159,9 +227,13 @@ function _make_header(vcxprojfile, vsinfo)
end
-- make tailer
-function _make_tailer(vcxprojfile, vsinfo)
+function _make_tailer(vcxprojfile, vsinfo, target)
vcxprojfile:print("<Import Project=\"%$(VCTargetsPath)\\Microsoft.Cpp.targets\" />")
vcxprojfile:enter("<ImportGroup Label=\"ExtensionTargets\">")
+ local cuda = _check_cuda(target)
+ if cuda then
+ vcxprojfile:print("<Import Project=\"%s\" />", path.join(cuda.msbuildextensionsdir, format("CUDA %s.targets", cuda.version)))
+ end
vcxprojfile:leave("</ImportGroup>")
vcxprojfile:leave("</Project>")
end
@@ -219,6 +291,10 @@ function _make_configurations(vcxprojfile, vsinfo, target)
-- make ExtensionSettings
vcxprojfile:enter("<ImportGroup Label=\"ExtensionSettings\">")
+ local cuda = _check_cuda(target)
+ if cuda then
+ vcxprojfile:print("<Import Project=\"%s\" />", path.join(cuda.msbuildextensionsdir, format("CUDA %s.props", cuda.version)))
+ end
vcxprojfile:leave("</ImportGroup>")
-- make PropertySheets
@@ -248,7 +324,7 @@ function _make_configurations(vcxprojfile, vsinfo, target)
-- handle ExternalIncludePath (should we handle IncludePath here too?)
local externaldirs = {}
- for _, flag in ipairs(targetinfo.commonflags) do
+ for _, flag in ipairs(targetinfo.commonflags.cl) do
flag:gsub("[%-/]external:I(.*)", function (dir) table.insert(externaldirs, dir) end)
end
if #externaldirs > 0 then
@@ -267,8 +343,8 @@ function _make_configurations(vcxprojfile, vsinfo, target)
end
end
--- make source options
-function _make_source_options(vcxprojfile, flags, condition)
+-- make source options for cl
+function _make_source_options_cl(vcxprojfile, flags, condition)
-- exists condition?
condition = condition or ""
@@ -346,9 +422,9 @@ function _make_source_options(vcxprojfile, flags, condition)
-- make PreprocessorDefinitions
local defstr = ""
for _, flag in ipairs(flags) do
- flag:gsub("[%-/]D(.*)",
+ flag:gsub("^[%-/]D(.*)",
function (def)
- defstr = defstr .. def .. ";"
+ defstr = defstr .. vsutils.escape(def) .. ";"
end
)
end
@@ -389,7 +465,7 @@ function _make_source_options(vcxprojfile, flags, condition)
if flagstr:find("[%-/]I") then
local dirs = {}
for _, flag in ipairs(flags) do
- flag:gsub("[%-/]I(.*)", function (dir) table.insert(dirs, dir) end)
+ flag:gsub("^[%-/]I(.*)", function (dir) table.insert(dirs, vsutils.escape(dir)) end)
end
if #dirs > 0 then
vcxprojfile:print("<AdditionalIncludeDirectories%s>%s</AdditionalIncludeDirectories>", condition, table.concat(dirs, ";"))
@@ -402,24 +478,192 @@ function _make_source_options(vcxprojfile, flags, condition)
end
-- make AdditionalOptions
- local additional_flags = {}
local excludes = {
"Od", "Os", "O0", "O1", "O2", "Ot", "Ox", "W0", "W1", "W2", "W3", "W4", "WX", "Wall", "Zi", "ZI", "Z7", "MT", "MTd", "MD", "MDd", "TP",
"Fd", "fp", "I", "D", "Gm-", "Gm", "MP", "external:W0", "external:W1", "external:W2", "external:W3", "external:W4", "external:templates-?", "external:I",
"std:c11", "std:c17", "std:c%+%+11", "std:c%+%+14", "std:c%+%+17", "std:c%+%+20", "std:c%+%+latest", "nologo", "wd(%d+)"
}
+ local additional_flags = _exclude_flags(flags, excludes)
+ if #additional_flags > 0 then
+ vcxprojfile:print("<AdditionalOptions%s>%s %%(AdditionalOptions)</AdditionalOptions>", condition, os.args(additional_flags))
+ end
+end
+
+-- make source options for cuda
+function _make_source_options_cuda(vcxprojfile, flags, opt)
+
+ -- exists condition?
+ condition = (opt and opt.condition) or ""
+
+ -- combine successive commands
+ flags = _combine_flags(flags, {"^%-gencode$", "^%-arch$", "^%-code$", "^%-%-machine$", "^%-rdc$", "^%-cudart$", "^%-%-keep%-dir$"})
+
+ -- get flags string
+ local flagstr = os.args(flags)
+
+ if not (opt and opt.link) then
+
+ -- make Optimization
+ if flagstr:find("[%-/]Od") then
+ vcxprojfile:print("<Optimization%s>Od</Optimization>", condition)
+ elseif flagstr:find("[%-/]O1") then
+ vcxprojfile:print("<Optimization%s>O1</Optimization>", condition)
+ elseif flagstr:find("[%-/]O2") then
+ vcxprojfile:print("<Optimization%s>O2</Optimization>", condition)
+ elseif flagstr:find("[%-/]O3") or flagstr:find("[%-/]Ox") then
+ vcxprojfile:print("<Optimization%s>O3</Optimization>", condition)
+ end
+
+ -- make Warning
+ if flagstr:find("[%-/]W[1234]") then
+ local wlevel = flagstr:find("[%-/](W[1234])")
+ vcxprojfile:print("<Warning%s>%s</Warning>", condition, wlevel)
+ elseif flagstr:find("[%-/]Wall") then
+ vcxprojfile:print("<Warning%s>Wall</Warning>", condition)
+ end
+
+ -- make Defines
+ local defstr = ""
+ for _, flag in ipairs(flags) do
+ flag:gsub("^[%-/]D(.*)",
+ function (def)
+ defstr = defstr .. vsutils.escape(def) .. ";"
+ end
+ )
+ end
+ defstr = defstr .. "%%(Defines)"
+ vcxprojfile:print("<Defines%s>%s</Defines>", condition, defstr)
+
+ -- make Include
+ if flagstr:find("[%-/]I") then
+ local dirs = {}
+ for _, flag in ipairs(flags) do
+ flag:gsub("^[%-/]I(.*)", function (dir) table.insert(dirs, vsutils.escape(dir)) end)
+ end
+ if #dirs > 0 then
+ vcxprojfile:print("<Include%s>%s</Include>", condition, table.concat(dirs, ";"))
+ end
+ end
+
+ end
+
+ -- make TargetMachinePlatform
+ local machinebitwidth
for _, flag in ipairs(flags) do
- local excluded = false
- for _, exclude in ipairs(excludes) do
- if flag:find("[%-/]" .. exclude) then
- excluded = true
- break
+ flag:gsub("^%-m(.+)", function (value) machinebitwidth = value end)
+ flag:gsub("^%-%-machine[ =](.+)", function (value) machinebitwidth = value end)
+ end
+ if machinebitwidth and (machinebitwidth == "32" or machinebitwidth == "64") then
+ vcxprojfile:print("<TargetMachinePlatform%s>%s</TargetMachinePlatform>", condition, machinebitwidth)
+ end
+
+ -- make CodeGeneration
+ local gpucode_patterns = {
+ "^%-gencode[ =]arch=(.+),code=(.+)",
+ "^%-%-generate%-code[ =]arch=(.+),code=(.+)",
+ "^%-arch",
+ "^%-%-gpu%-architecture",
+ "^%-code",
+ "^%-%-gpu%-code"
+ }
+ local has_gpucode = false
+ for _, pattern in ipairs(gpucode_patterns) do
+ if flagstr:find(pattern) then
+ has_gpucode = true
+ break
+ end
+ end
+ if has_gpucode then
+ local arch
+ local codes = {}
+ local gencodes = {}
+ for _, flag in ipairs(flags) do
+ flag:gsub("%-gencode[ =]arch=(.+),code=(.+)$", function (garch, gcodes)
+ for _, gcode in ipairs(_split_gpucodes(gcodes)) do
+ table.insert(gencodes, garch .. "," .. gcode)
+ end
+ end)
+ flag:gsub("^%-%-generate%-code[ =]arch=(.+),code=(.+)", function (garch, gcodes)
+ for _, gcode in ipairs(_split_gpucodes(gcodes)) do
+ table.insert(gencodes, garch .. "," .. gcode)
+ end
+ end)
+ flag:gsub("^%-arch[ =](.+)", function (garch) arch = garch end)
+ flag:gsub("^%-%-gpu%-architecture[ =](.+)", function (garch) arch = garch end)
+ flag:gsub("^%-code[ =](.+)", function (gcodes) table.join2(codes, _split_gpucodes(gcodes)) end)
+ flag:gsub("^%-%-gpu%-code[ =](.+)", function (gcodes) table.join2(codes, _split_gpucodes(gcodes)) end)
+ end
+ if arch then
+ if #codes == 0 then
+ table.insert(codes, arch)
+ arch = arch:gsub("sm", "compute")
+ table.insert(gencodes, arch .. "," .. arch)
+ end
+ for _, code in ipairs(codes) do
+ table.insert(gencodes, arch .. "," .. code)
end
end
- if not excluded then
- table.insert(additional_flags, flag)
+ if #gencodes > 0 then
+ gencodes = table.unique(gencodes)
+ vcxprojfile:print("<CodeGeneration%s>%s</CodeGeneration>", condition, table.concat(gencodes, ";"))
end
end
+
+ if not (opt and opt.link) then
+
+ -- make CudaRuntime
+ local cudart
+ local cudaruntime = {
+ none = "None",
+ static = "Static",
+ shared = "Shared"
+ }
+ for _, flag in ipairs(flags) do
+ flag:gsub("%-cudart[ =](.+)", function (value) cudart = value end)
+ end
+ if cudart and cudaruntime[cudart] then
+ vcxprojfile:print("<CudaRuntime%s>%s</CudaRuntime>", condition, cudaruntime[cudart])
+ end
+
+ -- handle GPU debug info
+ if flagstr:find("%-G") then
+ vcxprojfile:print("<GPUDebugInfo%s>true</GPUDebugInfo>", condition)
+ end
+
+ -- handle fast math
+ if flagstr:find("%-use_fast_math") then
+ vcxprojfile:print("<FastMath%s>true</FastMath>", condition)
+ end
+
+ -- handle relocatable device code
+ local rdc
+ for _, flag in ipairs(flags) do
+ flag:gsub("%-rdc[ =](.+)", function (value) rdc = value end)
+ end
+ if rdc then
+ vcxprojfile:print("<GenerateRelocatableDeviceCode%s>%s</GenerateRelocatableDeviceCode>", condition, rdc)
+ end
+
+ -- handle keep preprocessed files or directories
+ if flagstr:find("%-%-keep") then
+ vcxprojfile:print("<Keep%s>true</Keep>", condition)
+ end
+ if flagstr:find("%-%-keep%-dir") then
+ local dirs = {}
+ for _, flag in ipairs(flags) do
+ flag:gsub("%-%-keep%-dir[ =](.*)", function (dir) table.insert(dirs, dir) end)
+ end
+ if #dirs > 0 then
+ vcxprojfile:print("<KeepDir%s>%s</KeepDir>", condition, table.concat(dirs, ";"))
+ end
+ end
+ end
+
+ -- make AdditionalOptions
+ local excludes = {
+ "Od", "O1", "O2", "O3", "Ox", "W1", "W2", "W3", "W4", "Wall", "I", "D", "L", "l", "m", "%-machine", "gencode", "arch", "code", "cudart", "G", "use_fast_math", "rdc", "%-keep", "%-keep%-dir"
+ }
+ local additional_flags = _exclude_flags(flags, excludes)
if #additional_flags > 0 then
vcxprojfile:print("<AdditionalOptions%s>%s %%(AdditionalOptions)</AdditionalOptions>", condition, os.args(additional_flags))
end
@@ -502,7 +746,7 @@ function _make_common_item(vcxprojfile, vsinfo, target, targetinfo)
subsystem = "Windows"
elseif flag_lower:find("[%-/]libpath") then
-- link dir
- flag:gsub("[%-/]libpath:(.*)", function (dir) table.insert(libdirs, dir) end)
+ flag:gsub("[%-/]libpath:(.*)", function (dir) table.insert(libdirs, vsutils.escape(dir)) end)
elseif flag_lower:find("[^%-/].+%.lib") then
-- link file
table.insert(links, flag)
@@ -534,7 +778,7 @@ function _make_common_item(vcxprojfile, vsinfo, target, targetinfo)
-- make AdditionalOptions
if #flags > 0 then
flags = os.args(flags)
- vcxprojfile:print("<AdditionalOptions>%s %%(AdditionalOptions)</AdditionalOptions>", flags)
+ vcxprojfile:print("<AdditionalOptions>%s %%(AdditionalOptions)</AdditionalOptions>", vsutils.escape(flags))
end
-- generate debug infomation?
@@ -562,11 +806,11 @@ function _make_common_item(vcxprojfile, vsinfo, target, targetinfo)
vcxprojfile:leave("</%s>", linkerkinds[targetinfo.targetkind])
- -- for compiler?
+ -- for C/C++ compiler?
vcxprojfile:enter("<ClCompile>")
-- make source options
- _make_source_options(vcxprojfile, targetinfo.commonflags)
+ _make_source_options_cl(vcxprojfile, targetinfo.commonflags.cl)
-- add c and c++ standard
local clangflags = {
@@ -619,15 +863,39 @@ function _make_common_item(vcxprojfile, vsinfo, target, targetinfo)
-- make precompiled header and outputfile
vcxprojfile:print("<PrecompiledHeader>Use</PrecompiledHeader>")
- vcxprojfile:print("<PrecompiledHeaderFile>%s</PrecompiledHeaderFile>", path.filename(pcheader))
+ vcxprojfile:print("<PrecompiledHeaderFile>%s</PrecompiledHeaderFile>", vsutils.escape(path.filename(pcheader)))
local pcoutputfile = targetinfo.pcxxoutputfile or targetinfo.pcoutputfile
if pcoutputfile then
- vcxprojfile:print("<PrecompiledHeaderOutputFile>%s</PrecompiledHeaderOutputFile>", path.relative(path.absolute(pcoutputfile), target.project_dir))
+ vcxprojfile:print("<PrecompiledHeaderOutputFile>%s</PrecompiledHeaderOutputFile>", vsutils.escape(path.relative(path.absolute(pcoutputfile), target.project_dir)))
end
- vcxprojfile:print("<ForcedIncludeFiles>%s;%%(ForcedIncludeFiles)</ForcedIncludeFiles>", path.filename(pcheader))
+ vcxprojfile:print("<ForcedIncludeFiles>%s;%%(ForcedIncludeFiles)</ForcedIncludeFiles>", vsutils.escape(path.filename(pcheader)))
end
vcxprojfile:leave("</ClCompile>")
+
+ local cuda = _check_cuda(target)
+ if cuda then
+ -- for CUDA linker?
+ vcxprojfile:enter("<CudaLink>")
+
+ -- make cuda link flags
+ _make_source_options_cuda(vcxprojfile, targetinfo.culinkflags, {link = true})
+
+ -- make devlink
+ if targetinfo.cudevlink then
+ vcxprojfile:print("<PerformDeviceLink>%s</PerformDeviceLink>", targetinfo.cudevlink)
+ end
+
+ vcxprojfile:leave("</CudaLink>")
+
+ -- for CUDA compiler?
+ vcxprojfile:enter("<CudaCompile>")
+
+ -- make source options
+ _make_source_options_cuda(vcxprojfile, targetinfo.commonflags.cuda)
+
+ vcxprojfile:leave("</CudaCompile>")
+ end
-- make custom commands
_make_custom_commands(vcxprojfile, targetinfo)
@@ -643,9 +911,9 @@ function _build_common_items(vsinfo, target)
for _, targetinfo in ipairs(target.info) do
-- make source flags
- local flags_stats = {}
- local files_count = 0
- local first_flags = nil
+ local flags_stats = {cl = {}, cuda = {}}
+ local files_count = {cl = 0, cuda = 0}
+ local first_flags = {}
targetinfo.sourceflags = {}
for _, sourcebatch in pairs(targetinfo.sourcebatches) do
local sourcekind = sourcebatch.sourcekind
@@ -657,43 +925,84 @@ function _build_common_items(vsinfo, target)
-- no common flags for asm
if sourcekind ~= "as" then
- for _, flag in ipairs(flags) do
- flags_stats[flag] = (flags_stats[flag] or 0) + 1
+ for _, flag in ipairs(table.unique(flags)) do
+ flags_stats.cl[flag] = (flags_stats.cl[flag] or 0) + 1
end
-- update files count
- files_count = files_count + 1
+ files_count.cl = files_count.cl + 1
-- save first flags
- if first_flags == nil then
- first_flags = flags
+ if first_flags.cl == nil then
+ first_flags.cl = flags
end
end
-- save source flags
targetinfo.sourceflags[sourcefile] = flags
end
+ elseif sourcekind == "cu" then
+ for _, sourcefile in ipairs(sourcebatch.sourcefiles) do
+
+ -- make compiler flags
+ local flags = _make_compflags(sourcefile, targetinfo, target.project_dir)
+
+ -- count flags
+ for _, flag in ipairs(table.unique(flags)) do
+ flags_stats.cuda[flag] = (flags_stats.cuda[flag] or 0) + 1
+ end
+
+ -- update files count
+ files_count.cuda = files_count.cuda + 1
+
+ -- save first flags
+ if first_flags.cuda == nil then
+ first_flags.cuda = flags
+ end
+
+ -- save source flags
+ targetinfo.sourceflags[sourcefile] = flags
+ end
end
end
-- make common flags
- targetinfo.commonflags = {}
- for _, flag in ipairs(first_flags) do
- if flags_stats[flag] >= files_count then
- table.insert(targetinfo.commonflags, flag)
+ targetinfo.commonflags = {cl = {}, cuda = {}}
+ for _, comp in ipairs({"cl", "cuda"}) do
+ for _, flag in ipairs(first_flags[comp]) do
+ if flags_stats[comp][flag] >= files_count[comp] then
+ table.insert(targetinfo.commonflags[comp], flag)
+ end
end
end
-- remove common flags from source flags
local sourceflags = {}
- for sourcefile, flags in pairs(targetinfo.sourceflags) do
- local otherflags = {}
- for _, flag in ipairs(flags) do
- if flags_stats[flag] < files_count then
- table.insert(otherflags, flag)
+ for _, sourcebatch in pairs(targetinfo.sourcebatches) do
+ local sourcekind = sourcebatch.sourcekind
+ if (sourcekind == "cc" or sourcekind == "cxx" or sourcekind == "mrc") then
+ for _, sourcefile in ipairs(sourcebatch.sourcefiles) do
+ local flags = targetinfo.sourceflags[sourcefile]
+ local otherflags = {}
+ for _, flag in ipairs(flags) do
+ if flags_stats.cl[flag] < files_count.cl then
+ table.insert(otherflags, flag)
+ end
+ end
+ sourceflags[sourcefile] = otherflags
+ end
+ elseif sourcekind == "cu" then
+ for _, sourcefile in ipairs(sourcebatch.sourcefiles) do
+ local flags = targetinfo.sourceflags[sourcefile]
+ local otherflags = {}
+ for _, flag in ipairs(flags) do
+ if flags_stats.cuda[flag] < files_count.cuda then
+ table.insert(otherflags, flag)
+ end
+ end
+ sourceflags[sourcefile] = otherflags
end
end
- sourceflags[sourcefile] = otherflags
end
targetinfo.sourceflags = sourceflags
end
@@ -725,7 +1034,12 @@ function _make_source_file_forall(vcxprojfile, vsinfo, target, sourcefile, sourc
end
-- enter it
- local nodename = (sourcekind == "as" and "CustomBuild" or (sourcekind == "mrc" and "ResourceCompile" or "ClCompile"))
+ local nodename
+ if sourcekind == "as" then nodename = "CustomBuild"
+ elseif sourcekind == "mrc" then nodename = "ResourceCompile"
+ elseif sourcekind == "cu" then nodename = "CudaCompile"
+ elseif sourcekind == "cc" or sourcekind == "cxx" then nodename = "ClCompile"
+ end
sourcefile = path.relative(path.absolute(sourcefile), target.project_dir)
vcxprojfile:enter("<%s Include=\"%s\">", nodename, sourcefile)
@@ -749,7 +1063,7 @@ function _make_source_file_forall(vcxprojfile, vsinfo, target, sourcefile, sourc
info.mode, info.arch, objectfile)
end
- -- for *.c/cpp files
+ -- for *.c/cpp/cu files
else
-- we need use different object directory and allow parallel building
@@ -763,9 +1077,10 @@ function _make_source_file_forall(vcxprojfile, vsinfo, target, sourcefile, sourc
targetinfo.objectnames = hashset:new()
end
if targetinfo.objectnames:has(objectname) then
+ local outputnode = (sourcekind == "cu" and "CompileOut" or "ObjectFileName")
local objectfile = path.relative(path.absolute(info.objectfile), target.project_dir)
- vcxprojfile:print("<ObjectFileName Condition=\"\'%$(Configuration)|%$(Platform)\'==\'%s|%s\'\">%s</ObjectFileName>",
- info.mode, info.arch, objectfile)
+ vcxprojfile:print("<%s Condition=\"\'%$(Configuration)|%$(Platform)\'==\'%s|%s\'\">%s</%s>",
+ outputnode, info.mode, info.arch, objectfile, outputnode)
else
targetinfo.objectnames:insert(objectname)
end
@@ -809,7 +1124,7 @@ function _make_source_file_forall(vcxprojfile, vsinfo, target, sourcefile, sourc
-- disable the precompiled header if sourcekind ~= headerkind
local pcheader = target.pcxxheader or target.pcheader
local pcheader_disable = false
- if pcheader and language.sourcekind_of(sourcefile) ~= (target.pcxxheader and "cxx" or "cc") then
+ if sourcekind == "cu" or (pcheader and language.sourcekind_of(sourcefile) ~= (target.pcxxheader and "cxx" or "cc")) then
pcheader_disable = true
end
@@ -858,7 +1173,12 @@ function _make_source_file_forspec(vcxprojfile, vsinfo, target, sourcefile, sour
for _, info in ipairs(sourceinfo) do
-- enter it
- local nodename = (info.sourcekind == "as" and "CustomBuild" or (info.sourcekind == "mrc" and "ResourceCompile" or "ClCompile"))
+ local nodename
+ if info.sourcekind == "as" then nodename = "CustomBuild"
+ elseif info.sourcekind == "mrc" then nodename = "ResourceCompile"
+ elseif info.sourcekind == "cu" then nodename = "CudaCompile"
+ elseif info.sourcekind == "cc" or info.sourcekind == "cxx" then nodename = "ClCompile"
+ end
vcxprojfile:enter("<%s Condition=\"\'%$(Configuration)|%$(Platform)\'==\'%s|%s\'\" Include=\"%s\">",
nodename, info.mode, info.arch, sourcefile)
@@ -872,11 +1192,11 @@ function _make_source_file_forspec(vcxprojfile, vsinfo, target, sourcefile, sour
vcxprojfile:print("<Command>%s</Command>", compcmd)
-- for *.rc files
- elseif sourcekind == "mrc" then
+ elseif info.sourcekind == "mrc" then
vcxprojfile:print("<ResourceOutputFileName Condition=\"\'%$(Configuration)|%$(Platform)\'==\'%s|%s\'\">%s</ResourceOutputFileName>",
info.mode, info.arch, objectfile)
- -- for *.c/cpp files
+ -- for *.c/cpp/cu files
else
-- we need use different object directory and allow parallel building
--
@@ -888,16 +1208,17 @@ function _make_source_file_forspec(vcxprojfile, vsinfo, target, sourcefile, sour
targetinfo.objectnames = hashset:new()
end
local targetinfo = info.targetinfo
+ local outputnode = (info.sourcekind == "cu" and "CompileOut" or "ObjectFileName")
if targetinfo.objectnames:has(objectname) then
- vcxprojfile:print("<ObjectFileName Condition=\"\'%$(Configuration)|%$(Platform)\'==\'%s|%s\'\">%s</ObjectFileName>",
- info.mode, info.arch, objectfile)
+ vcxprojfile:print("<%s Condition=\"\'%$(Configuration)|%$(Platform)\'==\'%s|%s\'\">%s</%s>",
+ outputnode, info.mode, info.arch, objectfile, outputnode)
else
targetinfo.objectnames:insert(objectname)
end
-- disable the precompiled header if sourcekind ~= headerkind
local pcheader = target.pcxxheader or target.pcheader
- if pcheader and language.sourcekind_of(sourcefile) ~= (target.pcxxheader and "cxx" or "cc") then
+ if pcheader and info.sourcekind ~= "cu" and language.sourcekind_of(sourcefile) ~= (target.pcxxheader and "cxx" or "cc") then
vcxprojfile:print("<PrecompiledHeader>NotUsing</PrecompiledHeader>")
end
vcxprojfile:print("<AdditionalOptions>%s %%(AdditionalOptions)</AdditionalOptions>", os.args(info.flags))
@@ -947,7 +1268,7 @@ function _make_source_files(vcxprojfile, vsinfo, target)
for _, targetinfo in ipairs(target.info) do
for _, sourcebatch in pairs(targetinfo.sourcebatches) do
local sourcekind = sourcebatch.sourcekind
- if (sourcekind == "cc" or sourcekind == "cxx" or sourcekind == "as" or sourcekind == "mrc") then
+ if (sourcekind == "cc" or sourcekind == "cxx" or sourcekind == "as" or sourcekind == "mrc" or sourcekind == "cu") then
local objectfiles = sourcebatch.objectfiles
for idx, sourcefile in ipairs(sourcebatch.sourcefiles) do
local objectfile = objectfiles[idx]
@@ -1017,7 +1338,7 @@ function make(vsinfo, target)
_make_source_files(vcxprojfile, vsinfo, target)
-- make tailer
- _make_tailer(vcxprojfile, vsinfo)
+ _make_tailer(vcxprojfile, vsinfo, target)
-- exit solution file
vcxprojfile:close()
diff --git a/xmake/plugins/project/vstudio/impl/vs201x_vcxproj_filters.lua b/xmake/plugins/project/vstudio/impl/vs201x_vcxproj_filters.lua
index 90253940b..fb47926ed 100644
--- a/xmake/plugins/project/vstudio/impl/vs201x_vcxproj_filters.lua
+++ b/xmake/plugins/project/vstudio/impl/vs201x_vcxproj_filters.lua
@@ -95,10 +95,15 @@ function _make_sources(filtersfile, vsinfo, target, vcxprojdir)
for _, sourcefile in ipairs(target.sourcefiles) do
local filter = _make_filter(sourcefile, target, vcxprojdir)
if filter then
- local as = sourcefile:endswith(".asm")
- filtersfile:enter("<%s Include=\"%s\">", (as and "CustomBuild" or "ClCompile"), path.relative(path.absolute(sourcefile), vcxprojdir))
+ local nodename
+ local ext = path.extension(sourcefile)
+ if ext == "asm" then nodename = "CustomBuild"
+ elseif ext == "cu" then nodename = "CudaCompile"
+ else nodename = "ClCompile"
+ end
+ filtersfile:enter("<%s Include=\"%s\">", nodename, path.relative(path.absolute(sourcefile), vcxprojdir))
filtersfile:print("<Filter>%s</Filter>", filter)
- filtersfile:leave("</%s>", (as and "CustomBuild" or "ClCompile"))
+ filtersfile:leave("</%s>", nodename)
end
local pcheader = target.pcxxheader or target.pcheader
if pcheader then
diff --git a/xmake/plugins/project/vstudio/impl/vsutils.lua b/xmake/plugins/project/vstudio/impl/vsutils.lua
new file mode 100644
index 000000000..b4de1717b
--- /dev/null
+++ b/xmake/plugins/project/vstudio/impl/vsutils.lua
@@ -0,0 +1,44 @@
+--!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 xq114
+-- @file vsutils.lua
+--
+
+-- 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
+ , ["\""] = "&quot;"
+ , ["<"] = "&lt;"
+ , [">"] = "&gt;"
+ , ["&"] = "&amp;"
+ }
+
+ return (string.gsub(str, "[%%%$@';%?%*\"<>&]", function (c) return assert(map[c]) end))
+end
diff --git a/xmake/plugins/project/vstudio/vs.lua b/xmake/plugins/project/vstudio/vs.lua
index 4aadbb0b5..8d6b23c18 100644
--- a/xmake/plugins/project/vstudio/vs.lua
+++ b/xmake/plugins/project/vstudio/vs.lua
@@ -22,15 +22,16 @@
import("impl.vs200x")
import("impl.vs201x")
import("impl.vsinfo")
+import("core.tool.toolchain")
import("core.project.config")
-- make factory
function make(version)
if not version then
- version = tonumber(config.get("vs"))
+ version = tonumber(toolchain.load("msvc"):config("vs") or config.get("vs"))
if not version then
- return function(outputdir)
+ return function (outputdir)
raise("invalid vs version, run `xmake f --vs=201x`")
end
end
@@ -39,13 +40,13 @@ function make(version)
-- get vs version info
local info = vsinfo(version)
if version < 2010 then
- return function(outputdir)
+ return function (outputdir)
vprint("using project kind vs%d", version)
vs200x.make(outputdir, info)
end
else
- return function(outputdir)
- utils.warning("please use the new vs project generator, .e.g xmake project -k vsxmake")
+ return function (outputdir)
+ wprint("please use the new vs project generator, .e.g xmake project -k vsxmake")
vprint("using project kind vs%d", version)
vs201x.make(outputdir, info)
end
diff --git a/xmake/plugins/project/vsxmake/getinfo.lua b/xmake/plugins/project/vsxmake/getinfo.lua
index 0cd83a2f1..2441ab982 100644
--- a/xmake/plugins/project/vsxmake/getinfo.lua
+++ b/xmake/plugins/project/vsxmake/getinfo.lua
@@ -467,7 +467,7 @@ function main(outputdir, vsinfo)
for _, target in pairs(targets) do
target._paths = {}
local dirs = {}
- local root = project.directory()
+ local root = target.scriptdir or project.directory()
target.sourcefiles = table.imap(target.sourcefiles, function(_, v) return path.relative(v, root) end)
target.headerfiles = table.imap(target.headerfiles, function(_, v) return path.relative(v, root) end)
for _, f in ipairs(table.join(target.sourcefiles, target.headerfiles)) do