From cf1b44018cf61f3af018035e86e173ec7d10049e Mon Sep 17 00:00:00 2001 From: Tom van Dijck Date: Tue, 5 Apr 2016 09:12:33 -0700 Subject: [PATCH 1/2] refactor file categorization in vcxproj backend. and add Masm support. --- src/actions/vstudio/vs2010_vcxproj.lua | 492 +++++++++++------- .../vstudio/vs2010_vcxproj_filters.lua | 69 +-- tests/actions/vstudio/vc2010/test_filters.lua | 6 +- 3 files changed, 305 insertions(+), 262 deletions(-) diff --git a/src/actions/vstudio/vs2010_vcxproj.lua b/src/actions/vstudio/vs2010_vcxproj.lua index 4f4e8c8f..52466300 100644 --- a/src/actions/vstudio/vs2010_vcxproj.lua +++ b/src/actions/vstudio/vs2010_vcxproj.lua @@ -577,219 +577,244 @@ -- Write out the list of source code files, and any associated configuration. --- - m.elements.files = function(prj, groups) - return { - m.clIncludeFiles, - m.clCompileFiles, - m.noneFiles, - m.resourceCompileFiles, - m.customBuildFiles, - m.customRuleFiles, - m.midlFiles - } - end - - function m.files(prj) local groups = m.categorizeSources(prj) - p.callArray(m.elements.files, prj, groups) + for _, group in ipairs(groups) do + group.category.emitFiles(prj, group) + end end - m.elements.ClCompileFile = function(cfg, file) - return {} - end + m.categories = {} + +--- +-- ClInclude group +--- + m.categories.ClInclude = { + name = "ClInclude", + extensions = { ".h", ".hh", ".hpp", ".hxx" }, + priority = 1, + + emitFiles = function(prj, group) + m.emitFiles(prj, group, "ClInclude") + end, + + emitFilter = function(prj, group) + m.filterGroup(prj, group, "ClInclude") + end + } - m.elements.ClCompileFileCfg = function(fcfg, condition) - if fcfg then - return { - m.excludedFromBuild, - m.objectFileName, - m.clCompilePreprocessorDefinitions, - m.clCompileUndefinePreprocessorDefinitions, - m.optimization, - m.forceIncludes, - m.precompiledHeader, - m.enableEnhancedInstructionSet, - m.additionalCompileOptions, - m.disableSpecificWarnings, - m.treatSpecificWarningsAsErrors - } - else - return { +--- +-- ClCompile group +--- + m.categories.ClCompile = { + name = "ClCompile", + extensions = { ".cc", ".cpp", ".cxx", ".c", ".s", ".m", ".mm" }, + priority = 2, + + emitFiles = function(prj, group) + local fileCfgFunc = function(fcfg, condition) + if fcfg then + return { + m.excludedFromBuild, + m.objectFileName, + m.clCompilePreprocessorDefinitions, + m.clCompileUndefinePreprocessorDefinitions, + m.optimization, + m.forceIncludes, + m.precompiledHeader, + m.enableEnhancedInstructionSet, + m.additionalCompileOptions, + m.disableSpecificWarnings, + m.treatSpecificWarningsAsErrors + } + else + return { + m.excludedFromBuild + } + end + end + + m.emitFiles(prj, group, "ClCompile", nil, fileCfgFunc) + end, + + emitFilter = function(prj, group) + m.filterGroup(prj, group, "ClCompile") + end + } + + +--- +-- None group +--- + m.categories.None = { + name = "None", + priority = 3, + + emitFiles = function(prj, group) + m.emitFiles(prj, group, "None") + end, + + emitFilter = function(prj, group) + m.filterGroup(prj, group, "None") + end + } + + +--- +-- ResourceCompile group +--- + m.categories.ResourceCompile = { + name = "ResourceCompile", + extensions = ".rc", + priority = 4, + + emitFiles = function(prj, group) + local fileCfgFunc = { m.excludedFromBuild } + + m.emitFiles(prj, group, "ResourceCompile", nil, fileCfgFunc, function(cfg) + return cfg.system == p.WINDOWS + end) + end, + + emitFilter = function(prj, group) + m.filterGroup(prj, group, "ResourceCompile") end - end + } - function m.clCompileFiles(prj, groups) - m.emitFiles(prj, groups, "ClCompile") - end +--- +-- CustomBuild group +--- + m.categories.CustomBuild = { + name = "CustomBuild", + priority = 5, + emitFiles = function(prj, group) + local fileFunc = { + m.fileType + } - m.elements.ClIncludeFile = function(cfg, file) - return {} - end + local fileCfgFunc = { + m.excludedFromBuild, + m.buildCommands, + m.buildOutputs, + m.buildMessage, + m.buildAdditionalInputs + } + m.emitFiles(prj, group, "CustomBuild", fileFunc, fileCfgFunc, function (cfg, fcfg) + return fileconfig.hasCustomBuildRule(fcfg) + end) + end, - m.elements.ClIncludeFileCfg = function(fcfg, condition) - return {} - end - - - function m.clIncludeFiles(prj, groups) - m.emitFiles(prj, groups, "ClInclude") - end - - - m.elements.CustomBuildFile = function(cfg, file) - return { - m.fileType - } - end - - m.elements.CustomBuildFileCfg = function(fcfg, condition) - return { - m.excludedFromBuild, - m.buildCommands, - m.buildOutputs, - m.buildMessage, - m.buildAdditionalInputs - } - end - - function m.customBuildFiles(prj, groups) - m.emitFiles(prj, groups, "CustomBuild", function (cfg, fcfg) - return fileconfig.hasCustomBuildRule(fcfg) - end) - end - - - - function m.customRuleFiles(prj, groups) - for i = 1, #prj.rules do - local rule = p.global.getRule(prj.rules[i]) - local files = groups[rule.name] - if files and #files > 0 then - p.push('') - - for _, file in ipairs(files) do - local contents = p.capture(function() - p.push() - for prop in p.rule.eachProperty(rule) do - local fld = p.rule.getPropertyField(rule, prop) - - for cfg in project.eachconfig(prj) do - local fcfg = fileconfig.getconfig(file, cfg) - if fcfg and fcfg[fld.name] then - local value = p.rule.getPropertyString(rule, prop, fcfg[fld.name]) - if value and #value > 0 then - m.element(prop.name, m.condition(cfg), '%s', value) - end - end - end - - end - p.pop() - end) - - if #contents > 0 then - p.push('<%s Include=\"%s\">', rule.name, path.translate(file.relpath)) - p.outln(contents) - p.pop('', rule.name) - else - p.x('<%s Include=\"%s\" />', rule.name, path.translate(file.relpath)) - end - end - - p.pop('') - end + emitFilter = function(prj, group) + m.filterGroup(prj, group, "CustomBuild") end - end + } +--- +-- Midl group +--- + m.categories.Midl = { + name = "Midl", + extensions = ".idl", + priority = 6, - m.elements.NoneFile = function(cfg, file) - return {} - end - - - m.elements.NoneFileCfg = function(fcfg, condition) - return {} - end - - - function m.noneFiles(prj, groups) - m.emitFiles(prj, groups, "None") - end - - - m.elements.ResourceCompileFile = function(cfg, file) - return {} - end - - m.elements.ResourceCompileFileCfg = function(fcfg, condition) - return { - m.excludedFromBuild - } - end - - - function m.resourceCompileFiles(prj, groups) - m.emitFiles(prj, groups, "ResourceCompile", function(cfg) - return cfg.system == p.WINDOWS - end) - end - - - - m.elements.MidlFile = function(cfg, file) - return {} - end - - - m.elements.MidlFileCfg = function(fcfg, condition) - return { - m.excludedFromBuild - } - end - - function m.midlFiles(prj, groups) - m.emitFiles(prj, groups, "Midl", function(cfg) - return cfg.system == p.WINDOWS - end) - end - + emitFiles = function(prj, group) + local fileCfgFunc = { + m.excludedFromBuild + } + + m.emitFiles(prj, group, "Midl", nil, fileCfgFunc, function(cfg) + return cfg.system == p.WINDOWS + end) + end, + + emitFilter = function(prj, group) + m.filterGroup(prj, group, "Midl") + end + } + +--- +-- Masm group +--- + m.categories.Masm = { + name = "Masm", + extensions = ".asm", + priority = 7, + + emitFiles = function(prj, group) + local fileCfgFunc = { + m.excludedFromBuild + } + + m.emitFiles(prj, group, "Masm", nil, fileCfgFunc, function(cfg) + return cfg.system == p.WINDOWS + end) + end, + + emitFilter = function(prj, group) + m.filterGroup(prj, group, "Masm") + end, + + emitExtensionSettings = function(prj, group) + p.w('') + end, + + emitExtensionTargets = function(prj, group) + p.w('') + end + } +--- +-- Categorize files into groups. +--- function m.categorizeSources(prj) - local groups = prj._vc2010_sources - if groups then - return groups + -- if we already did this, return the cached result. + if prj._vc2010_sources then + return prj._vc2010_sources end - groups = {} - prj._vc2010_sources = groups + -- build the new group table. + local result = {} + local groups = {} + prj._vc2010_sources = result local tr = project.getsourcetree(prj) tree.traverse(tr, { onleaf = function(node) local cat = m.categorizeFile(prj, node) - groups[cat] = groups[cat] or {} - table.insert(groups[cat], node) + groups[cat.name] = groups[cat.name] or { + category = cat, + files = {} + } + table.insert(groups[cat.name].files, node) end }) -- sort by relative-to path; otherwise VS will reorder the files - for group, files in pairs(groups) do - table.sort(files, function (a, b) + for name, group in pairs(groups) do + table.sort(group.files, function (a, b) return a.relpath < b.relpath end) + table.insert(result, group) end - return groups + -- sort by category priority then name; so we get stable results. + table.sort(result, function (a, b) + if (a.category.priority == b.category.priority) then + return a.category.name < b.category.name + end + return a.category.priority < b.category.priority + end) + + return result end @@ -799,44 +824,50 @@ for cfg in project.eachconfig(prj) do local fcfg = fileconfig.getconfig(file, cfg) if fileconfig.hasCustomBuildRule(fcfg) then - return "CustomBuild" + return m.categories.CustomBuild end end -- If there is a custom rule associated with it, use that local rule = p.global.getRuleForFile(file.name, prj.rules) if rule then - return rule.name + return { + name = rule.name, + priority = 100, + rule = rule, + emitFiles = function(prj, group) + m.emitRuleFiles(prj, group) + end, + emitFilter = function(prj, group) + m.filterGroup(prj, group, group.category.name) + end + } end -- Otherwise use the file extension to deduce a category - if path.iscppfile(file.name) then - return "ClCompile" - elseif path.iscppheader(file.name) then - return "ClInclude" - elseif path.isresourcefile(file.name) then - return "ResourceCompile" - elseif path.isidlfile(file.name) then - return "Midl" - else - return "None" + for _, cat in pairs(m.categories) do + if cat.extensions and path.hasextension(file.name, cat.extensions) then + return cat + end end + + return m.categories.None end - function m.emitFiles(prj, groups, group, check) - local files = groups[group] + function m.emitFiles(prj, group, tag, fileFunc, fileCfgFunc, checkFunc) + local files = group.files if files and #files > 0 then p.push('') for _, file in ipairs(files) do local contents = p.capture(function () p.push() - p.callArray(m.elements[group .. "File"], cfg, file) + p.callArray(fileFunc, cfg, file) for cfg in project.eachconfig(prj) do local fcfg = fileconfig.getconfig(file, cfg) - if not check or check(cfg, fcfg) then - p.callArray(m.elements[group .. "FileCfg"], fcfg, m.condition(cfg)) + if not checkFunc or checkFunc(cfg, fcfg) then + p.callArray(fileCfgFunc, fcfg, m.condition(cfg)) end end p.pop() @@ -844,11 +875,11 @@ local rel = path.translate(file.relpath) if #contents > 0 then - p.push('<%s Include="%s">', group, rel) + p.push('<%s Include="%s">', tag, rel) p.outln(contents) - p.pop('', group) + p.pop('', tag) else - p.x('<%s Include="%s" />', group, rel) + p.x('<%s Include="%s" />', tag, rel) end end @@ -856,6 +887,46 @@ end end + function m.emitRuleFiles(prj, group) + local files = group.files + local rule = group.category.rule + + if files and #files > 0 then + p.push('') + + for _, file in ipairs(files) do + local contents = p.capture(function() + p.push() + for prop in p.rule.eachProperty(rule) do + local fld = p.rule.getPropertyField(rule, prop) + + for cfg in project.eachconfig(prj) do + local fcfg = fileconfig.getconfig(file, cfg) + if fcfg and fcfg[fld.name] then + local value = p.rule.getPropertyString(rule, prop, fcfg[fld.name]) + if value and #value > 0 then + m.element(prop.name, m.condition(cfg), '%s', value) + end + end + end + + end + p.pop() + end) + + if #contents > 0 then + p.push('<%s Include=\"%s\">', rule.name, path.translate(file.relpath)) + p.outln(contents) + p.pop('', rule.name) + else + p.x('<%s Include=\"%s\" />', rule.name, path.translate(file.relpath)) + end + end + + p.pop('') + end + end + -- @@ -1312,6 +1383,7 @@ m.elements.importExtensionTargets = function(prj) return { + m.importGroupTargets, m.importRuleTargets, m.importBuildCustomizationsTargets } @@ -1323,6 +1395,15 @@ p.pop('') end + function m.importGroupTargets(prj) + local groups = m.categorizeSources(prj) + for _, group in ipairs(groups) do + if group.category.emitExtensionTargets then + group.category.emitExtensionTargets(prj, group) + end + end + end + function m.importRuleTargets(prj) for i = 1, #prj.rules do local rule = p.global.getRule(prj.rules[i]) @@ -1333,8 +1414,8 @@ function m.importBuildCustomizationsTargets(prj) for i, build in ipairs(prj.buildcustomizations) do - premake.w('', path.translate(build)) - end + p.w('', path.translate(build)) + end end @@ -1351,6 +1432,7 @@ m.elements.importExtensionSettings = function(prj) return { + m.importGroupSettings, m.importRuleSettings, m.importBuildCustomizationsProps } @@ -1362,6 +1444,17 @@ p.pop('') end + + function m.importGroupSettings(prj) + local groups = m.categorizeSources(prj) + for _, group in ipairs(groups) do + if group.category.emitExtensionSettings then + group.category.emitExtensionSettings(prj, group) + end + end + end + + function m.importRuleSettings(prj) for i = 1, #prj.rules do local rule = p.global.getRule(prj.rules[i]) @@ -1370,10 +1463,11 @@ end end + function m.importBuildCustomizationsProps(prj) for i, build in ipairs(prj.buildcustomizations) do - premake.w('', path.translate(build)) - end + p.w('', path.translate(build)) + end end diff --git a/src/actions/vstudio/vs2010_vcxproj_filters.lua b/src/actions/vstudio/vs2010_vcxproj_filters.lua index 50deb628..752755d8 100644 --- a/src/actions/vstudio/vs2010_vcxproj_filters.lua +++ b/src/actions/vstudio/vs2010_vcxproj_filters.lua @@ -36,28 +36,11 @@ - m.elements.filterGroups = { - "None", - "ClInclude", - "ClCompile", - "ResourceCompile", - "CustomBuild", - "CustomRule" - } - - m.elements.filters = function(prj, groups) - local calls = {} - for i, group in ipairs(m.elements.filterGroups) do - calls[i] = m[group .. "Filters"] - end - return calls - end - function m.filterGroups(prj) - -- Categorize the source files in groups by build rule; each will - -- be written to a separate item group by one of the handlers local groups = m.categorizeSources(prj) - p.callArray(m.elements.filters, prj, groups) + for _, group in ipairs(groups) do + group.category.emitFilter(prj, group) + end end @@ -90,51 +73,17 @@ end --- --- The second portion of the filters file assigns filters to each source --- code file, as needed. Group is one of "ClCompile", "ClInclude", --- "ResourceCompile", or "None". --- - - function m.ClCompileFilters(prj, groups) - m.filterGroup(prj, groups, "ClCompile") - end - - function m.ClIncludeFilters(prj, groups) - m.filterGroup(prj, groups, "ClInclude") - end - - function m.CustomBuildFilters(prj, groups) - m.filterGroup(prj, groups, "CustomBuild") - end - - function m.CustomRuleFilters(prj, groups) - for group, files in pairs(groups) do - if not table.contains(m.elements.filterGroups, group) then - m.filterGroup(prj, groups, group) - end - end - end - - function m.NoneFilters(prj, groups) - m.filterGroup(prj, groups, "None") - end - - function m.ResourceCompileFilters(prj, groups) - m.filterGroup(prj, groups, "ResourceCompile") - end - - function m.filterGroup(prj, groups, group) - local files = groups[group] or {} - if #files > 0 then + function m.filterGroup(prj, group, tag) + local files = group.files + if files and #files > 0 then p.push('') for _, file in ipairs(files) do if file.parent.path then - p.push('<%s Include=\"%s\">', group, path.translate(file.relpath)) + p.push('<%s Include=\"%s\">', tag, path.translate(file.relpath)) p.w('%s', path.translate(file.parent.path)) - p.pop('', group) + p.pop('', tag) else - p.w('<%s Include=\"%s\" />', group, path.translate(file.relpath)) + p.w('<%s Include=\"%s\" />', tag, path.translate(file.relpath)) end end p.pop('') diff --git a/tests/actions/vstudio/vc2010/test_filters.lua b/tests/actions/vstudio/vc2010/test_filters.lua index 58668db2..fd23c119 100644 --- a/tests/actions/vstudio/vc2010/test_filters.lua +++ b/tests/actions/vstudio/vc2010/test_filters.lua @@ -63,15 +63,15 @@ files { "hello.c", "hello.h", "hello.rc", "hello.txt" } prepare() test.capture [[ - - - + + + From da89636575d98ebfdd1056472b2d795ab7bc528a Mon Sep 17 00:00:00 2001 From: Tom van Dijck Date: Thu, 7 Apr 2016 12:48:09 -0700 Subject: [PATCH 2/2] Test for .asm file support in visual studio action. --- .../vstudio/vc2010/test_extension_settings.lua | 15 +++++++++++++++ .../vstudio/vc2010/test_extension_targets.lua | 16 ++++++++++++++++ tests/actions/vstudio/vc2010/test_filters.lua | 14 ++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/tests/actions/vstudio/vc2010/test_extension_settings.lua b/tests/actions/vstudio/vc2010/test_extension_settings.lua index e1a2bd64..01059b3c 100644 --- a/tests/actions/vstudio/vc2010/test_extension_settings.lua +++ b/tests/actions/vstudio/vc2010/test_extension_settings.lua @@ -72,3 +72,18 @@ ]] end + +-- +-- the asm 'file category' should add the right settings. +-- + + function suite.hasAssemblyFiles() + files { "test.asm" } + location "build" + prepare() + test.capture [[ + + + + ]] + end diff --git a/tests/actions/vstudio/vc2010/test_extension_targets.lua b/tests/actions/vstudio/vc2010/test_extension_targets.lua index 355c8fff..40d1720a 100644 --- a/tests/actions/vstudio/vc2010/test_extension_targets.lua +++ b/tests/actions/vstudio/vc2010/test_extension_targets.lua @@ -72,3 +72,19 @@ ]] end + + +-- +-- the asm 'file category' should add the right target. +-- + + function suite.hasAssemblyFiles() + files { "test.asm" } + location "build" + prepare() + test.capture [[ + + + + ]] + end diff --git a/tests/actions/vstudio/vc2010/test_filters.lua b/tests/actions/vstudio/vc2010/test_filters.lua index fd23c119..9c69b62b 100644 --- a/tests/actions/vstudio/vc2010/test_filters.lua +++ b/tests/actions/vstudio/vc2010/test_filters.lua @@ -184,3 +184,17 @@ ]] end + + +-- +-- Check handling of .asm files +-- + function suite.itemGroup_onNoneSection() + files { "hello.asm" } + prepare() + test.capture [[ + + + + ]] + end