Reputation: 10532
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
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