MSBuild脚本默认属性最佳实践解释

8
在编写MSBuild脚本时,我需要定义一系列默认属性,但可以在运行脚本时进行覆盖。根据以下文章,您应该使用条件语句来设置属性的默认值:

http://msdn.microsoft.com/en-us/library/ee240983.aspx

微软的建议:
<PropertyGroup>
    <MyProperty Condition="'$(MyProperty)' == '' ">Default Value</MyProperty>
</PropertyGroup>

然而,这个表现方式完全相同:
<PropertyGroup>
    <MyProperty>Default Value Without Conditional</MyProperty>
</PropertyGroup>

所以,如果我有这个目标(Target)并使用上述任何一种方式调用它,它的行为都是相同的:

<Target Name="DefaultsTest">
    <Message Text="$(MyProperty)"></Message>
</Target>

调用:

msbuild build.xml /t:DefaultsTest /p:MyProperty="Overridden value"

如果您只是默认相同的属性,而这些属性可以从调用中覆盖,那么请解释使用 Condition 属性的好处。

更新:

这里有一个完整的简单配置文件来演示:defaults.xml

<?xml version="1.0" encoding="utf-8" ?>
<Project DefaultTargets="DefaultsTest" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup>
        <MyProperty Condition=" '$(MyProperty)' == '' ">MyProperty with Conditional</MyProperty>
        <MyOtherProperty>MyOtherProperty without Conditional</MyOtherProperty>
    </PropertyGroup>

    <Target Name="DefaultsTest">
        <Message Text="$(MyProperty)"></Message>
        <Message Text="$(MyOtherProperty)"></Message>
    </Target>
</Project>

这可以简单地运行为msbuild defaults.xml 或者 msbuild defaults.xml /p:MyProperty="更改的值" /p:MyOtherProperty="同样更改"

2
然而,这两种行为完全相同:不是的:如果MyProperty没有在其他地方(比如在命令行上)指定,它将为空。然而,如果使用推荐的方法,如果未在其他地方指定MyProperty,则其值将为“默认值”。使用msbuild build.xml /t:DefaultsTest调用这两种情况,您将看到差异。 - stijn
@stijn 我按照你说的测试了,无论条件是否存在,我都收到了节点的默认值。 - Keith Morris
1个回答

10
你正确地注意到,你可以通过无条件赋值属性来实现所需的行为。如果在命令行中不使用 /p:override 构建以下项目,则会产生 "默认值"。而使用命令 msbuild myproj.proj /t:DefaultsTest /p:MyProperty=NewValue 构建时将产生 NewValue。请保留 HTML 标签。
 <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup>
        <MyProperty>Default Value</MyProperty>
    </PropertyGroup>
    <Target Name="DefaultsTest">
        <Message Text="MyProperty=$(MyProperty)"></Message>
    </Target>
</Project>

这是因为在MSBuild命令行上指定的任何属性或作为任务参数提供的属性都将被视为全局属性。对于全局属性,任何条件或非条件的分配或修改都会被简单地忽略——全局属性将在整个项目执行期间保持不变。

条件分配和非条件分配之间的唯一行为差异在于是否使用TreatAsLocalProperty属性。

例如,请考虑以下项目:

 <Project TreatAsLocalProperty="Prop1;Prop2" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup>
        <Prop1>Prop1 Default Value</Prop1>
        <Prop2 Condition="$(Prop2) == ''">Prop2 Default Value</Prop2>
    </PropertyGroup>
    <Target Name="DefaultsTest">
        <Message Text="Prop1=$(Prop1)"></Message>
        <Message Text="Prop2=$(Prop2)"></Message>
    </Target>
</Project>

在Project元素中,有两个属性——Prop1和Prop2都被声明为局部变量。Prop1被无条件地赋值,而Prop2则使用非空条件进行赋值。执行构建命令:

msbuild b.proj /t:DefaultsTest /p:Prop1=NewValue1 /p:Prop2=NewValue2

将会产生输出:

Prop1=Prop1 Default Value
Prop2=NewValue2

这意味着在一般情况下(如果您不确定属性是全局还是局部),更安全的做法是使用默认值的条件赋值,因为它始终有效。

还有一个问题涉及环境变量。根据http://msdn.microsoft.com/en-us/library/ms171459.aspx的说法:“如果项目文件包含与环境变量同名的属性的显式定义,那么项目文件中的属性将覆盖环境变量的值。”通过检查属性是否已定义,环境属性就不会被覆盖。(请注意,我实际上还没有测试过这个) - alh84001

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