diff options
| author | xq114 <[email protected]> | 2022-02-25 19:46:38 +0800 |
|---|---|---|
| committer | xq114 <[email protected]> | 2022-02-25 19:46:38 +0800 |
| commit | 4d36d93be6ab1e4750676645cbd1632ce3ccfccd (patch) | |
| tree | 83773ea3f1a694ed4a315695846854f744f182f8 | |
| parent | d1628f8c57ecc60823a5d0b59bf070cddc794443 (diff) | |
finish cuda support for vs generator
| -rw-r--r-- | xmake/plugins/project/vstudio/impl/vs201x.lua | 14 | ||||
| -rw-r--r-- | xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua | 321 |
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] |
