20

也许我在这里挑战极限,但我迫切希望利用 NuGet 来缓解我发现自己陷入的 DLL 地狱。

我们有 4 种主要产品,它们都存在于相互关联的 Mercurial 存储库中。他们所有人都“共享”了 3 个核心组件,然后其他所有内容都几乎是特定于产品的。现在管理起来变得非常困难,因为一个产品已经升级到 .NET 4.0 并且正在使用需要 .NET 4.0 的外部依赖项,而另一个产品由于我什至不想进入的原因被困在 .NET 3.5 中。

因此,我们失去了融合产品之间差异的能力。

为了修复它,我想取出 3 个主要程序集,并将它们变成具有自己发布周期的自己的项目,并注意确保它们可以针对 .NET 3.5 和 4.0 进行编译,然后将它们变成包含多个框架版本的 NuGet 包。

但是,我也希望开发人员能够浏览这些项目的来源。

所以我设置了一个私有 NuGet 服务器和一个私有 SymbolSource 服务器。然后我小心地将所有存储库中的所有更改合并在一起,并丢弃了除我的核心程序集之外的所有内容。然后我煞费苦心地手工编辑了 .csproj 文件,以便每个项目都有 3.5 和 4.0 的平台目标而不是 AnyCPU 平台,它们指定条件常量(用于控制特定于平台的功能,如 System.Dynamic)并设置框架版本。

然后我为“3.5 Debug”、“3.5 Release”、“4.0 Debug”和“4.0 Release”设置了解决方案配置。每一个都针对适当的配置(调试或发布)和平台(3.5 或 4.0)。

我可以在 Visual Studio 中为任何平台构建一切正常的东西。现在我在谈到 NuGet 时遇到了一个问题,因为有两种方法可以创建一个包,并且都有一个弱点,除非我遗漏了一些东西:

按项目文件打包

nuget pack MyProject.csproj -Build -Symbols -Version <insert-from-build-server> -Properties "Configuration=Release;Platform=3.5;"

这样做的问题是:

  • 在构建和打包 3.5 版本时,输出显示“为目标框架 '.NETFramework,Version=v4.0' 构建项目”。
  • 如果我解压缩生成的包,则程序集所在的位置lib\net40是错误的。
  • 我不认为有任何方法可以以这种方式打包 2 个框架目标,您必须以另一种方式使用文件夹和约定。
  • 我愿意接受您不能将框架打包在一起并制作 2 个名为 MyProject(我会做为 4.0)和 MyProject.V35 的包......但是我不知道如何拥有相同的项目和 nuspec并以不同的 id 结束 2 个不同的结果。

按 Nuspec 文件打包

使用这种方法,我必须自己完成所有的 msbuilding,然后进行一堆文件复制来设置文件夹结构,例如

* MyProject.nuspec
* net40
    * MyProject.dll
    * MyProject.pdb
* net35
    * MyProject.dll
    * MyProject.pdb

然后我可以运行nuget pack MyProject.nuspec,但是没有与符号一起使用的源,因为没有 .csproj 文件,NuGet 无法确定从哪里获取所有源文件,而且我没有看到任何有关如何操作的文档这也使用目录约定。

所以我的问题是:

  1. 有没有办法将源文件添加到基于约定的包中?
  2. 有没有办法用不同的 id 将基于项目的包打包两次?
  3. 还有其他可能我没有考虑过的途径吗?

任何想法将不胜感激。

4

3 回答 3

15

Xavier 的回答将我引向了正确的方向,也为我的 Google 搜索提供了信息。我并不完全了解文件声明,当沿着这些思路进行搜索时,我发现了 Joshua Flanagan 的帖子Tips for building NuGet packages,非常棒。Xavier 和 Joshua 一起教会了我一些事情:

  1. 您不必为了构建包而组装符合约定的文件树。使用 file 元素选择文件并将它们定位到组装的 NuGet 包中的目标目录要好得多。
  2. NuGet 的 -Symbols 标志不仅适用于打包 .csproj 文件。当您确实在文件上使用它时.csproj,当然,这就是它如何确定如何打包所有源文件的方式。但是您也可以通过文件元素在包含源-Symbols的文件上使用。.nuspec普通的 NuGet 包不会包含 src 目录,但 Symbols 包会包含。

所以现在,让我描述一下我的 CI 服务器上发生的构建过程:

  1. 使用“3.5 Release”解决方案配置构建解决方案。
  2. 使用“4.0 Release”解决方案配置构建解决方案。
  3. 使用 ILMerge.exe 内部化一些程序集。我有这些输出(例如)bin\Release-3.5\merged所以我不必在合并中使用它之前将目标程序集重命名为 temp.dll。
  4. .nuspec在 Powershell 中构建包。

这是打包命令:

nuget pack src\MyProject\MyProject.nuspec -OutputDirectory .\output -Build -Symbols -Version $Version

请注意,$Version 是从构建服务器传入的,因此我可以将其内部版本号用作版本的最后一部分。

这是 .nuspec 文件:

<?xml version="1.0"?>
<package>
    <metadata>
        <id>MyProject</id>
        <version>0.0.0</version>
        <title>MyProject</title>
        <authors>David Boike</authors>
        <owners>David Boike</owners>
        <requireLicenseAcceptance>false</requireLicenseAcceptance>
        <description>MyProject</description>
        <releaseNotes></releaseNotes>
        <copyright>Copyright 2012</copyright>
        <tags>my tags</tags>
    </metadata>
    <files>
        <file src="bin\Release-4.0\merged\MyProject.dll" target="lib\net40" />
        <file src="bin\Release-4.0\merged\MyProject.pdb" target="lib\net40" />
        <file src="bin\Release-4.0\MyProject.xml" target="lib\net40" />
        <file src="bin\Release-3.5\merged\MyProject.dll" target="lib\net35" />
        <file src="bin\Release-3.5\merged\MyProject.pdb" target="lib\net35" />
        <file src="bin\Release-3.5\MyProject.xml" target="lib\net35" />
        <file src="**\*.cs" target="src" />
    </files>
</package>

请注意,我已经从我的 nuspec 中删除了很多信息量更大的元素,因为这对于像这样的内部项目并不重要。

结果是我的私有 NuGet 服务器的一个包,其中包含 .NET 3.5 和 4.0 程序集的 DLL、PDB 和 XML 文档,然后是我的私有 SymbolServer 的单独符号包,其中包括上述所有内容以及源代码。使用NuGet 包资源管理器很容易查看,我强烈建议您下载它。

最后,我测试了所有内容,并使用symbolsource.org 上建议的 Visual Studio 设置(除了我自己的私有符号服务器),我能够调试代码并轻松进入源代码。

再次感谢 Xavier 带领我走上正确的道路!

于 2012-10-17T14:44:33.173 回答
8

你知道还有第三种选择吗?以 csproj 文件为目标时,它还将查找与您的项目文件同名的 nuspec 文件(myProject.csproj --> myProject.nuspec)。这意味着您可以通过将其定义到 nuspec 文件中来将额外的元数据添加到生成的包中,同时仍然以您的 csproj 文件为目标。本质上,您最终会得到一个包含来自您的 csproj 文件和 nuspec 文件的合并元数据的包。

在您的特定场景中,如果您想打包同一项目的多个平台构建,您确实必须先构建这些项目,然后再使用 nuspec 打包。

我建议您创建两个项目,一个针对 NET35,另一个针对 NET40,并将文件作为链接添加到其中一个项目中。因此,您可以构建这两个项目,并使用 nuspec 文件将所有输出打包到一个 NuGet 包中

现在对于符号,我认为您可以有第二个 nuspec 文件(例如 myProject.symbols.nuspec),您可以在其中使用通配符添加项目的所有内容(源等),类似于下面显示的内容。

<file src="myProject35\**\*.cs" target="src" />
<file src="myProject40\bin\Release\*.dll" target="lib\net40" />
<file src="myProject40\bin\Release\*.pdb" target="lib\net40" />
<file src="myProject35\bin\Release\*.dll" target="lib\net35" />
<file src="myProject35\bin\Release\*.pdb" target="lib\net35" />

希望这有助于或至少为您提供一些信息以找到出路:)

干杯,泽维尔

于 2012-10-12T22:02:58.327 回答
0

查看 NuGet 2.5 中与框架版本相关参考相关的新功能:http: //docs.nuget.org/docs/release-notes/nuget-2.5

您可以选择在 csproj 文件中使用带有条件引用元素的构建配置(TargetFrameworkVersion 上的条件),然后在所有配置中运行您的构建,并为 net35 和 net40 生成输出,并在您的 nupkg 中选择引用目标。

于 2013-05-02T08:56:37.497 回答