I've created a workaround for this problem. This only works on VS2010, and not on previous versions, since it requires MSBuild 4.
First, create a file named Configure.xslt
with the following contents.
<?xml version="1.0" encoding="utf-8"?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msbuild="http://schemas.microsoft.com/developer/msbuild/2003">
<xsl:output version="1.0" encoding="UTF-8" indent="yes" />
<xsl:template match="/msbuild:Project">
<xsl:copy>
<xsl:copy-of select="@*" />
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:copy-of select="." />
</xsl:template>
<xsl:template match="msbuild:ItemGroup[@Label = 'ProjectConfigurations']">
<xsl:copy-of select="document('Default.props')/msbuild:Project/msbuild:ItemGroup[@Label = 'ProjectConfigurations']" />
</xsl:template>
</xsl:transform>
Now, create a file named Default.props
with the following contents.
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" InitialTargets="Configure" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- This must come first, or else VS IDE's property sheets will choke. -->
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<!-- The following configurations will be pasted into the importing project file on demand. -->
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<!-- XLST task which manipulates the project file and performs an in-place replacement. -->
<Target Name="Configure" Condition="Exists('$(MSBuildThisFileDirectory)Configure.xslt')" Inputs="$(MSBuildProjectFile);$(MSBuildThisFileFullPath);$(MSBuildThisFileDirectory)Configure.xslt" Outputs="$(MSBuildProjectFile);$(OutDir)">
<Message Text="Configuring $(MSBuildProjectFile)..." />
<XslTransformation XslInputPath="$(MSBuildThisFileDirectory)Configure.xslt" XmlInputPaths="$(MSBuildProjectFile)" OutputPaths="$(MSBuildProjectFile).tmp" />
<Move SourceFiles="$(MSBuildProjectFile).tmp" DestinationFiles="$(MSBuildProjectFile)" />
<MakeDir Directories="$(OutDir)" />
</Target>
<!-- The remaining MSBuild imports. -->
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
This file is your separate "property sheet" containing all of the common properties for your projects, including configurations. Customize it to your needs. The important parts are the <Target>
node (which creates a new target named Configure
) and the InitialTargets
attribute in the <Project>
node (which tells MSBuild to execute the Configure
target initially).
After that, move both Configure.xslt
and Default.props
to a directory of your choice.
Finally, use the following template in all your projects.
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Change the directory below according to the path containing the above files. -->
<Import Project="Directory\Default.props" />
<!-- The ItemGroup below will be effectively replaced by the same ItemGroup inside Default.props. -->
<ItemGroup Label="ProjectConfigurations" />
</Project>
From the VS prompt, run an initial msbuild
to populate your file with configurations, or else VS IDE won't open your project (because of the same bug which motivated this workaround in the first place). Alternatively, your template might contain any dummy configuration, just to enable the IDE to initially open the project -- the effect is the same.
Known caveats: You can't create per-project configurations using the IDE (because the IDE will forcibly group any configurations found under the ProjectConfigurations
label). You can create them directly in the project file's XML data, and, as soon as you don't label them ProjectConfigurations
, they won't be replaced or deleted.