当调试Delphi应用程序时,出现“没有调试信息”的情况。

15

我们构建了一个应用程序,使用了包和组件。在调试该应用程序时,IDE中的“事件日志”经常显示我们的BPL文件正在加载,但没有调试信息(“无调试信息”)。这是没有道理的,因为我们所有的包和EXE都是使用调试模式构建的。

_(each project) | Options | Compiling_
[ x ] Assertions
[ x ] Debug information
[ x ] Local symbols
Symbol reference info = "Reference info"
[   ] Use debug .dcus
[ x ] Use imported data references

_(each project) | Options | Linking_
[ x ] Debug information
Map file = Detailed

我们有4个项目,全部都是使用运行时包构建的:

  1. Core.bpl
  2. Components.bpl
  3. Plugin.bpl (同时使用 #1 和 #2)
  4. MainApp.exe (使用 #1)

观察到的问题

1) 经常在我们进行调试时,Components.bpl会加载调试信息,但“本地变量”窗口中的所有值都为空。如果将鼠标悬停在代码中的变量上,则不会弹出任何内容,而Evaluate窗口也不显示任何内容(“结果”窗格始终为空)。

2) 有时事件日志会显示各种BPL的“无调试信息”。例如,如果我们激活Plugin.bpl项目并将其“运行|参数”的主机应用程序设置为MainApp.exe,然后按F9键,除了Plugin.bpl模块之外,似乎所有模块都加载了“Has Debug Info”。当它加载时,事件日志显示“无调试信息”。但是,如果我们关闭应用程序并立即按F9键,它将再次运行而无需重新编译任何内容,这次Plugin.bpl将加载调试信息(“Has Debug Info”)。

问题

1) 什么原因会导致“本地变量”窗口不显示值?

2) 为什么有时BPL会在编译时使用调试信息,而所有调试文件(dcu、map等)都可用时,仍然没有加载调试信息?

7个回答

5

我想描述一下我的问题。

我使用LoadPackage函数动态加载软件包。

SysInternals.com Process Monitor中,我可以看到在处理LoadPackage后,packagename.DCP被成功打开和读取——没有文件I/O失败、没有试图在错误位置找到它或其他可疑情况。也许在DCP中有某种结构使得IDE调试器失常。我想念Turbo Debugger在Delphi可用的时代。

顺便说一下,如果开发人员创建了packagename.RSM,情况也是一样的。

然后(在断点暂停或单步跟踪时),我打开“查看/调试窗口/模块”,看到最后一个模块是我的模块,并且它的“符号信息”单元格为空。我右键单击它,选择“重新加载符号”操作——就这样,从此我可以进行调试。

PS. 不知道这是否能帮助我调试初始化部分,希望即使有动态的LoadPackage调用,“加载时中断”菜单项也能起作用......

PPS. 的确起作用了,即使在IDE重启后也是如此。现在我会在BPL加载时得到CPU视图的提示,我按下CTRL+ALT+M,滚动到底部找到我的BPL,右键单击它以重新加载符号,按Enter键,然后关闭模块CPU视图,并按下F9(运行)。当initialization部分完成后,我会再次通过CPU视图得到提示——在LoadPackage退出前只有几个JMP——然后我关闭CPU视图并再次按下F9。虽然这很繁琐,但仍比IDE重启要好得多。


虽然没有回答为什么调试信息丢失,但是给出了有用的解决方法,点个赞。这比重启Delphi并一遍又一遍地尝试直到最终成功要好得多。 - James L.
1
事实是它不是缺失的,而是在BPL中存在 - CFF Explorer显示了这一点。问题是IDE没有使用它 - 而是使用DCP文件。如果有几个DCP文件 - 那么它就会失败。但是,即使只有一个DCP存在并且它明确地正确读取了该文件,为什么它有时会失败 - 这是个谜。在我的情况下,我发现同名的单元EXE:Path1 \ name和BPL1:Path2 \ name - 但是BPL1和BPL2都已经被加载了,只有动态加载的BPL3受到了影响。无论如何,SysInit单元都应该在所有EXE / DLL / BPL文件中克隆,以便不会混淆IDE debugfer。神秘。PS感谢您注意Modules视图 - Arioch 'The
不用谢 - 但我从来没有尝试过右键点击告诉它“重新加载符号”。那是一个不错的新技巧。 - James L.
1
好久不见了,詹姆斯。 我刚刚发现,当我安装了XE2 Upd4 HF1时,在Windows\System32中有一些之前2011版本(更新1?不知道)的rtl160bpl和vcl160.bpl。因此,程序编译针对c:\RAD Studio\9.0\...中的RTL/VCL,并且针对其他BPL版本运行和调试。在RTL内部调试、评估变量.classname等方面也带来了很多麻烦。我删除了那些遗留的全局BPL,并且在几个小时内这个问题没有再次出现。希望它不会再次发生,或者更加罕见。 - Arioch 'The
这个答案在2020年被访问了,哇。前面提到的两个BPL是XE2 Upd3版本,并由(如果我没记错的话)Raize CodeSite远程日志记录插件安装。总体而言,第四个更新似乎质量不够完善,破坏了重要的东西,比如与Microsoft Office的COM互操作性。 - Arioch 'The

4

这个非官方工具可以修复Delphi的许多问题。对于我来说,它修复了在没有调试信息的情况下加载模块的问题。所有的功劳归功于 magicandre1981


我在 Delphi XE6 中调试设计包时遇到了麻烦,IDE 不想加载调试信息。这个工具帮了我很大的忙,谢谢! - Denys Avilov
每次断点被触发时,我也会落在“CPU”选项卡上 -> 我的bpl和应用程序是没有调试信息加载的。我安装了这个工具,它就可以正常工作了。谢谢! - santiagoIT
尽管如此,在XE2中这对我没有起作用。疯狂的事情是,Andy似乎有Delphi源代码(不是RTL / VCL,而是IDE本身),因此可以在源代码级别上修复错误。为什么这些错误经常在Delphi版本之间持续存在,这完全令人激怒。 - Arioch 'The

4

我们在项目中遇到了类似的问题。不幸的是,我们有数十个 bpl 文件,因此无法将它们合并成一个文件。

在迁移到 XE2 并更改编译目标文件夹结构后出现了此问题。虽然很难确定新版本的 Delphi 是否引入了该问题,但我们可以通过将编译 bpl 的文件夹添加到路径环境变量中来解决该问题,并使用 IDE 的路径覆盖功能。在 Delphi 2010 中不需要这种配置...


2

对于我们的特定情况,我们通过将Core.pbl和Components.bpl合并成一个单独的BPL文件来解决问题。现在所有的模块都加载了调试信息,并且偶尔出现的局部窗口不显示变量值的问题也得到了解决。


3
将BPL合并以解决问题并不是一个好的解决方案。想象一下,如果您有数百个动态包,将它们合并成一个BPL是不可能的。 - Chau Chee Yang
@ChauCheeYang - 我们确实有其他几十个BPL文件。只是这两个的分离导致了问题。在我们的情况下,合并这两个是可以接受的,而将其他几十个保持分开...可能与Components.bpl对Core.bpl有很大依赖有关。 - James L.
你在debugrelease配置中都使用了optset引用吗? - Chau Chee Yang
我已经发布了一个新答案,可能有助于解决问题。 - Chau Chee Yang

2
您需要构建带有调试信息的单独软件包,并最终也需要构建不带调试信息的软件包,这样您将在两个位置都有它们。然后,您需要使用调试信息来构建应用程序项目。检查您的路径以确保在调试项目构建中包含启用调试的软件包源代码。听起来您可能正在包含已经构建好但没有调试的软件包,因为您从错误的源代码进行了包含。您必须确保不要同时包含两个路径,否则Delphi会在找到相同的软件包时选择要包含什么。

我们所有的项目都是使用调试模式构建的,而且 DEBUG 和 RELEASE 都使用相同的输出文件夹。因此,这不是构建包时没有使用 DEBUG 或者调试器找到任何包的 RELEASE 版本的问题... 不过我们会检查路径,确保能够正确找到调试 DCUs。感谢您的建议。 - James L.
+1 感谢您建议检查路径。这促使我打开了“调试模块”窗口,显示调试符号的加载位置。这有助于引导我想到解决问题的方法(请参见下面的答案)。 - James L.

2
这个问题可能与QC#109291有关:
当Delphi IDE引入.dproj文件和带有选项集的构建配置时,它极大地改善了项目发布管理。
然而,它也有一个难以重现和捕捉的副作用,我认为这是IDE中的错误。这个问题经常让用户感到困惑,因为有些项目无法在IDE调试器中进行调试。即使我们检查了项目中所有相关的设置、编译器和链接选项,调试器也不会对该项目进行激活。有些项目可以工作,有些项目则不行。我们甚至认为这是内存问题或CPU问题。
我注意到问题是由于.dproj文件设置未正确存储所致。如果相关的.dproj文件有以下内容:
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''">
    <Cfg_1>true</Cfg_1>
    <CfgParent>Base</CfgParent>
    <Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''">
    <Cfg_2>true</Cfg_2>
    <CfgParent>Base</CfgParent>
    <Base>true</Base>
</PropertyGroup>

<Import Project="Release.optset" Condition="'$(Cfg_2)'!='' And Exists('Release.optset')"/>
<PropertyGroup Condition="'$(Cfg_1)'!=''">
    <CfgDependentOn>Release.optset</CfgDependentOn>
</PropertyGroup>
<Import Project="Debug.optset" Condition="'$(Cfg_1)'!='' And Exists('Debug.optset')"/>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
    <CfgDependentOn>Debug.optset</CfgDependentOn>
</PropertyGroup>

“Release.optset”绑定到“Cfg_2”,“Debug.optset”绑定到“Cfg_1”,但是“Release”配置正在使用“Cfg_1”,而“Debug”配置正在使用“Cfg_2”。
在构建项目时,在调试配置下不会生成调试信息,但在发布配置下会生成。
一种解决方法是使用任何文本编辑器打开.dproj文件,而不是Delphi IDE,并更新为:
<Import Project="Release.optset" Condition="'$(Cfg_1)'!='' And Exists('Release.optset')"/>
<PropertyGroup Condition="'$(Cfg_1)'!=''">
    <CfgDependentOn>Release.optset</CfgDependentOn>
</PropertyGroup>
<Import Project="Debug.optset" Condition="'$(Cfg_2)'!='' And Exists('Debug.optset')"/>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
    <CfgDependentOn>Debug.optset</CfgDependentOn>
</PropertyGroup>

这看起来很有前途,但在我再次遇到缺少调试信息的情况之前,我将无法测试它。感谢您分享您的经验。 - James L.
真的。我通过删除dproj文件并让Delphi重新生成它来解决了许多问题。其中一个很好的例子:http://stackoverflow.com/questions/21958575/access-violation-when-i-drop-a-tidsmtp-on-a-form - Gabriel

0

我在.dprj文件中发现了一行Cfg_2详细信息,其中值为Debugger_LoadAllSymbols,被设置为false。我将其设置为true。问题解决了。也许与你的情况不同,但可能有所帮助。

<PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
...
    <Debugger_LoadAllSymbols>true</Debugger_LoadAllSymbols>
...
</PropertyGroup>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接