diff options
| author | ruki <[email protected]> | 2022-02-26 22:42:51 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-02-26 22:42:51 +0800 |
| commit | 534e8608d5867ef766cf6b2836ccbe2b72fbdfee (patch) | |
| tree | 97aaf33757319366ea13925c01a23d850a583dd2 | |
| parent | f527dbaf01ee10efb14cf0b12aca00b25debc011 (diff) | |
| parent | f8a510b9e8b24283b3fbe3edc839cc3edac9bb65 (diff) | |
Merge pull request #2093 from xq114/dev
support cuda for vs generator
| -rw-r--r-- | xmake/plugins/project/cmake/cmakelists.lua | 3 | ||||
| -rw-r--r-- | xmake/plugins/project/vstudio/impl/vs201x.lua | 46 | ||||
| -rw-r--r-- | xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua | 427 | ||||
| -rw-r--r-- | xmake/plugins/project/vstudio/impl/vs201x_vcxproj_filters.lua | 11 | ||||
| -rw-r--r-- | xmake/plugins/project/vstudio/impl/vsutils.lua | 44 | ||||
| -rw-r--r-- | xmake/plugins/project/vstudio/vs.lua | 11 | ||||
| -rw-r--r-- | xmake/plugins/project/vsxmake/getinfo.lua | 2 |
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 - , ["\""] = """ - , ["<"] = "<" - , [">"] = ">" - , ["&"] = "&" - } - - 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 + , ["\""] = """ + , ["<"] = "<" + , [">"] = ">" + , ["&"] = "&" + } + + 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 |
