【问题标题】:Best practices with Nuget: Debug or Release?Nuget 的最佳实践:调试还是发布?
【发布时间】:2012-11-09 09:50:36
【问题描述】:

目前,我使用 Nuget 将发布版本打包到 nuget.org,但我使用 Nuget 打包调试版本,以便将符号源推送到 symbolsource.org。

编辑:(Jon Skeet,对 Noda Time 开发有一些偏见)

NuGet 现在支持推送到 NuGet 库 symbolsource.org(或类似服务器)as documented。不幸的是,这里有两个相互矛盾的要求:

  • 当只是使用一个库而不需要调试时,你真的想要一个发布版本。毕竟,这就是发布版本的用途。
  • 当出于诊断目的调试库时,您确实需要禁用所有适当优化的调试版本。毕竟,这就是调试版本的用途。

这很好,但 NuGet 不允许(据我所知)以有用的方式在同一个包中发布发布和调试版本。

所以,选择是:

  • 将调试版本分发给每个人(如文档中的示例所示),并接受任何规模和性能影响。
  • 将发布版本分发给所有人,调试体验略有下降。
  • 采用非常复杂的分发策略,可能会提供单独的发布和调试包。

前两个确实归结为调试和发布版本之间差异的影响......尽管值得注意的是,因为想要检查某些行为而想要进入库的代码之间也存在很大差异,并且想要调试库的代码,因为您认为自己发现了错误。在第二种情况下,最好将库的代码作为 Visual Studio 解决方案并以这种方式进行调试,因此我不会过多注意这种情况。

我的诱惑是只保留发布版本,期望相对很少有人需要调试,而那些这样做的人不会受到影响太多 通过发布版本中的优化。 (无论如何,JIT 编译器都会进行大部分优化。)

那么,还有其他我们没有考虑过的选择吗?是否还有其他因素可以打破平衡?将 NuGet 包推送到 SymbolSource 是否足够新,以至于“最佳实践”真的还没有建立?

【问题讨论】:

  • 我正要问同样的问题 - 虽然目前我也正在将发布配置推送到符号源,因为我只是使用 nuget pack ... -Symbol 并推送生成的包......跨度>
  • 我觉得我应该将此 Q/A 会议提交给 NuGet 背后的人,看看他们是否可以参与其中。
  • 烘焙登录到你的包,然后只发布发布版本。您可以允许记录器注入,这将使消费者可以根据自己的喜好设置记录。

标签: visual-studio debugging release nuget


【解决方案1】:

对于 SymbolSource,我认为最佳做法是:

  1. 仅将发布的二进制+内容包推送到 nuget.org(或任何其他生产源)
  2. 将调试二进制+内容包推送到开发提要:
    • 内部部署
    • 在 myget.org 上
    • 在 nuget.org 上作为预发布包。
  3. 将发布和调试二进制+符号包推送到 symbolsource.org 或任何其他符号存储。

虽然我们在这里,但一个常见的误解是 .NET 中的发布和调试版本确实存在很大差异,但我假设这里存在差异,因为两种版本中可能包含也可能不包含的各种代码,例如 Debug.Asserts。

也就是说,将这两种配置都推送到 SymbolSource 确实值得,因为您永远不知道何时需要调试生产代码。远程生产使其更难。发生这种情况时,您将需要从您的工具中获得的帮助。我显然不希望任何人这样做。

关于版本控制还有一个问题需要考虑:让 2 个不同的包(在调试和发布中构建)共享 1 个版本号是否正确? SymbolSource 会接受这一点,因为它提取包并将二进制文件存储在单独的构建模式分支中,如果仅允许 NuGet 相应地标记包。目前无法确定一个包是调试模式还是发布模式。

【讨论】:

  • “将两个构建发布到 NuGet”部分是棘手的部分。我总是发布 Noda Time 的 Release 版本,理由是我必须在两者之间做出选择。 (我有一个 nuspec 文件,而不是仅从 C# 项目中进行。)您提到调试生产代码好像仅使用发布版本要困难得多-尽管之前的“它们没有太大区别”部分。我知道调试版本中的 NOP,显然是Debug.Assert 等 - 但是你可以扩展(在你的答案中)调试时的含义吗?使用 Release 版本有多糟糕?
  • 我的意思是您希望为所有正在使用的二进制文件提供可用的符号:如果同时存在调试和发布版本,您将希望为两者提供符号。它们不需要在代码方面有太大差异,但它们会在校验和上有所不同,这使得加载符号在没有一些黑客攻击的情况下是不可能的。
  • 对。我可能的解决方案是 发布 Release 二进制文件,但我担心这会对调试造成多大影响。例如,没有 NOP 是否意味着不能添加断点?
  • 问题更多在于 JIT 优化而不是构建时优化。因此,如果您推送发布模式包并建议在需要调试时使用 COMPLUS_ZapDisable=1,那对我来说已经足够了。 NuGet 仍然应该允许以某种方式一起调试和发布。
  • 我不知道 symbolssource.org 存在。作为一种痒,我有很多次需要抓挠,我欢迎它。
【解决方案2】:

自 OP 的帖子以来已经 8 年了(之前的答案仍然在下面投票最高),所以我会用现在使用的东西来破解它。

有两种方法可以“进入”一个 NuGet 包:

1. PDB 分布

.symbols.nupkg 符号包是considered as legacy,并已被发布到Symbol Server.snupkg 包替换。大多数供应商都支持它,Azure DevOps 是最大的局外人,feature request 仍处于“审查中”(感谢 @alv 提供链接)。

这里是official instructions。只需将这两行添加到 csproj 文件中:

<PropertyGroup>
  <IncludeSymbols>true</IncludeSymbols>
  <SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>

在消费者方面,确保您的 IDE 已针对 NuGet.org(或 Azure 等)符号服务器进行了配置,以便在调试时允许 stepping into package code

2。 Source Link.Linking 实际代码

在某些情况下,由于 MSIL/JIT 优化,PDB 可能会隐藏源代码的某些细节。所以有一种方法可以在调试时“进入”你的 NuGet 的实际源代码。它被 .NET 基金会称为 Source Link——“一个语言和源代码控制无关的系统,用于为二进制文件提供源代码调试体验”。

Visual Studio 15.3+ 和所有主要供应商都支持它(也支持私有存储库)。

设置很简单 (official docs) – 只需在项目文件中添加一个开发依赖项(取决于您的 repo 的类型)以及一些标志:

<PropertyGroup>
    <PublishRepositoryUrl>true</PublishRepositoryUrl>
    <EmbedUntrackedSources>true</EmbedUntrackedSources>
</PropertyGroup>
<ItemGroup>
  <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>

在“5 steps to better NuGet package”中查看有关此主题的更多信息。

【讨论】:

【解决方案3】:

我完全同意你的结论。带有 RELEASE 的 NuGet 包和带有调试功能的 SymbolSource。直接进入包似乎很少见,启用优化的偶尔调试失误可能是可以接受的。

如果真的有问题,我认为理想的解决方案是让 NuGet 支持它。例如,假设在调试时,它可以将发布 DLL 替换为 SymbolSource 包中包含的那个。

理想情况下,随后会发生的情况是 nuget pack SomePackage -Symbols 针对发布版本会创建一个发布 nuget 包,但会创建一个调试符号包。并且 VS 插件将更新为足够智能,以便在调试器中运行时查看关联并拉入调试程序集并加载它们。有点疯狂,但会很有趣。

但是,我只是没有看到足够多的人抱怨这一点,目前值得这样做。

NuGet 团队接受拉取请求。 :)

【讨论】:

  • 我不确定我是否理解您的第二句话 - 我怀疑 OP(在我编辑之前)正在手动推送到 SymbolSource 以进行调试构建。如果 release 版本的 PDB 最终出现在 SymbolSource 而不是调试版本中,您是否设想过重大问题?还是那是您所提倡的,而我只是误解了?
  • “但是,我只是没有看到足够多的人抱怨这一点,所以目前值得这样做。”也许他们没有抱怨,但是如果您询问一些用户对此的看法,我敢打赌,您会发现大多数人会承认在这个特定步骤中有些困惑(发布到 NuGet.org 和 SymbolSource 的内容) .org)。如果你问他们最终选择了什么,你可能会发现没有统一的做法,每个人都做自己的事。
  • 我想投诉这个,我在哪里注册?
  • 一旦你有了内部 NuGet 并开始将它们部署到符号服务器......你不可避免地会想要调试它们......即使你可以逐​​步完成代码,你也会结束加上“无法获得局部变量或参数的值......它已被优化掉”。正如菲尔提到的......如果 nuget 有办法在调试模式下加载调试 dll 并在发布模式下发布 dll(来自 nuget 包),这将是终极的。在那之前,我们一直使用Nuget package switcher
  • 我同意,这将是一个很好的产品增强功能。
【解决方案4】:

Creating and Publishing A Symbol Package 中的示例引用了 Debug 目录中的文件作为 dll 和 pdb 文件的源。

指定符号包内容

符号包可以按照约定从按照上一节中描述的方式构建的文件夹构建,或者可以使用文件部分指定其内容。如果你想构建前面描述的示例包,你可以把它放到你的 nuspec 文件中:

<files>
  <file src="Full\bin\Debug\*.dll" target="lib\net40" /> 
  <file src="Full\bin\Debug\*.pdb" target="lib\net40" /> 
  <file src="Silverlight\bin\Debug\*.dll" target="lib\sl40" /> 
  <file src="Silverlight\bin\Debug\*.pdb" target="lib\sl40" /> 
  <file src="**\*.cs" target="src" />
</files>

由于发布符号的目的是允许其他人在调试时单步调试您的代码,因此发布用于调试的代码版本似乎最谨慎的做法是不进行可能影响代码单步调试的优化。

【讨论】:

  • 是的,这就是 example 所做的——但我宁愿不以调试的能力结束大多数开发人员只运行发布版本的愿望。据我所知,问题在于 NuGet 无法同时发布发布版本和调试版本。 (同时发布这两个版本对我来说也会有点痛苦,因为这意味着为签名的调试版本创建另一组配置......)
  • 这里我们进入一点主观性。通常,我对“最佳实践”的选择将是作者明确或暗示推荐的,因为我认为他们比我有更多的洞察力(或监督,在假设最终出现在示例中的情况下)。就个人而言,我认为这些符号应该与我使用的版本相匹配。我通常不会使用我认为可能必须调试的包,除非源代码是公开的并且如果需要我可以从头开始编译,因此缺少打包的调试版本并不是特别重要。
  • 在我的情况下,如果有人需要调试 Noda Time,因为他们认为 Noda Time 中存在错误,他们最好下载源代码(当然,他们可以这样做)。但是,能够单步进入 Noda Time 源代码以查看发生了什么仍然很有用。基本上我认为有(至少)两种不同的调试场景,不同的解决方案......
  • 我喜欢考虑的一件事是 .NET 本身:我认为可以肯定地说 Microsoft 发布发布版本而不是调试 .NET 版本。发布版本意味着一定程度的质量和稳定性,因此您应该很少需要进入代码来诊断问题。
  • 然而,这也是一种相当“闭源”的心态。我发现在开源世界中,更期望能够步入各种库的“稳定版本”的代码,不是因为东西坏了,而是因为有时最好的文档就是看看库是什么做。
猜你喜欢
  • 1970-01-01
  • 2011-07-11
  • 1970-01-01
  • 1970-01-01
  • 2010-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多