Using the contents of a file to define an MSBuild property
Say you want to define a property in your MSBuild project file (vcxproj, csproj, etc.) and have the property value come from a file. You might try using the
ReadLinesFromFile task to get the contents:
<Target Name="DefineMagic"> <ReadLinesFromFile File=".\magic.txt"> <Output TaskParameter="Lines" PropertyName="Magic" /> </ReadLinesFromFile> </Target> <ItemDefinitionGroup> <ClCompile> <PreprocessorDefinitions>MAGIC="$(Magic)";%(PreprocessorDefinitions)</PreprocessorDefinitions> </ClCompile> </ItemDefinitionGroup>
This doesn’t work because the
Target doesn’t run until after the
ItemDefinitionGroup is already defined. MSBuild evaluates
ItemGroup elements before running any
Targets, By the time you execute the
ReadLinesFromFile task, it’s too late.
Instead, you can use the
ReadAllText MSBuild property function to read the text into a property.
<PropertyGroup> <Magic>$([System.IO.File]::ReadAllText('.\magic.txt').TrimEnd())</Magic> </PropertyGroup> <ItemDefinitionGroup> <ClCompile> <PreprocessorDefinitions>MAGIC="$(Magic)";%(PreprocessorDefinitions)</PreprocessorDefinitions> </ClCompile> </ItemDefinitionGroup>
You can see an example of this trick in the WindowsAppSDK build properties.
I’ve been using this approach for quite a long, especially for the NuGet package release notes.
The only downside is the file needs to be physically present in the path mentioned. So relative path needs to be carefully managed.
MSBuild is so bad I’d love to cut it out of the build process, but trying to run the dotnet runtime any other way is its own pain.
Most of the actual build code is C# code inside dotnet.exe with no other entry point.