如何编写实用程序 msbuild 项目以使其依赖于 "real" C# 项目?
How to code a utility msbuild project so that it depends on a "real" C# project?
我所说的实用程序是指没有任何 C# 文件、不生成 .NET 程序集但实现了一些自定义构建逻辑的项目。
我可以将其安排为感兴趣的 C# 项目中的 AfterBuild 目标,但我不想增加该 C# 项目的构建时间。相反,我希望 msbuild 运行 此逻辑与该 C# 项目的其他依赖项并行。
一个解决方案是创建一个虚拟 C# 项目,该项目将真正构建一些虚拟代码并将我的逻辑放入 AfterBuild 目标中。但这很难看。
所以,这是我的解决方案(剧透警报 - 它不起作用):
目录结构
C:\work\u [master]> tree /F
Folder PATH listing for volume OSDisk
Volume serial number is F6C4-7BEF
C:.
│ .gitignore
│ Deployer.sln
│
├───Deployer
│ Deployer.csproj
│
├───DeploymentEngine
│ DeploymentEngine.csproj
│
└───Utility
Utility.csproj
C:\work\u [master]>
Deployer.csproj
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)$(MSBuildToolsVersion)\Microsoft.Common.props" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProjectGuid>{B451936B-54B7-41D1-A359-4B06865248CE}</ProjectGuid>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<OutputType>Library</OutputType>
<BaseOutputPath>bin</BaseOutputPath>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\DeploymentEngine\DeploymentEngine.csproj">
<Project>{901487BE-C604-4251-8485-3E96D5993145}</Project>
<Name>DeploymentEngine</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="TakeTime" AfterTargets="Build">
<Exec Command="powershell -NoProfile -Command Start-Sleep -Seconds 5" />
</Target>
</Project>
是的,这是一个遗留风格的项目,因为真正的解决方案是混合遗留和 SDK 风格的项目。
DeploymentEngine.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
</PropertyGroup>
<Target Name="TakeTime" AfterTargets="Build">
<Exec Command="powershell -NoProfile -Command Start-Sleep -Seconds 5" />
</Target>
</Project>
Utility.csproj
<Project>
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<EnableDefaultItems>False</EnableDefaultItems>
<GenerateAssemblyInfo>False</GenerateAssemblyInfo>
</PropertyGroup>
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
<Target Name="Build">
<Message Text="*** Good" Importance="high" Condition="Exists('..\DeploymentEngine\bin\Debug\net472\DeploymentEngine.dll')" />
<Message Text="*** Bad" Importance="high" Condition="!Exists('..\DeploymentEngine\bin\Debug\net472\DeploymentEngine.dll')" />
</Target>
<Target Name="Clean" />
<Target Name="Rebuild" DependsOnTargets="Clean;Build" />
<ItemGroup>
<ProjectReference Include="..\DeploymentEngine\DeploymentEngine.csproj" />
</ItemGroup>
</Project>
Deployer.sln
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31205.134
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Deployer", "Deployer\Deployer.csproj", "{B451936B-54B7-41D1-A359-4B06865248CE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DeploymentEngine", "DeploymentEngine\DeploymentEngine.csproj", "{901487BE-C604-4251-8485-3E96D5993145}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Utility", "Utility\Utility.csproj", "{9369D18D-D81D-4CA3-A287-C62C89BFB751}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B451936B-54B7-41D1-A359-4B06865248CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B451936B-54B7-41D1-A359-4B06865248CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B451936B-54B7-41D1-A359-4B06865248CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B451936B-54B7-41D1-A359-4B06865248CE}.Release|Any CPU.Build.0 = Release|Any CPU
{901487BE-C604-4251-8485-3E96D5993145}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{901487BE-C604-4251-8485-3E96D5993145}.Debug|Any CPU.Build.0 = Debug|Any CPU
{901487BE-C604-4251-8485-3E96D5993145}.Release|Any CPU.ActiveCfg = Release|Any CPU
{901487BE-C604-4251-8485-3E96D5993145}.Release|Any CPU.Build.0 = Release|Any CPU
{9369D18D-D81D-4CA3-A287-C62C89BFB751}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9369D18D-D81D-4CA3-A287-C62C89BFB751}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9369D18D-D81D-4CA3-A287-C62C89BFB751}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9369D18D-D81D-4CA3-A287-C62C89BFB751}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A70FF6AB-85B1-49F0-B2B0-25E20256A88F}
EndGlobalSection
EndGlobal
备注:
- 我人为地延迟了两个“真正的”C# 项目。
- Utility 项目在 运行 不在其声明的依赖项之后输出
*** Bad
,即不在 DeploymentEngine 项目之后。
现在让我们运行吧:
C:\work\u [master]> git clean -qdfx ; msbuild /v:m /restore /m
Microsoft (R) Build Engine version 16.11.0+0538acc04 for .NET Framework
Copyright (C) Microsoft Corporation. All rights reserved.
Determining projects to restore...
Restored C:\work\u\DeploymentEngine\DeploymentEngine.csproj (in 171 ms).
Restored C:\work\u\Utility\Utility.csproj (in 172 ms).
*** Bad
DeploymentEngine -> C:\work\u\DeploymentEngine\bin\Debug\net472\DeploymentEngine.dll
CSC : warning CS2008: No source files specified. [C:\work\u\Deployer\Deployer.csproj]
Deployer -> C:\work\u\Deployer\bin\Debug\Deployer.dll
C:\work\u [master]>
尽管声明了依赖于 DeploymentEngine 项目的意图,但输出表明首先构建了 Utility 项目。
注意,如果我 运行 构建单线程输出将是 *** Good
,所以输出逻辑确实工作正常:
C:\work\u [master]> git clean -qdfx ; msbuild /v:m /restore
Microsoft (R) Build Engine version 16.11.0+0538acc04 for .NET Framework
Copyright (C) Microsoft Corporation. All rights reserved.
Determining projects to restore...
Restored C:\work\u\Utility\Utility.csproj (in 172 ms).
Restored C:\work\u\DeploymentEngine\DeploymentEngine.csproj (in 172 ms).
DeploymentEngine -> C:\work\u\DeploymentEngine\bin\Debug\net472\DeploymentEngine.dll
CSC : warning CS2008: No source files specified. [C:\work\u\Deployer\Deployer.csproj]
Deployer -> C:\work\u\Deployer\bin\Debug\Deployer.dll
*** Good
C:\work\u [master]>
所以仅仅声明 ProjectReference
是不够的。看来我应该实施某种目标以使其发挥作用。
那我错过了什么?我应该添加什么来让 msbuild 知道 Utility 项目必须在 DeploymentEngine 之后构建?
编辑 1
我知道我可以在解决方案文件中设置依赖项。但是,由于各种原因,我不想这样做。
编辑 2
我的最终目标是在一个或多个“真正的”C# 项目之后 运行 拥有一个简单的实用程序项目。 IE。尽可能少的 .NET 构建导入。如果它可以有 .proj
扩展名,而不是 .csproj
- 最好。
我想知道为什么您不对实用程序项目使用 <Project Sdk="Microsoft.Net.Sdk"/>
并阅读 the docs 那是因为它会在其他所有内容的末尾隐式导入 Sdk.targets,从而覆盖你的 Build
目标。
我还没有想出具体的方法(现在没有更多时间,但我很确定应该可以有一个更简单的项目并且仍然让 ProjectReference 正常运行 - 将是声明正确的属性和目标的问题;这可能最终比仅仅在现有结构中乱搞更多的工作),但该目标是使 msbuild 尊重 ProjectReference 并保持正确的构建顺序的关键:除其他外,它取决于ResolveProjectReferences 是负责实际处理 ProjectReference 的目标。 Msbuild 本身对这些一无所知,其逻辑由 Microsoft.Common.CurrentVersion.targets.
提供
因此,简单地覆盖构建目标将使 ProjectReference 被完全忽略。解决方案在不使用 -m
时按所需顺序构建的唯一原因是实用程序项目排在最后。如果你在 .sln 中将它向上移动,msbuild 会更早地构建它并且它会打印'*** Bad'。
第一次尝试:Build
做了一个 lot 所以我想利用它只是为了你需要的东西,并保持它完好无损,其余的应该这样做。不是很干净,但可以:
<Project>
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<GenerateAssemblyInfo>False</GenerateAssemblyInfo>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\DeploymentEngine\DeploymentEngine.csproj">
</ProjectReference>
</ItemGroup>
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
<!-- Override Compile instead of Build, thereby also skipping
creating of Utility.dll -->
<Target Name="Compile">
<Message Text="*** Good" Importance="high" Condition="Exists('..\DeploymentEngine\bin\Debug\net472\DeploymentEngine.dll')" />
<Message Text="*** Bad" Importance="high" Condition="!Exists('..\DeploymentEngine\bin\Debug\net472\DeploymentEngine.dll')" />
</Target>
<!-- Empty so it doesn't try to copy the nonexisting Utility.dll. -->
<Target Name="CopyFilesToOutputDirectory" />
</Project>
第二次尝试:第一次尝试使用 Sdk.targets 等,这基本上是在说“我是一个完整的 .Net 项目”,因此采用了棘手的解决方法。更简单的方法是仅使用 CurrentVersion.Targets 中的内容,即 ResolveProjectReferences 目标来使 ProjectReference 工作,因此接近 'true' 实用程序项目(将其命名为 Utility.proj):
<Project>
<PropertyGroup>
<!-- ProjectReference requires the referenced project to have the same version -->
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<!-- Required for Microsoft.Common.CurrentVersion.targets -->
<OutputPath>bin</OutputPath>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\DeploymentEngine\DeploymentEngine.csproj">
</ProjectReference>
</ItemGroup>
<!-- For ResolveProjectReferences and everything it does -->
<Import Project="$(MSBuildBinPath)\Microsoft.Common.CurrentVersion.targets"/>
<Target Name="Build" DependsOnTargets="ResolveProjectReferences">
<Message Text="*** Good" Importance="high" Condition="Exists('..\DeploymentEngine\bin\Debug\net472\DeploymentEngine.dll')" />
<Warning Text="*** Bad" Condition="!Exists('..\DeploymentEngine\bin\Debug\net472\DeploymentEngine.dll')" />
</Target>
</Project>
我所说的实用程序是指没有任何 C# 文件、不生成 .NET 程序集但实现了一些自定义构建逻辑的项目。
我可以将其安排为感兴趣的 C# 项目中的 AfterBuild 目标,但我不想增加该 C# 项目的构建时间。相反,我希望 msbuild 运行 此逻辑与该 C# 项目的其他依赖项并行。
一个解决方案是创建一个虚拟 C# 项目,该项目将真正构建一些虚拟代码并将我的逻辑放入 AfterBuild 目标中。但这很难看。
所以,这是我的解决方案(剧透警报 - 它不起作用):
目录结构
C:\work\u [master]> tree /F
Folder PATH listing for volume OSDisk
Volume serial number is F6C4-7BEF
C:.
│ .gitignore
│ Deployer.sln
│
├───Deployer
│ Deployer.csproj
│
├───DeploymentEngine
│ DeploymentEngine.csproj
│
└───Utility
Utility.csproj
C:\work\u [master]>
Deployer.csproj
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)$(MSBuildToolsVersion)\Microsoft.Common.props" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProjectGuid>{B451936B-54B7-41D1-A359-4B06865248CE}</ProjectGuid>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<OutputType>Library</OutputType>
<BaseOutputPath>bin</BaseOutputPath>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\DeploymentEngine\DeploymentEngine.csproj">
<Project>{901487BE-C604-4251-8485-3E96D5993145}</Project>
<Name>DeploymentEngine</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="TakeTime" AfterTargets="Build">
<Exec Command="powershell -NoProfile -Command Start-Sleep -Seconds 5" />
</Target>
</Project>
是的,这是一个遗留风格的项目,因为真正的解决方案是混合遗留和 SDK 风格的项目。
DeploymentEngine.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
</PropertyGroup>
<Target Name="TakeTime" AfterTargets="Build">
<Exec Command="powershell -NoProfile -Command Start-Sleep -Seconds 5" />
</Target>
</Project>
Utility.csproj
<Project>
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<EnableDefaultItems>False</EnableDefaultItems>
<GenerateAssemblyInfo>False</GenerateAssemblyInfo>
</PropertyGroup>
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
<Target Name="Build">
<Message Text="*** Good" Importance="high" Condition="Exists('..\DeploymentEngine\bin\Debug\net472\DeploymentEngine.dll')" />
<Message Text="*** Bad" Importance="high" Condition="!Exists('..\DeploymentEngine\bin\Debug\net472\DeploymentEngine.dll')" />
</Target>
<Target Name="Clean" />
<Target Name="Rebuild" DependsOnTargets="Clean;Build" />
<ItemGroup>
<ProjectReference Include="..\DeploymentEngine\DeploymentEngine.csproj" />
</ItemGroup>
</Project>
Deployer.sln
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31205.134
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Deployer", "Deployer\Deployer.csproj", "{B451936B-54B7-41D1-A359-4B06865248CE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DeploymentEngine", "DeploymentEngine\DeploymentEngine.csproj", "{901487BE-C604-4251-8485-3E96D5993145}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Utility", "Utility\Utility.csproj", "{9369D18D-D81D-4CA3-A287-C62C89BFB751}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B451936B-54B7-41D1-A359-4B06865248CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B451936B-54B7-41D1-A359-4B06865248CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B451936B-54B7-41D1-A359-4B06865248CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B451936B-54B7-41D1-A359-4B06865248CE}.Release|Any CPU.Build.0 = Release|Any CPU
{901487BE-C604-4251-8485-3E96D5993145}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{901487BE-C604-4251-8485-3E96D5993145}.Debug|Any CPU.Build.0 = Debug|Any CPU
{901487BE-C604-4251-8485-3E96D5993145}.Release|Any CPU.ActiveCfg = Release|Any CPU
{901487BE-C604-4251-8485-3E96D5993145}.Release|Any CPU.Build.0 = Release|Any CPU
{9369D18D-D81D-4CA3-A287-C62C89BFB751}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9369D18D-D81D-4CA3-A287-C62C89BFB751}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9369D18D-D81D-4CA3-A287-C62C89BFB751}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9369D18D-D81D-4CA3-A287-C62C89BFB751}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A70FF6AB-85B1-49F0-B2B0-25E20256A88F}
EndGlobalSection
EndGlobal
备注:
- 我人为地延迟了两个“真正的”C# 项目。
- Utility 项目在 运行 不在其声明的依赖项之后输出
*** Bad
,即不在 DeploymentEngine 项目之后。
现在让我们运行吧:
C:\work\u [master]> git clean -qdfx ; msbuild /v:m /restore /m
Microsoft (R) Build Engine version 16.11.0+0538acc04 for .NET Framework
Copyright (C) Microsoft Corporation. All rights reserved.
Determining projects to restore...
Restored C:\work\u\DeploymentEngine\DeploymentEngine.csproj (in 171 ms).
Restored C:\work\u\Utility\Utility.csproj (in 172 ms).
*** Bad
DeploymentEngine -> C:\work\u\DeploymentEngine\bin\Debug\net472\DeploymentEngine.dll
CSC : warning CS2008: No source files specified. [C:\work\u\Deployer\Deployer.csproj]
Deployer -> C:\work\u\Deployer\bin\Debug\Deployer.dll
C:\work\u [master]>
尽管声明了依赖于 DeploymentEngine 项目的意图,但输出表明首先构建了 Utility 项目。
注意,如果我 运行 构建单线程输出将是 *** Good
,所以输出逻辑确实工作正常:
C:\work\u [master]> git clean -qdfx ; msbuild /v:m /restore
Microsoft (R) Build Engine version 16.11.0+0538acc04 for .NET Framework
Copyright (C) Microsoft Corporation. All rights reserved.
Determining projects to restore...
Restored C:\work\u\Utility\Utility.csproj (in 172 ms).
Restored C:\work\u\DeploymentEngine\DeploymentEngine.csproj (in 172 ms).
DeploymentEngine -> C:\work\u\DeploymentEngine\bin\Debug\net472\DeploymentEngine.dll
CSC : warning CS2008: No source files specified. [C:\work\u\Deployer\Deployer.csproj]
Deployer -> C:\work\u\Deployer\bin\Debug\Deployer.dll
*** Good
C:\work\u [master]>
所以仅仅声明 ProjectReference
是不够的。看来我应该实施某种目标以使其发挥作用。
那我错过了什么?我应该添加什么来让 msbuild 知道 Utility 项目必须在 DeploymentEngine 之后构建?
编辑 1
我知道我可以在解决方案文件中设置依赖项。但是,由于各种原因,我不想这样做。
编辑 2
我的最终目标是在一个或多个“真正的”C# 项目之后 运行 拥有一个简单的实用程序项目。 IE。尽可能少的 .NET 构建导入。如果它可以有 .proj
扩展名,而不是 .csproj
- 最好。
我想知道为什么您不对实用程序项目使用 <Project Sdk="Microsoft.Net.Sdk"/>
并阅读 the docs 那是因为它会在其他所有内容的末尾隐式导入 Sdk.targets,从而覆盖你的 Build
目标。
我还没有想出具体的方法(现在没有更多时间,但我很确定应该可以有一个更简单的项目并且仍然让 ProjectReference 正常运行 - 将是声明正确的属性和目标的问题;这可能最终比仅仅在现有结构中乱搞更多的工作),但该目标是使 msbuild 尊重 ProjectReference 并保持正确的构建顺序的关键:除其他外,它取决于ResolveProjectReferences 是负责实际处理 ProjectReference 的目标。 Msbuild 本身对这些一无所知,其逻辑由 Microsoft.Common.CurrentVersion.targets.
提供因此,简单地覆盖构建目标将使 ProjectReference 被完全忽略。解决方案在不使用 -m
时按所需顺序构建的唯一原因是实用程序项目排在最后。如果你在 .sln 中将它向上移动,msbuild 会更早地构建它并且它会打印'*** Bad'。
第一次尝试:Build
做了一个 lot 所以我想利用它只是为了你需要的东西,并保持它完好无损,其余的应该这样做。不是很干净,但可以:
<Project>
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<GenerateAssemblyInfo>False</GenerateAssemblyInfo>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\DeploymentEngine\DeploymentEngine.csproj">
</ProjectReference>
</ItemGroup>
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
<!-- Override Compile instead of Build, thereby also skipping
creating of Utility.dll -->
<Target Name="Compile">
<Message Text="*** Good" Importance="high" Condition="Exists('..\DeploymentEngine\bin\Debug\net472\DeploymentEngine.dll')" />
<Message Text="*** Bad" Importance="high" Condition="!Exists('..\DeploymentEngine\bin\Debug\net472\DeploymentEngine.dll')" />
</Target>
<!-- Empty so it doesn't try to copy the nonexisting Utility.dll. -->
<Target Name="CopyFilesToOutputDirectory" />
</Project>
第二次尝试:第一次尝试使用 Sdk.targets 等,这基本上是在说“我是一个完整的 .Net 项目”,因此采用了棘手的解决方法。更简单的方法是仅使用 CurrentVersion.Targets 中的内容,即 ResolveProjectReferences 目标来使 ProjectReference 工作,因此接近 'true' 实用程序项目(将其命名为 Utility.proj):
<Project>
<PropertyGroup>
<!-- ProjectReference requires the referenced project to have the same version -->
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<!-- Required for Microsoft.Common.CurrentVersion.targets -->
<OutputPath>bin</OutputPath>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\DeploymentEngine\DeploymentEngine.csproj">
</ProjectReference>
</ItemGroup>
<!-- For ResolveProjectReferences and everything it does -->
<Import Project="$(MSBuildBinPath)\Microsoft.Common.CurrentVersion.targets"/>
<Target Name="Build" DependsOnTargets="ResolveProjectReferences">
<Message Text="*** Good" Importance="high" Condition="Exists('..\DeploymentEngine\bin\Debug\net472\DeploymentEngine.dll')" />
<Warning Text="*** Bad" Condition="!Exists('..\DeploymentEngine\bin\Debug\net472\DeploymentEngine.dll')" />
</Target>
</Project>