Add custom rules to VC 2010 filters

This commit is contained in:
Jason Perkins 2014-06-12 16:14:42 -04:00
parent d7c7c9373d
commit 07a4ad897d
4 changed files with 209 additions and 178 deletions

View File

@ -703,7 +703,13 @@
function m.categorizeSources(prj) function m.categorizeSources(prj)
local groups = {} local groups = prj._vc2010_sources
if groups then
return groups
end
groups = {}
prj._vc2010_sources = groups
local tr = project.getsourcetree(prj) local tr = project.getsourcetree(prj)
tree.traverse(tr, { tree.traverse(tr, {
@ -726,72 +732,6 @@
function m.getfilegroup(prj, group)
-- Have I already created the groups?
local groups = prj._vc2010_file_groups
if groups then
return groups[group]
end
groups = {
ClCompile = {},
ClInclude = {},
None = {},
ResourceCompile = {},
CustomBuild = {},
CustomRule = {},
}
local tr = project.getsourcetree(prj)
tree.traverse(tr, {
onleaf = function(node)
-- if any configuration of this file uses a custom build rule,
-- then they all must be marked as custom build
local customBuild, customRule
for cfg in project.eachconfig(prj) do
local fcfg = fileconfig.getconfig(node, cfg)
if fileconfig.hasCustomBuildRule(fcfg) then
customBuild = true
break
elseif fcfg and fcfg.customRule then
customRule = fcfg.customRule
break
end
end
if customBuild then
table.insert(groups.CustomBuild, node)
elseif customRule then
groups.CustomRule[customRule] = groups.CustomRule[customRule] or {}
table.insert(groups.CustomRule[customRule], node)
elseif path.iscppfile(node.name) then
table.insert(groups.ClCompile, node)
elseif path.iscppheader(node.name) then
table.insert(groups.ClInclude, node)
elseif path.isresourcefile(node.name) then
table.insert(groups.ResourceCompile, node)
else
table.insert(groups.None, node)
end
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)
return a.relpath < b.relpath
end)
end
prj._vc2010_file_groups = groups
return groups[group]
end
-- --
-- Generate the list of project dependencies. -- Generate the list of project dependencies.
-- --

View File

@ -5,55 +5,76 @@
-- --
local p = premake local p = premake
local vc2010 = p.vstudio.vc2010
local project = p.project local project = p.project
local tree = p.tree local tree = p.tree
local m = p.vstudio.vc2010
-- --
-- Generate a Visual Studio 201x C++ project, with support for the new platforms API. -- Generate a Visual Studio 201x C++ project, with support for the new platforms API.
-- --
function vc2010.generateFilters(prj) function m.generateFilters(prj)
vc2010.xmlDeclaration() m.xmlDeclaration()
vc2010.project() m.project()
m.uniqueIdentifiers(prj)
vc2010.filters_uniqueidentifiers(prj) m.filterGroups(prj)
vc2010.filters_filegroup(prj, "None")
vc2010.filters_filegroup(prj, "ClInclude")
vc2010.filters_filegroup(prj, "ClCompile")
vc2010.filters_filegroup(prj, "ResourceCompile")
vc2010.filters_filegroup(prj, "CustomBuild")
p.out('</Project>') p.out('</Project>')
end end
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)
end
-- --
-- The first portion of the filters file assigns unique IDs to each -- The first portion of the filters file assigns unique IDs to each
-- directory or virtual group. Would be cool if we could automatically -- directory or virtual group. Would be cool if we could automatically
-- map vpaths like "**.h" to an <Extensions>h</Extensions> element. -- map vpaths like "**.h" to an <Extensions>h</Extensions> element.
-- --
function vc2010.filters_uniqueidentifiers(prj) function m.uniqueIdentifiers(prj)
local opened = false
local tr = project.getsourcetree(prj) local tr = project.getsourcetree(prj)
tree.traverse(tr, { local contents = p.capture(function()
onbranch = function(node, depth) p.push()
if not opened then tree.traverse(tr, {
_p(1,'<ItemGroup>') onbranch = function(node, depth)
opened = true p.push('<Filter Include="%s">', path.translate(node.path))
p.w('<UniqueIdentifier>{%s}</UniqueIdentifier>', os.uuid(node.path))
p.pop('</Filter>')
end end
}, false)
p.pop()
end)
_x(2, '<Filter Include="%s">', path.translate(node.path)) if #contents > 0 then
_p(3, '<UniqueIdentifier>{%s}</UniqueIdentifier>', os.uuid(node.path)) p.push('<ItemGroup>')
_p(2, '</Filter>') p.out(contents)
end p.pop('</ItemGroup>')
}, false)
if opened then
_p(1,'</ItemGroup>')
end end
end end
@ -64,20 +85,48 @@
-- "ResourceCompile", or "None". -- "ResourceCompile", or "None".
-- --
function vc2010.filters_filegroup(prj, group) function m.ClCompileFilters(prj, groups)
local files = vc2010.getfilegroup(prj, group) m.filterGroup(prj, groups, "ClCompile")
if #files > 0 then end
_p(1,'<ItemGroup>')
for _, file in ipairs(files) do function m.ClIncludeFilters(prj, groups)
if file.parent.path then m.filterGroup(prj, groups, "ClInclude")
_p(2,'<%s Include=\"%s\">', group, path.translate(file.relpath)) end
_p(3,'<Filter>%s</Filter>', path.translate(file.parent.path))
_p(2,'</%s>', group) function m.CustomBuildFilters(prj, groups)
else m.filterGroup(prj, groups, "CustomBuild")
_p(2,'<%s Include=\"%s\" />', group, path.translate(file.relpath)) end
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
_p(1,'</ItemGroup>') 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
p.push('<ItemGroup>')
for _, file in ipairs(files) do
if file.parent.path then
p.push('<%s Include=\"%s\">', group, path.translate(file.relpath))
p.w('<Filter>%s</Filter>', path.translate(file.parent.path))
p.pop('</%s>', group)
else
p.w('<%s Include=\"%s\" />', group, path.translate(file.relpath))
end
end
p.pop('</ItemGroup>')
end end
end end

View File

@ -20,8 +20,8 @@
end end
local function prepare() local function prepare()
prj = premake.solution.getproject(sln, 1) prj = test.getproject(sln)
vc2010.filters_uniqueidentifiers(prj) vc2010.uniqueIdentifiers(prj)
end end
@ -44,11 +44,11 @@
files { "src/hello.c", "src/goodbye.c", "so_long.h" } files { "src/hello.c", "src/goodbye.c", "so_long.h" }
prepare() prepare()
test.capture [[ test.capture [[
<ItemGroup> <ItemGroup>
<Filter Include="src"> <Filter Include="src">
<UniqueIdentifier>{2DAB880B-99B4-887C-2230-9F7C8E38947C}</UniqueIdentifier> <UniqueIdentifier>{2DAB880B-99B4-887C-2230-9F7C8E38947C}</UniqueIdentifier>
</Filter> </Filter>
</ItemGroup> </ItemGroup>
]] ]]
end end
@ -61,14 +61,14 @@
files { "src/hello.c", "src/departures/goodbye.c", "so_long.h" } files { "src/hello.c", "src/departures/goodbye.c", "so_long.h" }
prepare() prepare()
test.capture [[ test.capture [[
<ItemGroup> <ItemGroup>
<Filter Include="src"> <Filter Include="src">
<UniqueIdentifier>{2DAB880B-99B4-887C-2230-9F7C8E38947C}</UniqueIdentifier> <UniqueIdentifier>{2DAB880B-99B4-887C-2230-9F7C8E38947C}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="src\departures"> <Filter Include="src\departures">
<UniqueIdentifier>{BB36ED8F-A704-E195-9098-51BC7C05BDFA}</UniqueIdentifier> <UniqueIdentifier>{BB36ED8F-A704-E195-9098-51BC7C05BDFA}</UniqueIdentifier>
</Filter> </Filter>
</ItemGroup> </ItemGroup>
]] ]]
end end
@ -82,11 +82,11 @@
vpaths { ["Source Files"] = "**.c" } vpaths { ["Source Files"] = "**.c" }
prepare() prepare()
test.capture [[ test.capture [[
<ItemGroup> <ItemGroup>
<Filter Include="Source Files"> <Filter Include="Source Files">
<UniqueIdentifier>{E9C7FDCE-D52A-8D73-7EB0-C5296AF258F6}</UniqueIdentifier> <UniqueIdentifier>{E9C7FDCE-D52A-8D73-7EB0-C5296AF258F6}</UniqueIdentifier>
</Filter> </Filter>
</ItemGroup> </ItemGroup>
]] ]]
end end
@ -95,13 +95,13 @@
vpaths { ["Source Files"] = "*.c", ["Header Files"] = "*.h" } vpaths { ["Source Files"] = "*.c", ["Header Files"] = "*.h" }
prepare() prepare()
test.capture [[ test.capture [[
<ItemGroup> <ItemGroup>
<Filter Include="Header Files"> <Filter Include="Header Files">
<UniqueIdentifier>{21EB8090-0D4E-1035-B6D3-48EBA215DCB7}</UniqueIdentifier> <UniqueIdentifier>{21EB8090-0D4E-1035-B6D3-48EBA215DCB7}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="Source Files"> <Filter Include="Source Files">
<UniqueIdentifier>{E9C7FDCE-D52A-8D73-7EB0-C5296AF258F6}</UniqueIdentifier> <UniqueIdentifier>{E9C7FDCE-D52A-8D73-7EB0-C5296AF258F6}</UniqueIdentifier>
</Filter> </Filter>
</ItemGroup> </ItemGroup>
]] ]]
end end

View File

@ -20,8 +20,8 @@
end end
local function prepare(group) local function prepare(group)
prj = premake.solution.getproject(sln, 1) prj = test.getproject(sln)
vc2010.filters_filegroup(prj, group) vc2010.filterGroups(prj)
end end
@ -30,32 +30,51 @@
-- --
function suite.itemGroup_onClInclude() function suite.itemGroup_onClInclude()
files { "hello.c", "hello.h", "hello.rc", "hello.txt" } files { "hello.h" }
prepare("ClInclude") prepare()
test.capture [[ test.capture [[
<ItemGroup> <ItemGroup>
<ClInclude Include="hello.h" /> <ClInclude Include="hello.h" />
</ItemGroup> </ItemGroup>
]] ]]
end end
function suite.itemGroup_onResourceSection() function suite.itemGroup_onResourceSection()
files { "hello.c", "hello.h", "hello.rc", "hello.txt" } files { "hello.rc" }
prepare("ResourceCompile") prepare()
test.capture [[ test.capture [[
<ItemGroup> <ItemGroup>
<ResourceCompile Include="hello.rc" /> <ResourceCompile Include="hello.rc" />
</ItemGroup> </ItemGroup>
]] ]]
end end
function suite.itemGroup_onNoneSection() function suite.itemGroup_onNoneSection()
files { "hello.c", "hello.h", "hello.rc", "hello.txt" } files { "hello.txt" }
prepare("None") prepare()
test.capture [[ test.capture [[
<ItemGroup> <ItemGroup>
<None Include="hello.txt" /> <None Include="hello.txt" />
</ItemGroup> </ItemGroup>
]]
end
function suite.itemGroup_onMixed()
files { "hello.c", "hello.h", "hello.rc", "hello.txt" }
prepare()
test.capture [[
<ItemGroup>
<None Include="hello.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="hello.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="hello.c" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="hello.rc" />
</ItemGroup>
]] ]]
end end
@ -65,28 +84,28 @@
-- --
function suite.itemGroup_onBuildRule() function suite.itemGroup_onBuildRule()
files { "hello.c", "hello.h", "hello.rc", "hello.cg" } files { "hello.cg" }
filter "files:**.cg" filter "files:**.cg"
buildcommands { "cgc $(InputFile)" } buildcommands { "cgc $(InputFile)" }
buildoutputs { "$(InputName).obj" } buildoutputs { "$(InputName).obj" }
prepare("CustomBuild") prepare("CustomBuild")
test.capture [[ test.capture [[
<ItemGroup> <ItemGroup>
<CustomBuild Include="hello.cg" /> <CustomBuild Include="hello.cg" />
</ItemGroup> </ItemGroup>
]] ]]
end end
function suite.itemGroup_onSingleConfigBuildRule() function suite.itemGroup_onSingleConfigBuildRule()
files { "hello.c", "hello.h", "hello.rc", "hello.cg" } files { "hello.cg" }
filter { "Release", "files:**.cg" } filter { "Release", "files:**.cg" }
buildcommands { "cgc $(InputFile)" } buildcommands { "cgc $(InputFile)" }
buildoutputs { "$(InputName).obj" } buildoutputs { "$(InputName).obj" }
prepare("CustomBuild") prepare("CustomBuild")
test.capture [[ test.capture [[
<ItemGroup> <ItemGroup>
<CustomBuild Include="hello.cg" /> <CustomBuild Include="hello.cg" />
</ItemGroup> </ItemGroup>
]] ]]
end end
@ -98,12 +117,12 @@
function suite.noFilter_onRootFiles() function suite.noFilter_onRootFiles()
files { "hello.c", "goodbye.c" } files { "hello.c", "goodbye.c" }
prepare("ClCompile") prepare()
test.capture [[ test.capture [[
<ItemGroup> <ItemGroup>
<ClCompile Include="goodbye.c" /> <ClCompile Include="goodbye.c" />
<ClCompile Include="hello.c" /> <ClCompile Include="hello.c" />
</ItemGroup> </ItemGroup>
]] ]]
end end
@ -113,13 +132,16 @@
function suite.filter_onRealPath() function suite.filter_onRealPath()
files { "src/hello.c", "hello.h" } files { "src/hello.c", "hello.h" }
prepare("ClCompile") prepare()
test.capture [[ test.capture [[
<ItemGroup> <ItemGroup>
<ClCompile Include="src\hello.c"> <ClInclude Include="hello.h" />
<Filter>src</Filter> </ItemGroup>
</ClCompile> <ItemGroup>
</ItemGroup> <ClCompile Include="src\hello.c">
<Filter>src</Filter>
</ClCompile>
</ItemGroup>
]] ]]
end end
@ -130,12 +152,32 @@
function suite.filter_onVpath() function suite.filter_onVpath()
files { "src/hello.c", "hello.h" } files { "src/hello.c", "hello.h" }
vpaths { ["Source Files"] = "**.c" } vpaths { ["Source Files"] = "**.c" }
prepare("ClCompile") prepare()
test.capture [[ test.capture [[
<ItemGroup> <ItemGroup>
<ClCompile Include="src\hello.c"> <ClInclude Include="hello.h" />
<Filter>Source Files</Filter> </ItemGroup>
</ClCompile> <ItemGroup>
</ItemGroup> <ClCompile Include="src\hello.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
]]
end
--
-- Check handling of files using custom rules.
--
function suite.filter_onCustomRule()
files { "hello.dae" }
filter "files:**.dae"
customRule "Animation"
prepare()
test.capture [[
<ItemGroup>
<Animation Include="hello.dae" />
</ItemGroup>
]] ]]
end end