MSBuild reexpand property - visual-studio

I use some custom props file like this (my_super_props.props)
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<TargetOsName>linux</TargetOsName>
<RemoteGeneratedFilesDir>$(RemoteIntDir)generated_files/</RemoteGeneratedFilesDir>
</PropertyGroup>
<ItemGroup />
</Project>
VS generates vcxproj file for me like this (piece)
.....
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="Shared" />
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='debug|x86'">
<Import Project="my_super_props.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='debug|x86'">
<RemoteIntDir>$(RemoteProjectDir)/obj/$(PlatformTarget)/$(TargetOsName)/$(Configuration)/</RemoteIntDir>
</PropertyGroup>
.....
Inside Microsoft.Cpp.props - $(RemoteIntDir) already defined like this
<RemoteIntDir Condition="'$(RemoteIntDir)' == ''">$(RemoteProjectDir)/obj/$(Platform)/$(Configuration)/</RemoteIntDir>
So Inside my Targets i'ev got wrong value of $(RemoteGeneratedFilesDir)
for exmaple
my_proj/obj/x86/debug/generated_files
instead of
my_proj/obj/x86/linux/debug/generated_files
because properties expands at declaration time,
but i can't declare $(RemoteIntDir) earlier, cos it depends of $(TargetOsName)
So I must somehow reexpand $(RemoteGeneratedFilesDir) before targets start - but i don't know how ??
PS
$(RemoteIntDir) - filled with Visual Studio project configuraion UI Dialog, so i even can't change order of properties declaration/props imports and etc

Your requirements are in a mess and there are no default properties RemoteProjectDir,RemoteGeneratedFilesDir,RemoteIntDir on system Microsoft.Cpp.props file. So it is quite strange due to your description.
I have added
<RemoteIntDir Condition="'$(RemoteIntDir)' == ''">$(RemoteProjectDir)/obj/$(Platform)/$(Configuration)/</RemoteIntDir>
.....
into my Microsoft.Cpp.props file to keep the same MSBuild environment as yours.
I have two questions.
my_proj/obj/x86/linux/debug/generated_files, is your current build configuration is linux? And why did you have two similar configuration linux and debug under it?
Also, is it my_proj/obj/x86/linux/generated_files?
In this situation, I have trusted your description, and assume it is my_proj/obj/x86/linux/debug/generated_files.
Besides, the changed $(Configuration) will act on the whole msbuild files including Microsoft.Cpp.props system files and vcxproj file.
One
If your current build configuration is debug and Platform is x86, you should try to change your my_super_props.props file like this:
<RemoteGeneratedFilesDir>$(RemoteProjectDir)/obj/$(Platform)/$(TargetOsName)/$(Configuration)/generated_files/</RemoteGeneratedFilesDir>
Two
If your build configuration is linux(to create it, you have to enter Build top menu under VS IDE-->Configuration Manager-->click New under the Project Configuration then input linux under it)
First, you have to add these under your current vcxproj file:
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='linux|x86'">
<Import Project="my_super_props.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='linux|x86'">
<RemoteIntDir>$(RemoteProjectDir)/obj/$(PlatformTarget)/$(TargetOsName)/debug/</RemoteIntDir>
</PropertyGroup>
Second, modify your my_super_props.props file:
<RemoteGeneratedFilesDir>$(RemoteProjectDir)/obj/$(Platform)/$(TargetOsName)/debug/generated_files/</RemoteGeneratedFilesDir>
Rebuild the project:

Related

Visual Studio project with a custom build step only (no default build)

I want to create a Visual Studio project that would allow me to see a bunch of JavaScript and other files and edit them as normal, but would also have a build step that can run any custom commands I want (currently some npm commands, possibly more later). Basically I want 3 features combined:
Be able to browse and edit files just like for any VS project (C#, C++, etc.)
Be able to run a custom build step by selecting "Build" in Visual Studio (including building the whole solution).
Be able to run that same custom build step from the command line (MSBuild).
Using a "shared project" (.shproj) allows me to easily see and edit the files, but there is no Build item in the context menu, even if I manually add a Build target:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>...</ProjectGuid>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
<Import Project="MyItems.projitems" Label="Shared" />
<PropertyGroup>
<Configuration>Debug</Configuration>
<Platform>Any CPU</Platform>
</PropertyGroup>
<Target Name="Build">
<Exec Command="ECHO My custom build!" />
</Target>
</Project>
I've also tried using a stripped-down VC++ project (since I don't actually want to run the C++ compiler) and this allows a build to be run from VS, but opening the project logs warnings like error MSB4057: The target "GetProjectDirectories" does not exist in the project. and trying to add files to fails with that error or similar ones.
There must be an easier way to do this!
From your current description, I think you want to create a js project in VS IDE.
However, VS IDE has the node js project template by default. And you should install the workload Node.js development under VS_Installer so that you can use it.
After that, you can create such project.
1) Adding js files or other files by right-click on the project-->Add-->Existing Item so that you can modify the files on VS IDE.
2) If you want to execute a custom build step that does not break the whole build, you should make the custom target depends on the default build.
You can use this:
<Target Name="CustomStep" AfterTargets="Build">
<Exec Command="ECHO My custom build!" />
</Target>
or
<Target Name="CustomStep" BeforeTargets="Build">
<Exec Command="ECHO My custom build!" />
</Target>
Note: If you use
<Target Name="Build">
<Exec Command="ECHO My custom build!" />
</Target>
It will overwrite the system build process and instead, run the command, which breaks the whole default build.
3) If you want to execute the custom build on msbuild command, you should specify the name of the custom target:
msbuild xxx\xxx.proj -t: CustomStep(the name of the custom target)
===============================================
Besides, if you still want to use C++ project template, you could create a empty c++ project which does not contain any clcompile files and then do the same steps.
If you do not want to use C++ compiler, you should only remove any xml node on the vcxproj file like these:
<ClCompile Include="xxx.cpp" />
<ClInclude Include="xxx.h" />
When you use the empty C++ project, you do not have to worry about that.
=========================================
Update 1
If you want to build this project on a build sever without VS IDE, I suggest you could install Build Tool for VS2019 which is an independent, lightweight build command line(It is equivalent to dotnet cli).
Build Tool for VS2019
Under All Downloads-->Tools for Visual Studio 2019--> Build Tools for Visual Studio 2019
Then, you have to install the related build workload such as Node.js Build tools and then we can use the command line to build node.js project on build sever.
The entire installation process is fast.
Inspired by Perry Qian-MSFT's answer, I managed to strip down a Node.js project to the bare minimum that I needed to get Visual Studio to load and build it, but without referencing any external files.
The main trick was VS needs a target named "CoreCompile" to be defined to show the Build menu item! (It also needs a "Build" target, but that one is more obvious.)
My project now looks like this:
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>(some guid)</ProjectGuid>
<ProjectHome>.</ProjectHome>
<ProjectTypeGuids>{3AF33F2E-1136-4D97-BBB7-1795711AC8B8};{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}</ProjectTypeGuids>
</PropertyGroup>
<!-- These property groups can be empty, but need to be defined for VS -->
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
</PropertyGroup>
<Import Project="My.Build.targets" />
<!-- Define empty standard MSBuild targets, since this project doesn't have them. Doing it this way allows My.Build.targets to also be used in a project that does define them. -->
<Target Name="Build" />
<Target Name="ReBuild" />
<Target Name="Clean" />
<!-- NOTE: a target named "CoreCompile" is needed for VS to display the Build menu item. -->
<Target Name="CoreCompile" />
<!-- Files shown in Visual Studio - adding and removing these in the UI works as expected -->
<ItemGroup>
<Content Include="myfile..." />
</ItemGroup>
</Project>
And My.Build.targets looks like this:
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="MyBuild" AfterTargets="Build">(build steps)</Target>
<Target Name="MyReBuild" AfterTargets="ReBuild">(re-build steps)</Target>
<Target Name="MyClean" AfterTargets="Clean">(clean steps)</Target>
<!-- This target is needed just to suppress "warning NU1503: Skipping restore for project '...'. The project file may be invalid or missing targets
required for restore." -->
<Target Name="_IsProjectRestoreSupported" Returns="#(_ValidProjectsForRestore)">
<ItemGroup>
<_ValidProjectsForRestore Include="$(MSBuildProjectFullPath)" />
</ItemGroup>
</Target>
</Project>

ToolsVersion in Visual Studio 2019

I am doing the migration of several projects from VS2010 to VS2019. Those projects have Tools Version 4 in their vcxprojs:
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
Target VS is VS2019 v16.5.0, MSBuild version is 16.5.0.12403, so I am trying to set ToolsVersion to 16.5:
<Project DefaultTargets="Build" ToolsVersion="16.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
But it seems that MSBuild doesn't like it:
1>Building with tools version "Current".
1>Project file contains ToolsVersion="16.5". This toolset may be unknown or missing, in which case you may be able to resolve this by installing the appropriate version of MSBuild, or the build may have been forced to a particular ToolsVersion for policy reasons. Treating the project as if it had ToolsVersion="Current".
Despite builds are anyway successful, I care about this message. What can be wrong here?
UPD:
Providing simplified example of structure of projects:
common props:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ShouldUnsetParentConfigurationAndPlatform>false</ShouldUnsetParentConfigurationAndPlatform>
</PropertyGroup>
<PropertyGroup Label="Globals">
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<DotNetFrameworkVersion>v4.0</DotNetFrameworkVersion>
</PropertyGroup>
<!-- Other common variables-->
</Project>
cpp props:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
</PropertyGroup>
<PropertyGroup>
<TargetExt>.dll</TargetExt>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="common.props" />
<-- compiler, linker settings and so on -->
</Project>
Real project:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="16.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectName>my_name</ProjectName>
<ProjectGuid>{my_guid}</ProjectGuid>
<RootNamespace>my_ns</RootNamespace>
<Keyword>my_keyword</Keyword>
</PropertyGroup>
<Import Project="cpp.props" />
<-- configurations (Release, Debug, x64/Win32 and so on -->
<-- project-specific compiler/linker settings -->
<-- items: cpp, heanders and so on -->
<-- references -->
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
Project file contains ToolsVersion="16.5". This toolset may be unknown
or missing
To solve this issue, you should do some updates.
Suggestion
1), right-click on the project on VS2019 IDE-->Retarget Projects and target this project to the Windows 10 SDK version and choose upgrade to v142.
2), Right-click your project on VS2019 IDE-->unload project-->Edit (project name).vcxproj-->change ToolsVersion="4.0" to ToolsVersion="Current"--> then reload your project
3) Right-click on your project-->Properties-->Configuration Properties-->General-->change Platform Toolset to Visual Studio 2019 v142.
----------------Update 1-----------
First of all, ToolVersion is related to the version of MSBuild that is included in the Visual Studio edition like. And in general, we do not use 16.5 in VS2019. See this link. And actually, In VS2019, the ToolVersion is set to Current.
VS2019-->Current, VS2017-->15.0,VS2015-->14.0
You cannot include a specific small version number.
This is my test result with your sample in my side and it seems that it is just like a warning:
It means that it cannot specify the Illegal toolversion 16.5.
Solution
1) Just as I said before, change toolversion to Current in Realproject.vcxproj.
2) delete the toolversion xml node in Realproject.vcxproj and in VS2019, it will automatically recognize toolversion without adding it manually.
To prove it, you can create a new VS2019 c++ project and I am sure that you cannot find toolversion node in xxxx.vcxproj file.
Then try my solution into every projects and I am sure when you finish it, the info will not appear again.

Importing project settings (properties) across projects in Visual Studio 2015

This question is related to this one. But, when going to the properties manager ("View > Other Windows > Property Manager"):
and selecting "Add New Project Property Sheet...":
the property files is exported but its contents are:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup />
<ItemGroup />
</Project>
Where are the build flags set (I need a custom build with optimizations, incremental linking, aslr and dep all disabled)? These custom settings are present in the above figure in project "ExampleSubroutine1" and I want to make use of them, also in project "SingleLocalVariable", but importing the properties file in "SingleLocalVariable" does not set the respective build flags.
Why?
The following settings are present in "ExampleSubroutine1":
while defaults are kept in "SingleLocalVariable" even though I've imported the properties sheet from "ExampleSubroutine1":
I am using the same build configuration for all projects (Debug x64):

Visual Studio parsing behavior with custom property sheet to set platform tools version

i am in the process of converting a large set (over 600, hard to manage manually or via script) of projects from Visual Studio 2010 to Visual Studio 2013.
In order to keep the compiler version (and possibly other values) as modular as possible and build the projects with the VS2010 compiler from within VS2013, i define it in a custom property sheet (called native multi targeting, see MSDN blog and this blog).
My stripped down custom property sheet (located in the project folder named my_properties.props) looks like this
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Configuration">
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
</Project>
It is imported in the project at the topmost position, as can be seen in the Property Manager
which means it will overide all settings previously defined (though not relevant here, this was tricky to figure out).
Now to the problem. Depending on the order of imports in the project, the default platform toolset is correctly set to Visual Studio 2013 (v120) or not, in which case it is reverted to Visual Studio 2010 (v100), no clue where this is defined.
My stripped down project looks like this:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<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>
<PropertyGroup Label="Globals">
<ProjectGuid>{396A761A-45C9-46AA-BCF0-59FFD306D674}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>platform_toolset</RootNamespace>
</PropertyGroup>
<!-- This is Block A -->
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<!-- /A -->
<!-- This is Block B -->
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<!-- /B -->
<!-- This is Block C -->
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="my_properties.props" />
</ImportGroup>
<!-- /C -->
<!-- This is Block D -->
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<!-- /D -->
<!-- This is Block E -->
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="my_properties.props" />
</ImportGroup>
<!-- /E -->
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
With this ordering of the blocks, A, B, C, D, E, from top to bottom i get a default platform toolset of v100 for Debug builds and v120 for Release builds, oh boy.
Moving Block A to the end gives v120 for Release and nothing (empty field) for Debug, so A in front seems important (which would make sense for default/basic other property sheets from Microsoft).
Moving the ImportGroups in front of the PropertyGroups (resulting in A, C, E, B, D) leads to the correct behavior, v120 for Debug and Release and it is "inherited" (not bold).
How would i ensure the right order for my project files to be safely able to define the platform toolset centrally? Isnt MSBuild breaking a basic XML rule here be introducing an order of elements?
The answer here gave some important hints ("ms warns ... order ..."), this thread actually asks in the same direction.
Even in the bad cases, i can expand the Makros and have the following values, which seem fine to me:
$(DefaultPlatformToolset) v120
$(PlatfromToolset) v120
$(MSBuildToolsVersion) 12.0
$(VCTargetsPath) ...\V120\
A MSBuild bug? I know, property sheets are a bit icky, you have to restart the Studio if property sheets changed, some values (e.g. environment variables) seem to be cached, etc.
Any input is highly appreciated!
PS: Using VS2013 Update 3 on a Windows 7 64bit machine.
The platform should be set in the very beginning, like described in the link you posted. It is used in the Microsoft.Cpp.Default.props / Microsoft.Cpp.props.
The 'v100' you get could come from one of the .user files. Do you really need/have them?
I mean, here:
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
I mean, they are basically only useful for custom building on a specific user computer. If you don't use any computer- or user- specific settings, you can just remove those. These "user-settings" files are located in your user profile folder.
Also mind that "Microsoft.Cpp.Default.props" normally goes before "Microsoft.Cpp.props".
Anyways, faced similar issue, I ended up removing all the stuff from the projects (.vcxproj) files at all. Then it seems to work pretty well. And clean. In your case, it would look like this.
.vcxproj (note that nothing related "debug" or "release" or ".user" or whatever is inside).
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ConfigurationType>Application</ConfigurationType>
<ProjectGuid>{49C9EA4B-99DC-47D1-B32E-ACDF297B2A43}</ProjectGuid>
</PropertyGroup>
<Import Project="Platform.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
....
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
Platform.props (shared for all .vcxproj files)
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PlatformToolset>v120_xp</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<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>
Yes, MSBuild file is XML but MSBuild processor has itself has multiple phases. Here is an excerpt from amazing book "Inside the Microsoft Build Engine" by Sayed Ibrahim Hashimi and William Bartholomew:
When the MSBuild engine begins to process a build file, it is evaluated in a top-down fashion
in a multi-pass manner. These passes are described in order in the following list.
0 . Load all environment and global properties
Evaluate properties and imports processing imports as encountered
Evaluate item definitions
Evaluate items
Evaluate using tasks
Start build and reading targets
This means that the last value of the property will win (the one which will be evaluated last). Many properties are written carefully with conditions to evaluate to this value only if no property with same name exists e.g.:
<PropertyGroup>
<PlatformToolset Condition="$(PlatformToolset)== ''">v10_Toolset</PlatformToolset>
<PropertyGroup>
This approach guarantees the following: this property will have certain (first met default) value before phase 5, but Condition clause allows usage of Global properties and environment variables (read - your build environment parameters) to override any default values.
And thus (and it might be very confusing and counter-intuitive) if you want to say "the final word" of what property value should be - you must put it to the very end of the script.
On other hand - your described behaviour means that in your included scripts something doesn't respect existing supplied properties (e.g. doesn't have this Condition clause ) - it might be a bug in one of your scripts or intentionally overridden behaviour. I'd recommend you to find out why exactly your initial values are being changed, otherwise you can get very subtle and tricky bugs.
PS: I also accept that there might be bugs in MSBuild targets - I found that MSBuild targets quality varies slightly from "great and working perfectly" to "tangled mess" so don't be surprised if you'll see bugged\hacky approach and you'll need to fix it.
I've found, and reported in other posts tagged msbuild, that the PlatformToolset behaves funny, and different in VS or command-line. In addition to making sure it's set early enough, it seems to "unnaturally" be required in the main (not included) file and possibly in a particular spot.
Make your modular include verify that it's already correct. Then at least you can make a change in one place that makes sure you updated every project.
Even without this one being funny, the value is used early on, so must be set before the workhorse includes. Prop sheets set in the IDE are put at the bottom, so that won't work.

Moving compile items in msbuild into a separate file?

This is probably a FAQ, but we weren't able to find a solution even after a lot of searching.
We have a number of msbuild files that all operate on the same set of source files. (It's not particularly relevant but they compile to completely different platforms.) To make managing these a little simpler, we'd like to move the <Compile> source file names to a separate file and reference that from all the msbuild files.
We tried cutting the <ItemGroup> containing the <Compile> items and pasting it into a new file, and surrounding it with
<Project DefaultTargets="Build" ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
and then referencing that file from the original with
<Import Project="Common.files.csproj" />
but that does not work - the solution opens (with a warning since we hacked the default config), but no items appear in the Solution Explorer.
What are we doing wrong?
Tried with Visual Studio 2010:
1) Create your external .proj (or .target) file and add your files (I used a different item name but that shouldn't matter)
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ExternalCompile Include="Program.cs" />
<ExternalCompile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
</Project>
2) Import your external .proj file at the top of your Visual Studio project file:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="MyExternalSources.proj" />
<PropertyGroup>
...
and modify the Compile ItemGroup like this:
...
<ItemGroup>
<Compile Include="#(ExternalCompile)" />
</ItemGroup>
...
Warning: You'll have to add new items/files to your external .proj file - all items/files added from within Visual Studio will end up like this:
...
<ItemGroup>
<Compile Include="#(ExternalCompile)" />
<Compile Include="MyNewClass.cs" />
</ItemGroup>
...
I've never seen "include" files work with MSBuild. Obviously Targets files work this way, but I haven't seen a partial msbuild file included in another. COuld you use a method such as illustrated in this?
http://msdn.microsoft.com/en-us/library/ms171454(VS.80).aspx
Using wildcards is how I've addressed this in the past.

Resources