如何在.csproj文件中使用MSBuild条件测试编译器指令?

20

我完全不了解.csproj文件中的函数和条件,所以非常感谢任何帮助。

我的目标是检查当前配置中是否存在特定的编译器指令。例如,以下是一个示例:

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

我不确定这是否可能。如果有更好的方法,请让我知道。无论如何,我想测试一个与配置 无关 的条件。

编辑

实际上我想要一个可以在Visual Studio内轻松编辑的值,而且也可以在任何配置下检查。我考虑使用编译器常量,因为你可以在VS项目属性中轻松更改它们。


更常见的做法可能是使用 Property 元素。您的 csproj 文件已经有了条件性的 PropertyGroup 元素,取决于配置。在它们内部,您可以添加新的自定义 Property 元素,并且可以像通常一样在 Condition= 属性中测试它们。这对您是否有效,或者您真的需要编译器指令?它们更复杂,因为它们可以以多种方式定义。 - user743382
可能可以。在我添加自定义属性元素后,有没有一种简单的方法在VS中轻松编辑它们,而不必每次都编辑.csproj文件来更改它们? - Mike Webb
我想要的是一个可以定义值的变量,无论配置如何我都可以更改和检查。 - Mike Webb
不,除非你想创建一个VS插件(一些插件确实会添加属性,并将它们作为项目属性的新选项卡提供),否则没有从GUI编辑自定义属性的方法,但这可能需要太多的工作。 - user743382
4个回答

26

编译器常量被设置为一个属性"DefineConstants",所以你只需要评估那个属性即可。你的Choose语句需要放在定义常量的PropertyGroups之后或者在一个目标内部。

<Choose>
    <When Condition="$(DefineConstants.Contains(CONST-1))">
        ...
    </When>
    <When Condition="$(DefineConstants.Contains(CONST-2))">
        ...
    </When>
</Choose>

1
谢谢,这个完美地解决了问题。不过我得删除 CONST-1 或其他条件定义周围的引号。 - Randeep

11

如果您使用MSBuild 4或更高版本,建议使用正则表达式而不是String.Contains()。原因是尽管String.Contains()通常运行良好,但在某些情况下可能会出现问题。

例如:

考虑在代码中使用指令CONST-1和CONST-12的情况。但是,您决定仅为当前构建定义CONST-12指令。
现在,Condition="$(DefineConstants.Contains('CONST-1'))"即使未定义CONST-1,也会评估为True

使用RegularExpressions.RegEx的解决方案:

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

总之,您可以小心确保不使用另一个指令的子字符串,或者您可以使用正则表达式而不必担心任何问题。


这是唯一在目标文件中起作用的 System.Text.RegularExpressions.Regex,谢谢:"<When Condition="$([System.Text.RegularExpressions.Regex]::IsMatch($(DefineConstants), '^(.*;)*CONST-1(;.*)*$'))">" - SoLaR

3

除了其他回答中提到的方法,你还可以通过在DefineConstants属性周围加上分号来处理这个问题,以确保只有在“CONST-1”常量被定义时,“; CONST-1;”将包含在DefineConstants中。如果没有分号,你可能会有一个名为CONST-100或UNCONST-1的变量,并且它将被评估为true,但不是CONST-1。

<PropertyGroup>
    <DefineConstants2>;$(DefineConstants);</DefineConstants2>
    <Foo Condition="'$(DefineConstants2.Contains(`;CONST-1;`))'">It worked</Foo>
    <Bar>$(Foo)</Bar> <!--It worked-->
</PropertyGroup>

0

使用当前编译器和“新”项目样式,即使在CommonSettings.targets文件中已经定义了DefineConstants,这对我也起作用:

  <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>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接