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 ReadÂLinesÂFromÂFile
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 ItemÂDefinitionÂGroup
is already defined. MSBuild evaluates PropertyÂGroup
and ItemÂGroup
elements before running any Target
s, By the time you execute the ReadÂLinesÂFromÂFile
task, it’s too late.
Instead, you can use the ReadÂAllÂText
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.
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.
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.