Msbuild 将生成标识为由依赖项目引用引起

Msbuild 将生成标识为由依赖项目引用引起,msbuild,Msbuild,在MSBuild中是否存在一个属性或其他机制,表明当前项目正在生成,因为它被另一个项目引用?除了@stijn的答案之外,我发现您还可以防止将属性传递给依赖项目 例如,您可以通过将Web项目依赖项的更新为包含DeployOnBuild来防止使用顶级项目生成Web项目依赖项。或者,要根据其他属性自动执行此操作: <PropertyGroup Condition="'$(DisableProjectReferenceDeployOnBuild)'=='true'"> <Befor

在MSBuild中是否存在一个属性或其他机制,表明当前项目正在生成,因为它被另一个项目引用?

除了@stijn的答案之外,我发现您还可以防止将属性传递给依赖项目

例如,您可以通过将Web项目依赖项的
更新为包含
DeployOnBuild
来防止使用顶级项目生成Web项目依赖项。或者,要根据其他属性自动执行此操作:

<PropertyGroup Condition="'$(DisableProjectReferenceDeployOnBuild)'=='true'">
  <BeforeResolveReferences>
    $(BeforeResolveReferences);
    DisableProjectReferenceDeployOnBuild
  </BeforeResolveReferences>
</PropertyGroup>

<Target Name="DisableProjectReferenceDeployOnBuild">
  <ItemGroup>
    <_ProjectReferencesTmp Include="@(ProjectReferences)" />
    <ProjectReferences Remove="@(ProjectReferences)" />
    <ProjectReferences Include="@(_ProjectReferencesTmp)">
      <GlobalPropertiesToRemove>%(GlobalPropertiesToRemove);DeployOnBuild</GlobalPropertiesToRemove>
    </ProjectReferences>
  </ItemGroup>
</Target>

$(引用前);
DisableProjectReferenceDeployOnBuild
%(全局属性删除);部署构建

(我不会将此标记为答案,因为它不会直接回答我提出的问题)

环顾四周后,这似乎不可能使用内置功能。从一个角度来看,这是有意义的:为什么一个项目必须知道它是由用户直接构建的,还是作为依赖项构建的?MSBuild团队可能也遵循了这一逻辑:MSBuild中有很多扩展点,但不适合这样做

两个问题:构建依赖项目的代码只是使用MSBuild任务,没有提供传递属性的方法。但即使这样,它也只能在从命令行构建时工作,而不是在VS中,因此它不是一个“完整”的解决方案。下面是一个取自ResolveProjectReferences的片段,它构建了依赖项目:

<!--
    Build referenced projects when building from the command line.
    -->
<MSBuild
    Projects="@(_MSBuildProjectReferenceExistent)"
    Targets="%(_MSBuildProjectReferenceExistent.Targets)"
    BuildInParallel="$(BuildInParallel)"
    Properties="%(_MSBuildProjectReferenceExistent.SetConfiguration); %(_MSBuildProjectReferenceExistent.SetPlatform)"
    Condition="'%(_MSBuildProjectReferenceExistent.BuildReference)' == 'true' and '@(ProjectReferenceWithConfiguration)' != '' and '$(BuildingInsideVisualStudio)' != 'true' and '$(BuildProjectReferences)' == 'true' and '@(_MSBuildProjectReferenceExistent)' != ''"
    ContinueOnError="$(ContinueOnError)"
    RemoveProperties="%(_MSBuildProjectReferenceExistent.GlobalPropertiesToRemove)">
  ...
</MSBuild>

...
所以,没有办法在这里添加属性。尽管如您所想,您可以通过设置ProjectReference的GlobalPropertiesToRemove来删除属性;这取决于你在追求什么,这可能是有价值的

对于其他人来说,剩下的选择不多了;您可以指定使用的目标:MSBuildProjectReferenceExistence.Targets设置为$(ProjectReferenceBuildTargets),这样您就可以覆盖调用的目标,但是您需要所有可能是依赖项目的项目声明一个自定义目标(这反过来也会调用生成目标,以便不破坏目标)。可行,但不好,也不是问题的直接答案。其他解决方案也是如此:您可以通过复制整个ResolveProjectReferences目标并在上面显示的代码段中添加属性来覆盖它(对于任何可能具有依赖项目的项目)


但正如前面所说的(如上面代码片段中的条件所示):在构建VS时,这些可能的解决方案都不适用。我不知道这到底是为什么或如何工作的,但是如果A依赖于B,而你在VS中构建了A,它发现B已经过时了,它就在构建A之前为它启动了一个构建,我不知道有什么标准的方式与之交互。

取决于你对“正在构建”的定义。当项目A引用项目B时,实际上会使用不同的目标对项目B多次调用msbuild。对于实际构建目标,无法将其与正常构建区分开来(至少我所知,在使用标准VS生成的项目文件时,没有一个是这样的:查看诊断构建输出,所有内容都完全相同)。对于其他目标(GetNativeManifest、GetCopyToOutputDirectoryItems),您可能会假定它们仅在生成项目时被调用,因为它是被引用的。@stijn谢谢,这确实是我要找的生成目标,但很高兴知道。如果你加上这个作为回答,我会接受的。@stijn出于兴趣。您是否可以将其他属性传递给依赖项目,而不将该属性传递给条目项目?(例如,通过向某个项目添加一些元数据)看起来不像这样,只传递了配置和平台,但没有可连接的扩展点。您可以覆盖生成的目标(例如,您可以让它生成“MyBuild”或其他版本,而不是默认的目标)。或者可以在主项目中完全覆盖ResolveProjectReferences目标。但这些解决方案都不是理想的。更糟糕的是,这只适用于命令行构建。我没有检查,但我认为在VS中构建是不同的。现在没有时间,但我明天会核实并准备答案。