【问题标题】:Multi-framework NuGet build with symbols for internal dependency management多框架 NuGet 构建,带有用于内部依赖管理的符号
【发布时间】:2012-10-12 21:41:45
【问题描述】:

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

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

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

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

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

所以我设置了一个private NuGet server 和一个private SymbolSource server。然后我小心地将所有存储库中的所有更改合并在一起,并丢弃了除了我的核心程序集之外的所有内容。然后我煞费苦心地手工编辑了 .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 版本时,输出显示“Building project for target framework '.NETFramework,Version=v4.0'。”
  • 如果我解压生成的包,程序集在lib\net40 下,这是错误的。
  • 我认为没有办法以这种方式打包 2 个框架目标,您必须使用文件夹和约定以另一种方式进行打包。
  • 我愿意接受您不能将框架打包在一起并制作 2 个名为 MyProject(我将作为 4.0 执行)和 MyProject.V35 的包......但是我不知道如何拥有相同的project 和 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. 还有其他可能我没有考虑过的途径吗?

任何想法将不胜感激。

【问题讨论】:

  • 我所有的赞成票 - 拿走他们!拿走他们!

标签: nuget nuget-package multiplatform


【解决方案1】:

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

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

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

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

这里是打包命令:

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 Package Explorer 查看,我强烈推荐您下载。

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

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

【讨论】:

    【解决方案2】:

    你知道有第三个​​选项吗? 以 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" />
    

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

    干杯, 泽维尔

    【讨论】:

    • 当您建议创建两个项目时,您是在说 MyProject.v35.csproj 和 MyProject.v40.csproj,两者都引用了所有 .cs 文件?这些项目包含大量代码文件,我真的希望避免让它们保持同步的管理噩梦。
    • 是的.. 2 个项目 MyProject.v35.csproj 和 MyProject.v40.csproj。将现有项目从一个项目添加到另一个项目时,请使用“添加为链接”。这确实是一个设置,但之后您只需要跟踪从项目中同步新添加或删除的文件。对链接项目的修改会被两个项目拾取,因为它们指向相同的文件。
    • 在某些情况下,您甚至不必跟踪文件并“将它们添加为链接”。在我的工作空间中,我创建了一个我一直使用的中心项目。此项目针对最新版本的 .NET 框架。其他版本的 .NET 框架的项目只需使用 MSBuild 的通配符功能从同一目录添加所有 *.cs 文件:&lt;Compile Include="$(MSBuildProjectDirectory)\**\*.cs" Exclude="$(MSBuildProjectDirectory)\**\obj\**" /&gt;
    • 仅供参考 - Control-Shift-Drag'n'Drop 在项目之间复制文件作为链接
    • @pomeroy 新的 csproj 格式可以处理 glob 文件模式,即 而不是每个文件的一行。使拥有 2 个 csproj 文件变得容易得多,这两个文件都包含(大部分)相同的文件集,但构建它们的方式不同。 natemcmaster.com/blog/2017/03/09/vs2015-to-vs2017-upgrade/…
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 2012-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-03
      • 1970-01-01
      • 2015-05-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多