Search code examples
msbuildmsbuild-taskcompiler-options

Compiler Additional Options computed in a custom Target


I have a msbuild custom Target and a Task computing a Value. The Task will output the Value as Property. This Property I would like to uses as Additional Option to the Compiler call.

But the Property is empty when used as Additional Option.

My *.targets File looks like this:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <UsingTask TaskName="GetBranchName_TASK" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" >
    <ParameterGroup>
        <sPath ParameterType="System.String" Required="true" />
        <sBranchName ParameterType="System.String" Output="true" />
    </ParameterGroup>
    <Task>
      <Code Type="Fragment" Language="cs">
        <![CDATA[
            ... some Code ...
        ]]>
      </Code>
    </Task>
  </UsingTask>

  <Target Name="GetBranchName_TARGET">
    <GetBranchName_TASK sPath="$(MSBuildThisFileDirectory)">
      <Output PropertyName="BranchName" TaskParameter="sBranchName" />
    </GetBranchName_TASK>
    <Message Importance="High" Text="BranchName = $(BranchName)" />
  </Target>

  <PropertyGroup>
    <BuildDependsOn>
        GetBranchName_TARGET;
        $(BuildDependsOn);
    </BuildDependsOn>
  </PropertyGroup>
</Project>

My *.props File is like this:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup Label="Configuration">
    ... some Properties here ...
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  <Import Project="IRSGetBranchName.targets" /> 
  <ItemDefinitionGroup>
    <ClCompile>
      <AdditionalOptions>/DBRANCHNAME=$(BranchName) /DMORE=BAR</AdditionalOptions>
    <ClCompile>
  <ItemDefinitionGroup>
</Project>

This .props File then is imported into several .vcxproj

The Value printed as Message in my GetBranchName_TARGET is correct as expected (showing the correct TFS-Branch Name). But when looking at Detailed Build Output, the Value seems empty:

1>ClCompile
1>    ..\FOO.cpp
1>        AdditionalOptions = /DBRANCHNAME= /DMORE=BAR

I tried for hours but found no solution and I really hope someone help whats wrong here ...

a) Is the Property BranchName not available globally? I tried to print the Property from other custom Targets and it worked well!

b) Or is the ClCompile.AdditionalOptions evaluated/build before my Target is excuted? In this case how can I re-evaluate?

c) ...

I'am very thankful for any Input.


Solution

  • You should be familiar with the msbuild evaluation process, as described here:

    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:

    1. Load all environment and global properties, and toolset properties. In Microsoft Visual Studio 2010, for example, C++ defines several properties in the MSBuild 4.0 toolset.
    2. Evaluate properties and process imports as encountered
    3. Evaluate item definitions
    4. Evaluate items
    5. Evaluate using tasks
    6. Start build and reading targets

    So, in your case, the ItemDefinitionGroup for ClCompile has been evaluated before the GetBranchName_TARGET has been executed. So, it is empty by design.

    In order to achieve the desired behavior, you should Add the following:

    <Target Name="GetBranchName_TARGET">
      <GetBranchName_TASK sPath="$(MSBuildThisFileDirectory)">
        <Output PropertyName="BranchName" TaskParameter="sBranchName" />
      </GetBranchName_TASK>
      <Message Importance="High" Text="BranchName = $(BranchName)" />
      <ItemGroup>
        <ClCompile>
          <AdditionalOptions>/DBRANCHNAME=$(BranchName) /DMORE=BAR</AdditionalOptions>
        </ClCompile>
      </ItemGroup>
    </Target>
    

    You can use a Condition attribute in the ClCompile in order to include only your sources, for example. Actually, what you are looking for is the feature to modify item metadata after it was declared.