How do I test for compiler directives with an MSBuild Condition in a .csproj file?
Asked Answered
S

4

20

I am totally new to the functions and conditions in .csproj files so any and all help is appreciated.

What I want to do is check for a specific compiler directive in the current configuration. An example would be something like the following:

<Choose>
    <When Condition= [current configuration has CONST-1 compiler constant defined] >
        ...
    </When>
    <When Condition= [current configuration has CONST-2 compiler constant defined] >
        ...
    </When>
</Choose>

I don't know if this is even possible or not. If there is a better way to do what I am asking let me know that as well. Either way, I want to test for a condition independent of the configuration.

EDIT

What I really want is a value that I can edit easily, preferrably within Visual Studio, that I can also check regargless of the configuraiton. I thought about compiler constants because you can easily change them in the Project Properties in VS.

Stambaugh answered 18/10, 2012 at 14:32 Comment(4)
Probably more common would be to use a Property element. Your csproj file will already have conditional PropertyGroup elements, depending on the configuration. Inside them, you can add new custom Property elements, and you can test them in the usual way in your Condition= attribute. Would that work for you, or do you really need compiler directives? They're more complicated, because there are various ways in which they could be defined.Beverie
It might. Is there a way to edit custom property elements, after I've added them, in VS easily without having to edit the .csproj file every time I want to change them?Stambaugh
What I want is a value defined that I can change and check no matter what the configuration is.Stambaugh
No, there's no way from the GUI to edit custom properties, unless you want to create a VS addin (some addins do add properties, and provide them as a new tab in the project properties, but that's probably too much work)Beverie
S
27

Compiler constants are set into a property "DefineConstants" so you should just be able to evaluate that property. Your Choose statement needs to go after the PropertyGroups that define the constants or inside a target.

<Choose>
    <When Condition="$(DefineConstants.Contains(CONST-1))">
        ...
    </When>
    <When Condition="$(DefineConstants.Contains(CONST-2))">
        ...
    </When>
</Choose>
Skate answered 18/10, 2012 at 15:10 Comment(1)
Thanks this worked perfectly... However I had to remove the quotes around CONST-1 or whatever the conditional define isSkye
B
11

In case you use MSBuild 4 or higher, I suggest using Regular Expression instead of String.Contains(). The reason for this is that even though String.Contains() usually works well, there are some cases you might get into problems.

For example:

Consider case when you use directives CONST-1 and CONST-12 in your code. However, you decide to define only CONST-12 directive for current build.
Now Condition="$(DefineConstants.Contains('CONST-1'))" evaluates to True even though CONST-1 is not defined.

Solution with RegularExpressions.RegEx:

<When Condition="$([System.Text.RegularExpressions.Regex]::IsMatch($(DefineConstants), '^(.*;)*CONST-1(;.*)*$'))">
...
</When>

To sum up, you can either be careful to make sure you don't use directive that is Substring of another or you can use the regular expression and not worry at all.

Bricole answered 2/12, 2014 at 22:10 Comment(1)
This is the only System.Text.RegularExpressions.Regex that works in targets file, thanks : "<When Condition="$([System.Text.RegularExpressions.Regex]::IsMatch($(DefineConstants), '^(.*;)*CONST-1(;.*)*$'))">"Matchlock
M
5

To add to the other answers posted here, another way you can approach this is to wrap the DefineConstants property with semicolons, to guarantee that ";CONST-1;" will be contained in DefineConstants if and only if the "CONST-1" constant is defined. Without the semicolons, you could have CONST-100, or UNCONST-1, but not CONST-1, as a variable and it would evaluate to true.

<PropertyGroup>
    <DefineConstants2>;$(DefineConstants);</DefineConstants2>
    <Foo Condition="'$(DefineConstants2.Contains(`;CONST-1;`))'">It worked</Foo>
    <Bar>$(Foo)</Bar> <!--It worked-->
</PropertyGroup>
Mastoiditis answered 8/10, 2017 at 20:0 Comment(0)
U
1

With current compiler and "new" project style this worked for me even if DefineConstants have been defined externally in CommonSettings.targets file:

  <Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFrameworks>netstandard2.0</TargetFrameworks>
        <LangVersion>latest</LangVersion>
    </PropertyGroup>
    <PropertyGroup>
      <DefineConstants>DEBUG;TRACE;Foo</DefineConstants>
    </PropertyGroup>
    
    <ItemGroup Condition="'$(DefineConstants.Contains(Foo))'">
        <PackageReference Include="System.Windows.Forms" Version="4.0.0" />
    </ItemGroup>
  </Project>
Unbroken answered 12/4, 2023 at 8:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.