I've done a lot of MSBuild customization for my C++ projects in the past. The Input and Output attributes of a MSBuild target are used to determine whether the target has to be executed or not. Additionally Visual Studio uses the .tlog files (located in the intermediate directory) to determine whether MSBuild has to be invoked at all.
Now I'm working on a C# project. I wrote a simple MSBuild target which copies a file to the output directory:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="CopyMyFile" BeforeTargets="AfterBuild" Inputs="$(ProjectDir)File.dat" Outputs="$(TargetDir)FileRenamed.dat">
<Copy SourceFiles="$(ProjectDir)File.dat" DestinationFiles="$(TargetDir)FileRenamed.dat" OverwriteReadOnlyFiles="true">
</Copy>
</Target>
</Project>
The target works as expected if the build is invoked through MSBuild.exe. The file is copied if the target file does not exist or the source file has been modified.
If I invoke the build inside Visual Studio it does not work as expected. Visual Studio does not invoke MSBuild if I delete the file from the output directory. On the other hand MSBuild is invoked every time I build the project after modifiying the source file even if there are no other changes made.
It seems that Visual Studio just compares every file from a project to the output files (.exe, .dll or .pdb). If any file in the project is newer than the output files, MSBuild is invoked. In my case MSBuild does not update the .exe file, so MSBuild is invoked again and again.
In a C++ project this behaviour is controlled by the .tlog files. Is there anything similar in a C# project?
Thanks a lot!
It looks like this is just poorly documented. This site shows you can easily hook up a command line tool, while lifting on the incremental features of tlog files.
To make sure the information doesn't get lost, I'll just copy over their use case, but looking at that, I think it's easy to transform into your needs. Every occurrence of dcx can be replaced by e.g. data
.xml fileItemTypeContentType to the ItemTypeFileExtension<?xml version="1.0" encoding="utf-8"?>
<ProjectSchemaDefinitions xmlns="http://schemas.microsoft.com/build/2009/properties">
<!-- Associate DXCShader item type with .hlsl files -->
<ItemType Name="DXCShader" DisplayName="DXC Shader" />
<ContentType Name="DXCShader" ItemType="DXCShader" DisplayName="DXC Shader" />
<FileExtension Name=".hlsl" ContentType="DXCShader" />
</ProjectSchemaDefinitions>
.targets file.xml definitions fileTarget that depends on one of your build hooks (here: ClCompile)ItemGroup in your Target that will serve as the argument to your CustomBuild. Message, Command, AdditionalInputs and Output are meta-attributes that are relevant.CustomBuild with MinimalRebuildFromTracking="true" and a TrackerLogDirectory to contain the tlog files. This part is the magic ingredient that makes MSBuild skip the build if your dependencies are up-to-date.<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<!-- Include definitions from dxc.xml, which defines the DXCShader item. -->
<PropertyPageSchema Include="$(MSBuildThisFileDirectory)dxc.xml" />
<!-- Hook up DXCShader items to be built by the DXC target. -->
<AvailableItemName Include="DXCShader">
<Targets>DXC</Targets>
</AvailableItemName>
</ItemGroup>
<Target
Name="DXC"
Condition="'@(DXCShader)' != ''"
BeforeTargets="ClCompile">
<Message Importance="High" Text="Building shaders!!!" />
<!-- Find all shader headers (.hlsli files) -->
<ItemGroup>
<ShaderHeader Include="*.hlsli" />
</ItemGroup>
<PropertyGroup>
<ShaderHeaders>@(ShaderHeader)</ShaderHeaders>
</PropertyGroup>
<!-- Setup metadata for custom build tool -->
<ItemGroup>
<DXCShader>
<Message>%(Filename)%(Extension)</Message>
<Command>
"$(WDKBinRoot)\x86\dxc.exe" -T vs_6_0 -E vs_main %(Identity) -Fh %(Filename).vs.h -Vn %(Filename)_vs
"$(WDKBinRoot)\x86\dxc.exe" -T ps_6_0 -E ps_main %(Identity) -Fh %(Filename).ps.h -Vn %(Filename)_ps
</Command>
<AdditionalInputs>$(ShaderHeaders)</AdditionalInputs>
<Outputs>%(Filename).vs.h;%(Filename).ps.h</Outputs>
</DXCShader>
</ItemGroup>
<!-- Compile by forwarding to the Custom Build Tool infrastructure,
so it will take care of .tlogs and error/warning parsing -->
<CustomBuild
Sources="@(DXCShader)"
MinimalRebuildFromTracking="true"
TrackerLogDirectory="$(TLogLocation)"
ErrorListRegex="(?'FILENAME'.+):(?'LINE'\d+):(?'COLUMN'\d+): (?'CATEGORY'error|warning): (?'TEXT'.*)" />
</Target>
</Project>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With