Build multiple binaries from one project in dotnet
November 18, 2020
Sometimes we might need to build slightly different binaries (or assemblies) out of the same code repository. For example, you might want to release your application with some features to your customers, while hosting/running the full version only by yourself, or in one platform a dependency of your application is not available, while there is a sub-optimal substitution which you don’t want to use on other platforms. In these cases we normally want to build different binaries from, ideally the same code base to avoid duplication. I am going to show you how to do it in dotnet core.
Use C# preprocessor directives/symbols
C# preprocessor directives are used by C# compiler to preprocess the code. In the following example we define a symbol called ‘SELFHOSTED’ at the first line, so line 4 and line 16 are included by the compiler. Without the directive in the first line, the compiler will be drop these two lines.#define SELFHOSTED
#if SELFHOSTED
using MyLib;
#endif
using System;
namespace app
{
class Program
{
static void Main(string[] args)
{
#if SELFHOSTED
MyClass.MyMethod1();
#endif
}
}
}
So by removing the first line, we can build a different binary! However, it is not that useful as we still need to edit the code before building, which might introduce a lot of errors if your project is slightly bigger than this example.
Use msbuild property to define symbols at compile time
The good news is, we can decide whether to define symbol ‘SELFHOSTED’ at build time. To do it, first of all let’s remove the symbol definition in the C# code:#define SELFHOSTED
Secondly, add the following to your .csproj file:
<PropertyGroup Condition="'$(HostingMode)'=='self'">
<DefineConstants>SELFHOSTED</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(HostingMode)'=='self'">
<ProjectReference Include="../lib/MyLib.csproj"/>
</ItemGroup>
HostedBy<PropertyGroup Condition="'$(HostingMode)'=='self'">
<DefineConstants>SELFHOSTED</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(HostingMode)'=='self'">
<ProjectReference Include="../lib/MyLib.csproj"/>
</ItemGroup>
Depending on the value of property ‘HostedBy’, we tell msbuild (dotnet build engine) whether to define symbol ‘SELFHOSTED’, and whether to add a project dependency. Notice that the project reference is used in C# code only when the symbol is defined.
Finally, we are able to build two different binaries with the same code base! The only difference is in the build commands:
dotnet build /p:HostedBy=self
dotnet build /p:HostedBy=others
See the full demo on my github.