Post

.Net Compiler Directives by Configuration Name

I’ve been building plugins that integrate into other application for a long time. I’ve been very successfully handling the 3rd party API version changes in a variety of ways, but recently there were some really large changes that required dynamic compiler preprocessor directives. I’ve used these plenty, but never had to make them so situational before. Here is the method I used to maintain a single code base and handle the configuration conditional build.

Context

Because my plugins are highly specific to another software’s version, I make use of the $(Configuration) environment variable a lot in my *.csproj files. In fact all my configuration names are just years like 2019, 2020, 2021. Which lets me use the $(Configuration) variable to dynamically target the right dependencies and/or build/install locations that represent the 3rd party defined paths.

You will find a line resembling this in your *.csproj files that represent the typical/standard available directives.

<DefineConstants>DEBUG;TRACE</DefineConstants>

In my circumstance, I flip these from looking for something to NOT something.

1
2
3
4
5
6
7
8
9
10
  <PropertyGroup Condition=" '$(Configuration)' != 'Release' ">
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>$(UserProfile)\Documents\Builds\DLL\Versions\$(Configuration)</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
    <PlatformTarget>x64</PlatformTarget>
  </PropertyGroup>

The Trick

When the 2022 version came out, I had breaking changes that required something to distinguish pre-2022 code from the newly adapted code. The trick was to create standalone PropertyGroup conditions specifically and only for defining my configuration name based preprocessor directive constants.

1
2
3
4
5
6
7
8
9
  <PropertyGroup Condition="'$(Configuration)' == '2021'">
    <DefineConstants>PRE2022</DefineConstants>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)' == '2020'">
    <DefineConstants>PRE2022</DefineConstants>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)' == '2019'">
    <DefineConstants>PRE2022</DefineConstants>
  </PropertyGroup>

It is actually possible to use the OR operator within a single statement, but I prefer the verbose and clear layout I have shown. It is just more obvious to someone else that comes behind me. Here is an example of the alternate smaller configuration:

1
2
3
  <PropertyGroup Condition="'$(Configuration)' == '2021' OR '$(Configuration)' == '2020' OR '$(Configuration)' == '2019'">
    <DefineConstants>PRE2022</DefineConstants>
  </PropertyGroup>

After doing one of the above, my code can now use #if PRE2022 directive to build an alternate block of code based on the active configuration name.

Source

I originally got put onto this ideas from StackOverflow, but I did not find any of the answers complete or entirely clear so I thought I would detail my own implementation. My secondary objective was to hopefully use some more keywords that I tried and didn’t lead me to such a source.

Bonus

Here is my XCopy PostBuildEvent script that does the actual installation of my DLL’s into a 3rd party location.

Note, this may require Visual Studio to be started in administrator mode.

1
2
3
4
<PropertyGroup>
    <PostBuildEvent>echo F|XCOPY "$(TargetDir)*.*" "C:\ProgramData\Autodesk\Revit\Addins\$(Configuration)\MyDlls\" /s /i /y /EXCLUDE:$(ProjectDir)excludes.txt
echo F|XCOPY "$(TargetDir)*.addin" "C:\ProgramData\Autodesk\Revit\Addins\$(Configuration)\" /s /y</PostBuildEvent>
  </PropertyGroup>
This post is licensed under CC BY 4.0 by the author.