Waldo Bronchart
Waldo Bronchart

Reputation: 10532

Msbuild preprocessor define for all dependencies of main exe project

I have an "engine" library that is used by a game executable. That engine library is also used by an editor executable.

I want to build the engine lib with a preprocessor constant EDITOR when it's built for editor.exe When the engine lib is built for game, there is no "EDITOR" preprocessor constant.

Is there a way to say that a preprocessor constant from the referencing project should be used for dependency builds too?

I've tried this in the editor .csproj:

<Project ToolsVersion="4.0" DefaultTargets="Build">
  <PropertyGroup>
    <AssemblyName>MyEditor</AssemblyName>
    <DefineConstants>EDITOR</DefineConstants>
  ...

but that only applies to MyEditor.exe assembly. I want it to apply to all references too.

I hope this is clear enough :)

Edit: I can get this working from the command line with msbuild MyEditor.csproj /p:DefineConstants=EDITOR, but I don't know how to get the same effect in Visual Studio

Upvotes: 2

Views: 2604

Answers (1)

Brian Kretzler
Brian Kretzler

Reputation: 9938

It is possible, but requires a bit of MSBuild trickery. The way referenced projects get built is that they end up in the @(ProjectReferenceWithConfiguration) item array, through manipulations in the Microsoft.Common.targets file. Now if the project were included in this item array like this, in one project but not from the other,

<!-- pseudo-code for what Microsoft.Common.targets creates -->
<ItemGroup>
   <ProjectReferenceWithConfiguration Include="ReferencedProject.csproj">
      <AdditionalProperties>DefineConstants=EDITOR</AdditionalProperties>
   </ProjectReferenceWithConfiguration>
</ItemGroup>

...it would get built the way you want. How do you set this up though? Well, you can wire into the creation of the @(ProjectReferenceWithConfiguration) item array with your own custom target and add the AdditionalProperties metadata value. Something like this...

<!-- inside referencing project -->
<Target Name="AddEditorConstant"
   AfterTargets="AssignProjectConfiguration"
   BeforeTargets="_SplitProjectReferencesByFileExistence">
   <ItemGroup>
      <ProjectReferenceWithConfiguration
         Condition="'%(Identity)' == 'ReferencedProject.csproj'>
         <AdditionalProperties>DefineConstants=EDITOR</AdditionalProperties>
      </ProjectReferenceWithConfiguration>
   </ItemGroup>
</Target>

(note, I didn't actually run this, some experimentation may be required)

For a more generic solution that reverses the location of the customization, placing it inside the reference project rather than inside the referencing, you could instead inject the parent project with the reference as a custom property into all references,

<!-- somewhere common to all projects -->
<Target Name="InjectReferencingProject"
   AfterTargets="AssignProjectConfiguration"
   BeforeTargets="_SplitProjectReferencesByFileExistence">
   <ItemGroup>
      <ProjectReferenceWithConfiguration>
         <AdditionalProperties>ReferencingProject=$(MSBuildProjectFile)</AdditionalProperties>
      </ProjectReferenceWithConfiguration>
   </ItemGroup>
</Target>

And then, inside the ReferencedProject.csproj, modify whatever you want based on which parent project has the reference,

<!-- inside referenced project -->
<PropertyGroup>
   <DefineConstants>default-constants</DefineConstants>
   <DefineConstants
      Condition="'$(ReferencingProject)' == 'SomeSpecialProject.csproj'"
      >$(DefineConstants);EDITOR</DefineConstants>
</PropertyGroup>

Upvotes: 4

Related Questions