通过 MSBuild 目标解决 .NET 4.7 外部项目 NuGet 依赖关系
Resolve .NET 4.7 external project NuGet dependencies via MSBuild targets
我们需要构建这些项目,它们有一些奇怪的做法。它们依赖于作为另一个项目构建过程的结果生成的链接代码文件。这些项目位于一个子文件夹中。
因此,在构建我们的项目之前,我们需要构建子项目。这是通过将自定义构建目标添加到每个项目的 BeforeBuild 目标来完成的,并且似乎有效。但是,如果不恢复 NuGet 依赖项,子项目将无法构建。
澄清一下:我们知道这种模式完全是疯子,但我们没有人力来重构使用这种模式的每个项目。我们只是想让它们一步到位地进行可靠编译。
这些外部项目依赖项中的每一个都列在自定义 ItemGroup 中,如下所示:
<ItemGroup>
<ExternalDependantProjects Include= "..\<subfolder>\<project>\<project>.csproj" />
</ItemGroup>
我们一直在尝试通过添加由每个项目的 BeforeBuild 目标调用的自定义构建目标来解决这个问题。我们首先尝试使用 ResolveNuGetPackageAssets 作为构建目标,但发现这仅在 netcore 中受支持,而我们的目标是 net47。
现在我们正在尝试编写一个自定义构建目标,它将恢复外部项目中的 NuGet 依赖项。我们已经尝试了直接的方法,像这样:<Exec Command="nuget restore @(ExternalDependantProjects)" />
和一个更复杂和 hacky 的 PowerShell 尝试:<Exec Command="powershell.exe -command "'@(ExternalDependantProjects, '' '')' | foreach { nuget restore $_ }"" />
在这两种情况下,它只是尝试恢复主项目的包,而不是外部项目。 @(ExternalDependantProjects) 似乎等于空白,因此没有添加新参数。使用表明 @(ExternalDependantProjects) returns 什么都没有。但是,当我们调用 MSBuild "Build" 目标时,它确实用作 "Projects" 参数。所以,我怀疑我们以错误的方式使用了 Item 参数?也许有一些语法可以访问 Item?
的 Include 属性
但是,如果我们能够解决该问题,我不确定它是否会奏效。我们在子项目上使用 nuget restore 命令进行了测试,总是得到 packages.conf 中的所有包都已安装的响应。然而,来自该外部项目的 ..\packages\ 是空的并且 packages.conf 指定了六个包(它们在 VS 中的 "References" 中也丢失了并且引用的 HintPath 正确地转到 ..\packages ).
所以我们在三个方面感到困惑:我们如何引用 ExternalDependentProjects 项包含来自 MSBuild 目标的路径,为什么 NuGet 恢复 CLI 无法工作,这是否是解决此问题的正确方法问题?我们是不是走错了路?
NuGet 发现 packages.config 个要从解决方案文件恢复的项目。如果所有项目都在解决方案文件中并且您 运行 nuget.exe restore <solution file>
它们应该得到恢复,无论项目文件中发生了什么。
作为任何自定义方案的解决方法,您可以编写一个脚本来发现文件夹中的所有 packages.config 文件,然后直接对这些文件调用 nuget.exe restore <packages.config> -SolutionDirectory <solution root>
。对于 packages.config 恢复,唯一需要的部分是从 packages.config 文件中发现 id/versions 的列表,以便可以将它们下载并提取到解决方案级别的包文件夹中。
我还建议将项目引用与 ReferenceOutputAssembly=false
一起使用,以确保项目按照您想要的顺序构建,并且不会相互引用。参见:https://blogs.msdn.microsoft.com/kirillosenkov/2015/04/04/how-to-have-a-project-reference-without-referencing-the-actual-binary/
How do we reference the the ExternalDependentProjects Item include path from MSBuild targets, why won't the NuGet restore CLI work, and is this even the correct way to go about solving this problem? Have we gone down completely the wrong avenue?
您应该使用选项 -OutputDirectory
编写自定义构建目标,因此自定义构建目标应如下所示:
<Target Name="BeforeBuild">
<Exec Command="nuget restore @(ExternalDependantProjects) -OutputDirectory ..\<subfolder>\packages" />
</Target>
有了这个目标,外部项目的 NuGet 包将成功恢复。
此外,@(ExternalDependantProjects)
的值不等于空白,你可以使用一个目标回显这个值。
下面是我的测试样本,你可以参考一些详细信息:
ExternalpProject
为子文件夹名称,TestExternalProject
为外部项目名称。
<ItemGroup>
<ExternalDependantProjects Include= "..\ExternalpProject\TestExternalProject\TestExternalProject.csproj" />
</ItemGroup>
<Target Name="BeforeBuild">
<Message Text="Restore package for Externalp Project" Importance="high"></Message>
<Exec Command="nuget restore @(ExternalDependantProjects) -OutputDirectory ..\ExternalpProject\packages" />
</Target>
<Target Name="AfterBuild">
<Message Text="Display the value of ExternalDependantProjects" Importance="high"></Message>
<Message Text="@(ExternalDependantProjects)"></Message>
</Target>
我们需要构建这些项目,它们有一些奇怪的做法。它们依赖于作为另一个项目构建过程的结果生成的链接代码文件。这些项目位于一个子文件夹中。
因此,在构建我们的项目之前,我们需要构建子项目。这是通过将自定义构建目标添加到每个项目的 BeforeBuild 目标来完成的,并且似乎有效。但是,如果不恢复 NuGet 依赖项,子项目将无法构建。
澄清一下:我们知道这种模式完全是疯子,但我们没有人力来重构使用这种模式的每个项目。我们只是想让它们一步到位地进行可靠编译。
这些外部项目依赖项中的每一个都列在自定义 ItemGroup 中,如下所示:
<ItemGroup>
<ExternalDependantProjects Include= "..\<subfolder>\<project>\<project>.csproj" />
</ItemGroup>
我们一直在尝试通过添加由每个项目的 BeforeBuild 目标调用的自定义构建目标来解决这个问题。我们首先尝试使用 ResolveNuGetPackageAssets 作为构建目标,但发现这仅在 netcore 中受支持,而我们的目标是 net47。
现在我们正在尝试编写一个自定义构建目标,它将恢复外部项目中的 NuGet 依赖项。我们已经尝试了直接的方法,像这样:<Exec Command="nuget restore @(ExternalDependantProjects)" />
和一个更复杂和 hacky 的 PowerShell 尝试:<Exec Command="powershell.exe -command "'@(ExternalDependantProjects, '' '')' | foreach { nuget restore $_ }"" />
在这两种情况下,它只是尝试恢复主项目的包,而不是外部项目。 @(ExternalDependantProjects) 似乎等于空白,因此没有添加新参数。使用表明 @(ExternalDependantProjects) returns 什么都没有。但是,当我们调用 MSBuild "Build" 目标时,它确实用作 "Projects" 参数。所以,我怀疑我们以错误的方式使用了 Item 参数?也许有一些语法可以访问 Item?
的 Include 属性但是,如果我们能够解决该问题,我不确定它是否会奏效。我们在子项目上使用 nuget restore 命令进行了测试,总是得到 packages.conf 中的所有包都已安装的响应。然而,来自该外部项目的 ..\packages\ 是空的并且 packages.conf 指定了六个包(它们在 VS 中的 "References" 中也丢失了并且引用的 HintPath 正确地转到 ..\packages ).
所以我们在三个方面感到困惑:我们如何引用 ExternalDependentProjects 项包含来自 MSBuild 目标的路径,为什么 NuGet 恢复 CLI 无法工作,这是否是解决此问题的正确方法问题?我们是不是走错了路?
NuGet 发现 packages.config 个要从解决方案文件恢复的项目。如果所有项目都在解决方案文件中并且您 运行 nuget.exe restore <solution file>
它们应该得到恢复,无论项目文件中发生了什么。
作为任何自定义方案的解决方法,您可以编写一个脚本来发现文件夹中的所有 packages.config 文件,然后直接对这些文件调用 nuget.exe restore <packages.config> -SolutionDirectory <solution root>
。对于 packages.config 恢复,唯一需要的部分是从 packages.config 文件中发现 id/versions 的列表,以便可以将它们下载并提取到解决方案级别的包文件夹中。
我还建议将项目引用与 ReferenceOutputAssembly=false
一起使用,以确保项目按照您想要的顺序构建,并且不会相互引用。参见:https://blogs.msdn.microsoft.com/kirillosenkov/2015/04/04/how-to-have-a-project-reference-without-referencing-the-actual-binary/
How do we reference the the ExternalDependentProjects Item include path from MSBuild targets, why won't the NuGet restore CLI work, and is this even the correct way to go about solving this problem? Have we gone down completely the wrong avenue?
您应该使用选项 -OutputDirectory
编写自定义构建目标,因此自定义构建目标应如下所示:
<Target Name="BeforeBuild">
<Exec Command="nuget restore @(ExternalDependantProjects) -OutputDirectory ..\<subfolder>\packages" />
</Target>
有了这个目标,外部项目的 NuGet 包将成功恢复。
此外,@(ExternalDependantProjects)
的值不等于空白,你可以使用一个目标回显这个值。
下面是我的测试样本,你可以参考一些详细信息:
ExternalpProject
为子文件夹名称,TestExternalProject
为外部项目名称。
<ItemGroup>
<ExternalDependantProjects Include= "..\ExternalpProject\TestExternalProject\TestExternalProject.csproj" />
</ItemGroup>
<Target Name="BeforeBuild">
<Message Text="Restore package for Externalp Project" Importance="high"></Message>
<Exec Command="nuget restore @(ExternalDependantProjects) -OutputDirectory ..\ExternalpProject\packages" />
</Target>
<Target Name="AfterBuild">
<Message Text="Display the value of ExternalDependantProjects" Importance="high"></Message>
<Message Text="@(ExternalDependantProjects)"></Message>
</Target>