summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxq114 <[email protected]>2022-02-25 19:46:38 +0800
committerxq114 <[email protected]>2022-02-25 19:46:38 +0800
commit4d36d93be6ab1e4750676645cbd1632ce3ccfccd (patch)
tree83773ea3f1a694ed4a315695846854f744f182f8
parentd1628f8c57ecc60823a5d0b59bf070cddc794443 (diff)
finish cuda support for vs generator
-rw-r--r--xmake/plugins/project/vstudio/impl/vs201x.lua14
-rw-r--r--xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua321
2 files changed, 291 insertions, 44 deletions
diff --git a/xmake/plugins/project/vstudio/impl/vs201x.lua b/xmake/plugins/project/vstudio/impl/vs201x.lua
index b7186dab5..4983387ae 100644
--- a/xmake/plugins/project/vstudio/impl/vs201x.lua
+++ b/xmake/plugins/project/vstudio/impl/vs201x.lua
@@ -274,6 +274,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 +292,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 +305,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 c813a07cf..5f4b6edfe 100644
--- a/xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua
+++ b/xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua
@@ -43,11 +43,13 @@ end
-- check for CUDA
function _check_cuda(target)
- local sourcekinds = target:sourcekinds()
- if table.contains(sourcekinds, "cu") then
- return
+ local cuda
+ for _, targetinfo in ipairs(target.info) do
+ if table.contains(targetinfo.sourcekinds, "cu") then
+ cuda = find_cuda()
+ break
+ end
end
- local cuda = find_cuda()
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
@@ -87,6 +89,46 @@ 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, flag)
+ end
+ end
+ return newflags
+end
+
-- make compiling command
function _make_compcmd(compargv, sourcefile, objectfile, vcxprojdir)
local argv = {}
@@ -273,7 +315,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
@@ -292,8 +334,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 ""
@@ -427,24 +469,162 @@ 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("[%-/]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 .. 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, 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
+ if flagstr:find("%-gencode[ =]arch=(.+),code=(.+)") or flagstr:find("%-arch") or flagstr:find("%-code") then
+ local arch, code
+ local gencodes = {}
+ for _, flag in ipairs(flags) do
+ flag:gsub("%-gencode[ =]arch=(.+),code=(.+)$", function (garch, gcode)
+ table.insert(gencodes, garch:gsub("\"", "") .. "," .. gcode:gsub("\"", ""))
+ end)
+ flag:gsub("^%-arch[ =](.+)", function (garch) arch = garch:gsub("\"", "") end)
+ flag:gsub("^%-code[ =](.+)", function (gcode) code = gcode:gsub("\"", "") end)
+ end
+ if arch then
+ if not code then
+ code = arch:gsub("sm", "compute")
end
+ table.insert(gencodes, arch .. "," .. code)
end
- if not excluded then
- table.insert(additional_flags, flag)
+ if #gencodes > 0 then
+ 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", "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
@@ -591,7 +771,7 @@ function _make_common_item(vcxprojfile, vsinfo, target, targetinfo)
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 = {
@@ -654,13 +834,26 @@ function _make_common_item(vcxprojfile, vsinfo, target, targetinfo)
vcxprojfile:leave("</ClCompile>")
- -- for CUDA compiler?
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>")
- -- architecture
- vcxprojfile:print("<TargetMachinePlatform>%s</TargetMachinePlatform>", targetinfo.mode:endswith("64") and "64" or "32")
+ -- make source options
+ _make_source_options_cuda(vcxprojfile, targetinfo.commonflags.cuda)
vcxprojfile:leave("</CudaCompile>")
end
@@ -679,9 +872,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
@@ -693,43 +886,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
@@ -804,9 +1038,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
@@ -850,7 +1085,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
@@ -936,8 +1171,8 @@ function _make_source_file_forspec(vcxprojfile, vsinfo, target, sourcefile, sour
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
@@ -994,7 +1229,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]