MSBuild 属性

属性是可用于配置生成的名称/值对。 属性可用于将值传递给任务,评估条件和存储将在整个项目文件中引用的值。

在项目文件中定义和引用属性

属性的声明方式是:创建一个与属性同名的元素,将其指定为 PropertyGroup 元素的子元素。 例如,下面的 XML 将创建一个名为 BuildDir 的属性,其值为 Build

<PropertyGroup>
    <BuildDir>Build</BuildDir>
</PropertyGroup>

有效属性的名称以大写或小写字母或下划线 (_) 开头;有效的后续字符包括字母数字字符(字母或数字)、下划线和连字符 (-)。

在整个项目文件中,可使用语法 $(<PropertyName>) 来引用各个属性。 例如,上一示例中的属性是使用 $(BuildDir) 引用的。

属性值可通过重新定义属性进行更改。 使用以下 XML可赋予 BuildDir 属性新值:

<PropertyGroup>
    <BuildDir>Alternate</BuildDir>
</PropertyGroup>

属性按其在项目中的显示顺序进行评估。 分配旧值后,必须声明 BuildDir 的新值。

预留属性

MSBuild 保留了一些属性名称,用于存储有关项目文件和 MSBuild 二进制文件的信息。 与其他属性一样,可使用 $ 符号引用这些属性。 例如,$(MSBuildProjectFile) 会返回项目文件的完整文件名,包括文件扩展名。

有关详细信息,请参阅如何:引用项目文件的名称或位置MSBuild 保留和常见属性

MSBuild 内部属性

在以下划线 (_) 开头的标准导入文件中定义的属性对 MSBuild 是专用属性,不应在用户代码中读取、重置或替代。

环境属性

可以引用项目文件中的环境变量,方法与引用保留属性相同。 例如,若要使用项目文件中的 PATH 环境变量,可使用 $(Path)。 如果项目包含与环境属性具有相同名称的属性定义,则项目中的属性将覆盖环境变量的值。

每个 MSBuild 项目都有一个独立环境块:它只能识别对自己块的读写操作。 在计算或生成项目文件之前,MSBuild 只在初始化属性集合时读取环境变量。 在此之后,环境属性是静态的,也就是说,每个生成工具使用相同的名称和值启动。

若要从生成工具中获取环境变量的当前值,请使用属性函数 System.Environment.GetEnvironmentVariable。 不过,首选方法是使用任务参数 EnvironmentVariables。 可将此字符串数组中的环境属性集传递给生成工具,而不影响系统环境变量。

提示

并非所有的环境变量都被读入并成为初始属性。 系统将忽略变量名称不是有效 MSBuild 属性名称的所有环境变量(例如“386”)。

有关详细信息,请参阅如何:在生成中使用环境变量

注册表属性

可使用以下语法读取系统注册表值,其中 Hive 是注册表配置单元(例如 HKEY_LOCAL_MACHINE),MyKey 是键名称,MySubKey 是子键名称,Value 是子键的值 。

$(registry:Hive\MyKey\MySubKey@Value)

若要获取默认的子键值,请省略 Value

$(registry:Hive\MyKey\MySubKey)

可以使用此注册表值初始化生成属性。 例如,若要创建一个表示 Visual Studio web 浏览器主页的生成属性,请使用此代码:

<PropertyGroup>
  <VisualStudioWebBrowserHomePage>
    $(registry:HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\14.0\WebBrowser@HomePage)
  </VisualStudioWebBrowserHomePage>
<PropertyGroup>

警告

在 .NET SDK 版本的 MSBuild (dotnet build) 中,不支持注册表属性。

在执行过程中创建属性

在生成的评估阶段会为 Target 元素外的属性分配值。 在后续执行阶段中,可按以下方式创建或修改属性:

  • 任何任务都可以发出属性。 若要发出属性,Task 元素必须具有含有 PropertyName 属性的 Output 子元素。

  • CreateProperty 任务可发出属性。 此用法已弃用。

  • Target 元素可能会包含 PropertyGroup 元素,后者可能会包含属性声明。

全局属性

借助 MSBuild,可使用 -property (或 -p )开关在命令行中设置属性。 这些全局属性值会覆盖项目文件中设置的属性值。 这包括环境属性,但不包括不能更改的保留属性。

以下示例将全局 Configuration 属性设置为 DEBUG

msbuild.exe MyProj.proj -p:Configuration=DEBUG

还可使用 MSBuild 任务的 Properties 属性为多项目生成中的子项目设置或修改全局属性。 除非使用 MSBuild 任务的 RemoveProperties 属性来指定不准备转发的属性列表,否则全局属性同样会转发到子项目。 有关详细信息,请参阅 MSBuild 任务

本地属性

可以在项目中重置局部属性。 但无法重置全局属性。 使用 -p 选项从命令行设置局部属性时,项目文件中的设置优先于命令行。

可以使用项目标记中的 TreatAsLocalProperty 特性指定局部属性。

下面的代码指定了两个局部属性:

<Project Sdk="Microsoft.Net.Sdk" TreatAsLocalProperty="Prop1;Prop2">

局部属性不会转发到多项目生成中的子项目。 如果在命令行上使用 -p 选项提供值,则子项目将获得全局属性的值,而不是父项目中更改的局部值,但子项目(或其任何导入)也可以使用自己的 TreatAsLocalProperty 来更改它。

局部属性示例

下面的代码示例演示了 TreatAsLocalProperty 的效果:

<!-- test1.proj -->
<Project TreatAsLocalProperty="TreatedAsLocalProp">
    <PropertyGroup>
        <TreatedAsLocalProp>LocalOverrideValue</TreatedAsLocalProp>
    </PropertyGroup>

    <Target Name="Go">
        <MSBuild Projects="$(MSBuildThisFileDirectory)\test2.proj" Targets="Go2" Properties="Inner=true" />
    </Target>

    <Target Name="Go2" BeforeTargets="Go">
        <Warning Text="TreatedAsLocalProp($(MSBuildThisFileName)): $(TreatedAsLocalProp)" />
    </Target>
</Project>
<!-- test2.proj -->
<Project TreatAsLocalProperty="TreatedAsLocalProp">
    <Target Name="Go2">
        <Warning Text="TreatedAsLocalProp($(MSBuildThisFileName)): $(TreatedAsLocalProp)" />
    </Target>
</Project>

假设生成 test1.proj 命令行,并为 TreatedAsLocalProperty 提供全局值 GlobalOverrideValue

dotnet msbuild .\test1.proj -p:TreatedAsLocalProp=GlobalOverrideValue

输出如下所示:

test1.proj(11,9): warning : TreatedAsLocalProp(test): LocalOverrideValue
test2.proj(3,9): warning : TreatedAsLocalProp(test2): GlobalOverrideValue

子项目将继承全局值,但父项目使用局部设置的属性。

局部属性和导入

如果在导入的项目上使用 TreatAsLocalProperty 特性,则考虑属性获取的值时,顺序很重要。

下面的代码示例演示了导入项目上 TreatAsLocalProperty 的效果:

<!-- importer.proj -->
<Project>
    <PropertyGroup>
        <TreatedAsLocalProp>FirstOverrideValue</TreatedAsLocalProp>
    </PropertyGroup>

    <Import Project="import.props" />

    <PropertyGroup>
        <TreatedAsLocalProp Condition=" '$(TrySecondOverride)' == 'true' ">SecondOverrideValue</TreatedAsLocalProp>
    </PropertyGroup>

    <Target Name="Go">
        <Warning Text="TreatedAsLocalProp($(MSBuildThisFileName)): $(TreatedAsLocalProp)" />
    </Target>
</Project>
<!-- import.proj -->
<Project TreatAsLocalProperty="TreatedAsLocalProp">
    <PropertyGroup>
        <TreatedAsLocalProp>ImportOverrideValue</TreatedAsLocalProp>
    </PropertyGroup>

    <!-- Here, TreatedAsLocalProp has the value "ImportOverrideValue"-->
</Project>

假设生成 importer.proj 并为 TreatedAsLocalProp 设置全局值,如下所示:

dotnet msbuild .\importer.proj -p:TreatedAsLocalProp=GlobalOverrideValue

输出为:

importer.proj(9,9): warning : TreatedAsLocalProp(importer.proj): GlobalOverrideValue

现在假设你使用属性 TrySecondOverride 进行构建以 true

dotnet msbuild .\importer.proj -p:TreatedAsLocalProp=GlobalOverrideValue -p:TrySecondOverride=true

输出为:

importer.proj(13,9): warning : TreatedAsLocalProp(importer.proj): SecondOverrideValue

示例显示,该属性在使用 TreatAsLocalProperty 特性的导入项目之后被视为局部属性,而不仅仅是在导入的文件内。 属性的值受全局替代值的影响,但仅在使用 TreatAsLocalProperty 的导入项目之前。

有关详细信息,请参阅 Project 元素 (MSBuild)如何:使用不同选项生成相同的源文件

属性函数

从 .NET Framework 版本 4 开始,可以使用属性函数来计算 MSBuild 脚本。 可在生成脚本中读取系统时间、比较字符串、匹配正则表达式及执行其他操作,而无需使用 MSBuild 任务。

可使用字符串(实例)方法来操作任何属性值,并且还可调用许多系统类的静态方法。 例如,可按如下所示将生成属性设置为当天的日期。

<Today>$([System.DateTime]::Now.ToString("yyyy.MM.dd"))</Today>

有关详细信息,以及属性函数的列表,请参阅属性函数

在属性中存储 XML

属性可包含任意 XML,这有助于将值传递给任务或显示日志记录信息。 以下示例介绍了 ConfigTemplate 属性,它具有一个包含 XML 和其他属性引用的值。 MSBuild 使用其相应属性值来替换属性引用。 属性值按其显示顺序进行分配。 因此,在此示例中,$(MySupportedVersion)$(MyRequiredVersion)$(MySafeMode) 应已定义。

<PropertyGroup>
    <ConfigTemplate>
        <Configuration>
            <Startup>
                <SupportedRuntime
                    ImageVersion="$(MySupportedVersion)"
                    Version="$(MySupportedVersion)"/>
                <RequiredRuntime
                    ImageVersion="$(MyRequiredVersion)"
                    Version="$(MyRequiredVersion)"
                    SafeMode="$(MySafeMode)"/>
            </Startup>
        </Configuration>
    </ConfigTemplate>
</PropertyGroup>