Added support for vcxitems project generation for VS2013+

This commit is contained in:
Sam Surtees 2019-08-09 00:16:11 +10:00
parent b5471154a6
commit 256e176eb1
18 changed files with 503 additions and 34 deletions

View File

@ -21,6 +21,7 @@ return {
"vs2010_rules_xml.lua", "vs2010_rules_xml.lua",
"vs2012.lua", "vs2012.lua",
"vs2013.lua", "vs2013.lua",
"vs2013_vcxitems.lua",
"vs2015.lua", "vs2015.lua",
"vs2017.lua", "vs2017.lua",
"vs2019.lua" "vs2019.lua"

View File

@ -31,6 +31,7 @@ return {
"sln2005/test_projects.lua", "sln2005/test_projects.lua",
"sln2005/test_platforms.lua", "sln2005/test_platforms.lua",
"sln2005/test_sections.lua", "sln2005/test_sections.lua",
"sln2005/test_shared_projects.lua",
-- Visual Studio 2002-2008 C/C++ projects -- Visual Studio 2002-2008 C/C++ projects
"vc200x/test_assembly_refs.lua", "vc200x/test_assembly_refs.lua",
@ -90,4 +91,7 @@ return {
"vc2010/test_user_file.lua", "vc2010/test_user_file.lua",
"vc2010/test_vectorextensions.lua", "vc2010/test_vectorextensions.lua",
"vc2010/test_ensure_nuget_imports.lua", "vc2010/test_ensure_nuget_imports.lua",
-- Visual Studio 2013+ C/C++ Shared Items projects
"vc2013/test_vcxitems.lua",
} }

View File

@ -782,3 +782,23 @@ GlobalSection(SolutionConfigurationPlatforms) = preSolution
EndGlobalSection EndGlobalSection
]] ]]
end end
---
-- Check that when a shared items project is specified that no entries are added
-- to the project configuration platforms
---
function suite.onSharedItemsProject()
p.action.set("vs2013")
project "MyProject"
kind "SharedItems"
prepare()
test.capture [[
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
EndGlobalSection
]]
end

View File

@ -0,0 +1,72 @@
--
-- tests/actions/vstudio/sln2005/test_shared_projects.lua
-- Validate generation of Visual Studio 2005+ SharedMSBuildProjectFiles entries.
-- Copyright (c) Jason Perkins and the Premake project
--
local p = premake
local suite = test.declare("vstudio_sln2005_shared_projects")
local sln2005 = p.vstudio.sln2005
--
-- Setup
--
local wks
function suite.setup()
p.action.set("vs2013")
p.escaper(p.vstudio.vs2005.esc)
wks = workspace("MyWorkspace")
configurations { "Debug", "Release" }
language "C++"
end
local function prepare()
sln2005.reorderProjects(wks)
sln2005.sharedProjects(wks)
end
--
-- Test the shared projects listing
--
function suite.noSharedProjects()
project "MyProject"
kind "ConsoleApp"
prepare()
test.isemptycapture()
end
function suite.onSharedProjects()
project "MyProject"
kind "SharedItems"
prepare()
test.capture [[
GlobalSection(SharedMSBuildProjectFiles) = preSolution
MyProject.vcxitems*{42b5dbc6-ae1f-903d-f75d-41e363076e92}*SharedItemsImports = 9
EndGlobalSection
]]
end
function suite.onLinkedSharedProjects()
project "MyProject"
kind "SharedItems"
project "MyProject2"
kind "ConsoleApp"
links { "MyProject" }
prepare()
test.capture [[
GlobalSection(SharedMSBuildProjectFiles) = preSolution
MyProject.vcxitems*{42b5dbc6-ae1f-903d-f75d-41e363076e92}*SharedItemsImports = 9
MyProject.vcxitems*{b45d52a2-a015-94ef-091d-6d4bf5f32ee0}*SharedItemsImports = 4
EndGlobalSection
]]
end

View File

@ -97,3 +97,20 @@
</ItemGroup> </ItemGroup>
]] ]]
end end
--
-- Shared items projects are referenced differently
--
function suite.sharedItemsProjects()
links { "MyProject" }
project("MyProject")
kind "SharedItems"
prepare()
test.capture [[
<ImportGroup Label="Shared">
<Import Project="MyProject.vcxitems" Label="Shared" />
</ImportGroup>
]]
end

View File

@ -0,0 +1,109 @@
--
-- tests/actions/vstudio/vc2013/test_vcxitems.lua
-- Validate generation of the vcxitems project.
-- Copyright (c) Jason Perkins and the Premake project
--
local p = premake
local suite = test.declare("vstudio_vs2013_vcxitems")
local vc2013 = p.vstudio.vc2013
--
-- Setup
--
local wks, prj
function suite.setup()
p.action.set("vs2013")
wks = test.createWorkspace()
end
local function prepare()
kind "SharedItems"
prj = test.getproject(wks, 1)
end
--
-- Check the structure with the default project values.
--
function suite.structureIsCorrect_onDefaultValues()
prepare()
vc2013.generate(prj)
test.capture [[
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<ItemsProjectGuid>{42B5DBC6-AE1F-903D-F75D-41E363076E92}</ItemsProjectGuid>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ProjectCapability Include="SourceItemsFromImports" />
</ItemGroup>
</Project>
]]
end
--
-- Check the structure with files.
--
function suite.structureIsCorrect_onFiles()
files { "test.h", "test.cpp" }
prepare()
vc2013.generate(prj)
test.capture [[
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<ItemsProjectGuid>{42B5DBC6-AE1F-903D-F75D-41E363076E92}</ItemsProjectGuid>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ProjectCapability Include="SourceItemsFromImports" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(MSBuildThisFileDirectory)test.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="$(MSBuildThisFileDirectory)test.cpp" />
</ItemGroup>
</Project>
]]
end
--
-- If the project name differs from the project filename, output a
-- <ItemsProjectName> element to indicate that.
--
function suite.projectName_OnFilename()
filename "MyProject_2013"
prepare()
vc2013.globals(prj)
test.capture [[
<PropertyGroup Label="Globals">
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<ItemsProjectGuid>{42B5DBC6-AE1F-903D-F75D-41E363076E92}</ItemsProjectGuid>
<ItemsProjectName>MyProject</ItemsProjectName>
</PropertyGroup>
]]
end

View File

@ -101,6 +101,20 @@
end end
--
-- Build a relative path from the solution file to the project file
--
function sln2005.buildRelativePath(prj)
local prjpath = vstudio.projectfile(prj)
prjpath = vstudio.path(prj.workspace, prjpath)
-- Unlike projects, solutions must use old-school %...% DOS style
-- for environment variables.
return prjpath:gsub("$%((.-)%)", "%%%1%%")
end
-- --
-- Write out the list of projects and groups contained by the solution. -- Write out the list of projects and groups contained by the solution.
-- --
@ -110,16 +124,7 @@
tree.traverse(tr, { tree.traverse(tr, {
onleaf = function(n) onleaf = function(n)
local prj = n.project local prj = n.project
p.x('Project("{%s}") = "%s", "%s", "{%s}"', vstudio.tool(prj), prj.name, sln2005.buildRelativePath(prj), prj.uuid)
-- Build a relative path from the solution file to the project file
local prjpath = vstudio.projectfile(prj)
prjpath = vstudio.path(prj.workspace, prjpath)
-- Unlike projects, solutions must use old-school %...% DOS style
-- for environment variables.
prjpath = prjpath:gsub("$%((.-)%)", "%%%1%%")
p.x('Project("{%s}") = "%s", "%s", "{%s}"', vstudio.tool(prj), prj.name, prjpath, prj.uuid)
p.push() p.push()
sln2005.projectdependencies(prj) sln2005.projectdependencies(prj)
p.pop('EndProject') p.pop('EndProject')
@ -149,6 +154,41 @@
end end
--
-- Write out the list of shared project files and their links
--
function sln2005.sharedProjects(wks)
local contents = p.capture(function ()
local tr = p.workspace.grouptree(wks)
p.tree.traverse(tr, {
onleaf = function(n)
local prj = n.project
-- SharedItems projects reference their own UUID with a "9"
-- SharedItems projects reference the UUID of projects that link them with a "4"
if prj.kind == p.SHAREDITEMS then
p.w('%s*{%s}*SharedItemsImports = %s', sln2005.buildRelativePath(prj), prj.uuid:lower(), "9")
else
local deps = p.project.getdependencies(prj, 'linkOnly')
for _, dep in ipairs(deps) do
if dep.kind == p.SHAREDITEMS then
p.w('%s*{%s}*SharedItemsImports = %s', sln2005.buildRelativePath(dep), prj.uuid:lower(), "4")
end
end
end
end,
})
end)
if #contents > 0 then
p.push('GlobalSection(SharedMSBuildProjectFiles) = preSolution')
p.outln(contents)
p.pop('EndGlobalSection')
end
end
-- --
-- Write out the list of project configuration platforms. -- Write out the list of project configuration platforms.
-- --
@ -167,6 +207,12 @@
tree.traverse(tr, { tree.traverse(tr, {
onleaf = function(n) onleaf = function(n)
local prj = n.project local prj = n.project
-- SharedItems projects don't have any configuration platform entries
if prj.kind == p.SHAREDITEMS then
return
end
table.foreachi(sorted, function(cfg) table.foreachi(sorted, function(cfg)
local context = {} local context = {}
-- Look up the matching project configuration. If none exist, this -- Look up the matching project configuration. If none exist, this
@ -351,6 +397,7 @@
sln2005.elements.sections = function(wks) sln2005.elements.sections = function(wks)
return { return {
sln2005.sharedProjects,
sln2005.configurationPlatforms, sln2005.configurationPlatforms,
sln2005.properties, sln2005.properties,
sln2005.nestedProjects, sln2005.nestedProjects,

View File

@ -69,19 +69,31 @@
end end
elseif p.project.isc(prj) or p.project.iscpp(prj) then elseif p.project.isc(prj) or p.project.iscpp(prj) then
local projFileModified = p.generate(prj, ".vcxproj", vstudio.vc2010.generate) if prj.kind == p.SHAREDITEMS then
local projFileModified = p.generate(prj, ".vcxitems", vstudio.vc2013.generate)
-- Skip generation of empty user files -- Only generate a filters file if the source tree actually has subfolders
local user = p.capture(function() vstudio.vc2010.generateUser(prj) end) if tree.hasbranches(project.getsourcetree(prj)) then
if #user > 0 then if p.generate(prj, ".vcxitems.filters", vstudio.vc2010.generateFilters) == true and projFileModified == false then
p.generate(prj, ".vcxproj.user", function() p.outln(user) end) -- vs workaround for issue where if only the .filters file is modified, VS doesn't automaticly trigger a reload
end p.touch(prj, ".vcxitems")
end
end
else
local projFileModified = p.generate(prj, ".vcxproj", vstudio.vc2010.generate)
-- Only generate a filters file if the source tree actually has subfolders -- Skip generation of empty user files
if tree.hasbranches(project.getsourcetree(prj)) then local user = p.capture(function() vstudio.vc2010.generateUser(prj) end)
if p.generate(prj, ".vcxproj.filters", vstudio.vc2010.generateFilters) == true and projFileModified == false then if #user > 0 then
-- vs workaround for issue where if only the .filters file is modified, VS doesn't automaticly trigger a reload p.generate(prj, ".vcxproj.user", function() p.outln(user) end)
p.touch(prj, ".vcxproj") end
-- Only generate a filters file if the source tree actually has subfolders
if tree.hasbranches(project.getsourcetree(prj)) then
if p.generate(prj, ".vcxproj.filters", vstudio.vc2010.generateFilters) == true and projFileModified == false then
-- vs workaround for issue where if only the .filters file is modified, VS doesn't automaticly trigger a reload
p.touch(prj, ".vcxproj")
end
end end
end end
end end

View File

@ -1210,6 +1210,12 @@
end) end)
local rel = path.translate(file.relpath) local rel = path.translate(file.relpath)
-- SharedItems projects paths are prefixed with a magical variable
if prj.kind == p.SHAREDITEMS then
rel = "$(MSBuildThisFileDirectory)" .. rel
end
if #contents > 0 then if #contents > 0 then
p.push('<%s Include="%s">', tag, rel) p.push('<%s Include="%s">', tag, rel)
p.outln(contents) p.outln(contents)
@ -1311,14 +1317,39 @@
function m.projectReferences(prj) function m.projectReferences(prj)
local refs = project.getdependencies(prj, 'linkOnly') local refs = project.getdependencies(prj, 'linkOnly')
if #refs > 0 then -- Handle linked shared items projects
p.push('<ItemGroup>') local contents = p.capture(function()
p.push()
for _, ref in ipairs(refs) do for _, ref in ipairs(refs) do
local relpath = vstudio.path(prj, vstudio.projectfile(ref)) if ref.kind == p.SHAREDITEMS then
p.push('<ProjectReference Include=\"%s\">', relpath) local relpath = vstudio.path(prj, vstudio.projectfile(ref))
p.callArray(m.elements.projectReferences, prj, ref) p.x('<Import Project="%s" Label="Shared" />', relpath)
p.pop('</ProjectReference>') end
end end
p.pop()
end)
if #contents > 0 then
p.push('<ImportGroup Label="Shared">')
p.outln(contents)
p.pop('</ImportGroup>')
end
-- Handle all other linked projects
local contents = p.capture(function()
p.push()
for _, ref in ipairs(refs) do
if ref.kind ~= p.SHAREDITEMS then
local relpath = vstudio.path(prj, vstudio.projectfile(ref))
p.push('<ProjectReference Include=\"%s\">', relpath)
p.callArray(m.elements.projectReferences, prj, ref)
p.pop('</ProjectReference>')
end
end
p.pop()
end)
if #contents > 0 then
p.push('<ItemGroup>')
p.outln(contents)
p.pop('</ItemGroup>') p.pop('</ItemGroup>')
end end
end end

View File

@ -78,12 +78,19 @@
if files and #files > 0 then if files and #files > 0 then
p.push('<ItemGroup>') p.push('<ItemGroup>')
for _, file in ipairs(files) do for _, file in ipairs(files) do
local rel = path.translate(file.relpath)
-- SharedItems projects paths are prefixed with a magical variable
if prj.kind == p.SHAREDITEMS then
rel = "$(MSBuildThisFileDirectory)" .. rel
end
if file.parent.path then if file.parent.path then
p.push('<%s Include=\"%s\">', tag, path.translate(file.relpath)) p.push('<%s Include=\"%s\">', tag, rel)
p.w('<Filter>%s</Filter>', path.translate(file.parent.path, '\\')) p.w('<Filter>%s</Filter>', path.translate(file.parent.path, '\\'))
p.pop('</%s>', tag) p.pop('</%s>', tag)
else else
p.w('<%s Include=\"%s\" />', tag, path.translate(file.relpath)) p.w('<%s Include=\"%s\" />', tag, rel)
end end
end end
p.pop('</ItemGroup>') p.pop('</ItemGroup>')

View File

@ -25,7 +25,7 @@
-- The capabilities of this action -- The capabilities of this action
valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Makefile", "None", "Utility" }, valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Makefile", "None", "Utility", "SharedItems" },
valid_languages = { "C", "C++", "C#", "F#" }, valid_languages = { "C", "C++", "C#", "F#" },
valid_tools = { valid_tools = {
cc = { "msc" }, cc = { "msc" },

View File

@ -0,0 +1,142 @@
--
-- vs2013_vcxitems.lua
-- Generate a Visual Studio 201x C/C++ shared items project.
-- Copyright (c) Jason Perkins and the Premake project
--
local p = premake
p.vstudio.vc2013 = {}
local vstudio = p.vstudio
local project = p.project
local config = p.config
local fileconfig = p.fileconfig
local tree = p.tree
local m = p.vstudio.vc2013
local vc2010 = p.vstudio.vc2010
---
-- Add namespace for element definition lists for p.callArray()
---
m.elements = {}
m.conditionalElements = {}
--
-- Generate a Visual Studio 201x C++ project, with support for the new platforms API.
--
m.elements.project = function(prj)
return {
vc2010.xmlDeclaration,
m.project,
m.globals,
m.itemDefinitionGroup,
m.itemGroup,
vc2010.files,
}
end
function m.generate(prj)
p.utf8()
p.callArray(m.elements.project, prj)
p.out('</Project>')
end
--
-- Output the XML declaration and opening <Project> tag.
--
function m.project(prj)
p.push('<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">')
end
--
-- Write out the Globals property group.
--
m.elements.globals = function(prj)
return {
m.msbuildAllProjects,
m.hasSharedItems,
m.itemsProjectGuid,
m.itemsProjectName,
}
end
function m.globals(prj)
vc2010.propertyGroup(nil, "Globals")
p.callArray(m.elements.globals, prj)
p.pop('</PropertyGroup>')
end
function m.msbuildAllProjects(prj)
vc2010.element("MSBuildAllProjects", nil, "$(MSBuildAllProjects);$(MSBuildThisFileFullPath)")
end
function m.hasSharedItems(prj)
vc2010.element("HasSharedItems", nil, "true")
end
function m.itemsProjectGuid(prj)
vc2010.element("ItemsProjectGuid", nil, "{%s}", prj.uuid)
end
function m.itemsProjectName(prj)
if prj.name ~= prj.filename then
vc2010.element("ItemsProjectName", nil, "%s", prj.name)
end
end
--
-- Write an item definition group, which contains all of the shared compile settings.
--
m.elements.itemDefinitionGroup = function(prj)
return {
m.clCompile,
}
end
function m.itemDefinitionGroup(prj)
p.push('<ItemDefinitionGroup>')
p.callArray(m.elements.itemDefinitionGroup, prj)
p.pop('</ItemDefinitionGroup>')
end
m.elements.clCompile = function(prj)
return {
m.additionalIncludeDirectories,
}
end
function m.clCompile(prj)
p.push('<ClCompile>')
p.callArray(m.elements.clCompile, prj)
p.pop('</ClCompile>')
end
function m.additionalIncludeDirectories(prj)
vc2010.element("AdditionalIncludeDirectories", nil, '%s', '%(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory)')
end
--
-- Write an item group, which contains the project capability
--
m.elements.itemGroup = function(prj)
return {
m.projectCapability,
}
end
function m.itemGroup(prj)
p.push('<ItemGroup>')
p.callArray(m.elements.itemGroup, prj)
p.pop('</ItemGroup>')
end
function m.projectCapability(prj)
p.w('<ProjectCapability Include="SourceItemsFromImports" />')
end

View File

@ -25,7 +25,7 @@
-- The capabilities of this action -- The capabilities of this action
valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Makefile", "None", "Utility" }, valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Makefile", "None", "Utility", "SharedItems" },
valid_languages = { "C", "C++", "C#", "F#" }, valid_languages = { "C", "C++", "C#", "F#" },
valid_tools = { valid_tools = {
cc = { "msc" }, cc = { "msc" },

View File

@ -25,7 +25,7 @@
-- The capabilities of this action -- The capabilities of this action
valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Makefile", "None", "Utility" }, valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Makefile", "None", "Utility", "SharedItems" },
valid_languages = { "C", "C++", "C#", "F#" }, valid_languages = { "C", "C++", "C#", "F#" },
valid_tools = { valid_tools = {
cc = { "msc" }, cc = { "msc" },

View File

@ -25,7 +25,7 @@
-- The capabilities of this action -- The capabilities of this action
valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Makefile", "None", "Utility" }, valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Makefile", "None", "Utility", "SharedItems" },
valid_languages = { "C", "C++", "C#", "F#" }, valid_languages = { "C", "C++", "C#", "F#" },
valid_tools = { valid_tools = {
cc = { "msc" }, cc = { "msc" },

View File

@ -447,7 +447,11 @@
elseif project.isfsharp(prj) then elseif project.isfsharp(prj) then
extension = ".fsproj" extension = ".fsproj"
elseif project.isc(prj) or project.iscpp(prj) then elseif project.isc(prj) or project.iscpp(prj) then
extension = iif(_ACTION > "vs2008", ".vcxproj", ".vcproj") if prj.kind == p.SHAREDITEMS then
extension = ".vcxitems"
else
extension = iif(_ACTION > "vs2008", ".vcxproj", ".vcproj")
end
end end
return p.filename(prj, extension) return p.filename(prj, extension)
@ -644,5 +648,6 @@
include("vs2010_rules_props.lua") include("vs2010_rules_props.lua")
include("vs2010_rules_targets.lua") include("vs2010_rules_targets.lua")
include("vs2010_rules_xml.lua") include("vs2010_rules_xml.lua")
include("vs2013_vcxitems.lua")
return p.modules.vstudio return p.modules.vstudio

View File

@ -701,6 +701,7 @@
"StaticLib", "StaticLib",
"WindowedApp", "WindowedApp",
"Utility", "Utility",
"SharedItems",
}, },
} }

View File

@ -46,6 +46,7 @@
premake.OFF = "Off" premake.OFF = "Off"
premake.POSIX = "posix" premake.POSIX = "posix"
premake.PS3 = "ps3" premake.PS3 = "ps3"
premake.SHAREDITEMS = "SharedItems"
premake.SHAREDLIB = "SharedLib" premake.SHAREDLIB = "SharedLib"
premake.STATICLIB = "StaticLib" premake.STATICLIB = "StaticLib"
premake.UNICODE = "Unicode" premake.UNICODE = "Unicode"