MSBuild - 属性/项的作用域/继承规则是什么?

3
我在我的工作MSBuild项目中有以下定义...
<MSBuild
        Projects="$(MSBuildProjectFile)"
        Condition="'@(FilesToCompile)' != ''"
        Targets="buildcpp"
        Properties="CPPFILE=%(FilesToCompile.FullPath);OBJFILE=$(ObjectFolder)\%(FilesToCompile.Filename).doj;IncludeDirs=$(IncludeDirs)"
    />

...接着是目标的定义。 注意目标的定义中包含对另一个目标compilecpp的调用...

<Target Name="buildcpp">
    <PropertyGroup>
        <CompileDefines Condition="'$(PreprocessorDefinitions)' != ''">-D$(PreprocessorDefinitions.Replace(";"," -D"))</CompileDefines>
    </PropertyGroup>
    <Exec
        EchoOff="true"
        StandardOutputImportance="low"
        StandardErrorImportance="low"
        IgnoreExitCode="true"
        ConsoleToMSBuild="true" 
        Command='
            "$(CompilerExe)" ^
                $(HWProcessor) ^
                $(IncludeDirs) ^
                $(CompilerOptions) ^
                $(CompileDefines) ^
                "$(CPPFILE)" ^
                -MM
    '>
        <Output TaskParameter="ConsoleOutput" PropertyName="output_cppdeps"/>
        <Output TaskParameter="ExitCode" PropertyName="exitcode_cppdeps"/>
    </Exec>

<MSBuild
        Projects="$(MSBuildProjectFile)"
    Condition="'$(exitcode_cppdeps)' == '0'"
        Targets="compilecpp"
        Properties="INPUTFILES=$(BuildCppDeps)"     
    />
</Target>

......尽管调用者从未传入,但它使用属性$(OBJFILE)

<Target Name="compilecpp" Inputs="$(INPUTFILES)" Outputs="$(OBJFILE)">
    <Message Importance="high" Text="$(CPPFILE): Compiling..."/>
...

问题

既然这个msbuild可以工作,那么我可以推断出$(OBJFILE)是可访问的;为什么它是可访问的?属性的范围规则是什么?


MSBuild/CallTarget任务继承所有全局属性。不确定它在官方文档中的确切位置,但例如在此处:https://blogs.msdn.microsoft.com/aaronhallberg/2007/07/16/msbuild-property-evaluation/。 - stijn
@stijn 你所说的“全局属性”是指在“MSBuild/CallTarget”调用时存在的所有属性吗? - Bob
是的。实际上,如果您使用诊断级别运行msbuild(命令行或任务),它将输出所有已知属性。这可能非常方便。 - stijn
1个回答

1
当使用 <MSBuild> 任务时,它执行一个新的 msbuild 运行,类似于使用带参数的 msbuild.exe 运行。特别是,传递属性类似于传递 /p:PropName=Value 参数-它为此运行定义了新的“全局属性”。
在这个内部构建过程中,该属性仍然存在,并且可以被其他内部构建(buildcpp->compilecpp)访问,除非被覆盖。因此,OBJFILE 仅在 compilecpp 中可访问,因为它被定义为父级 msbuild 运行的全局属性。如果以某种方式直接调用了 compilecpp,则该属性将不会被定义(假设它没有在其他地方设置)。当您想要停止转发全局属性时,您需要使用 MSBuild 任务的 RemoveProperties 参数。因此,如果您设置 RemoveProperties="OBJFILE",那么它就不会被传递。
顺便说一下,在 .NET Core 项目中,RemoveProperties 用于不将自包含应用程序的 RuntimeIdentifier 转发到可能无法使用此属性进行构建的引用项目(由于缺少还原信息)。

如需更多信息,请阅读属性文档,特别是关于全局属性的部分,并阅读MSBuild任务文档(重要部分是Properties参数的描述)。然而,全局属性被传递的事实并没有明确说明(尽管可以通过RemoveProperties推断出来)。

更新:全局属性文档已更新以描述此行为:

除非使用MSBuild任务的RemoveProperties属性指定不转发的属性列表,否则全局属性也会转发到子项目。


你知道这在官方文档中的哪里吗? - stijn
是的,我知道这些,但它们没有说明通过MSBuild任务(您所谓的“内部构建”)运行的项目是否继承父属性,对吧? - stijn
没错,它并没有说它们被转发了。但是RemoveProperties的文档暗示了这一点。非常有帮助 :( - 然而,这就是它的实现方式,也是将任何自定义属性传递到解决方案构建中始终有效的方法。 - Martin Ullrich
2
已为全球属性文档打开了 PR:https://github.com/MicrosoftDocs/visualstudio-docs/pull/343 - Martin Ullrich
好的,很好! - stijn

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