7

在新的 VCL 应用程序中,编译构建操作生成相同的二进制文件和映射文件(即使“在项目中包含版本信息”选项已关闭,.exe 文件末尾也有细微差别 - 已经讨论过)。映射文件是相同的字节到字节。但是当我添加任何第三方组件时,Build 和 Compile 生成的二进制文件和 map(!) 文件有很大不同!

在两个版本的 Delphi 上测试:
- 7.0 版(Build 8.1)
- CodeGear™ RAD Studio 2007 版 11.0.2902.10471(+2007 年 12 月更新)

重现步骤:

  1. 创建新的 VCL 应用程序。可能添加任何本机 Delphi 组件(我尝试了 Standart、Additional、Win32 和 System 选项卡中的所有组件)。
  2. 在项目选项的链接器选项卡上打开详细地图文件。
  3. 构建项目
  4. 重命名输出 .exe 和 .map 文件(例如:project1.exe 到 project1b.exe 和 project1.map 到 project1b.map)。
  5. 编译项目
  6. 重命名输出 .exe 和 .map 文件(例如:project1.exe 到 project1c.exe 和 project1.map 到 project1c.map)。
  7. 比较第 4 步和第 6 步中的文件。(我使用 WinMerge 2.12.4.0)。

我们几乎没有不同的 .exe 文件和完全相同的 .map 文件。然后,如果我们再次重复所有步骤,但在项目中使用第三方组件(我尝试 ODAC、DOA、DevExpress 和自制),我们会得到更多不同的 .exe 和不同的 .map 文件。

为什么?有什么建议么?

更新
一些关于我如何发现它以及它为什么让我感兴趣的信息:
项目是使用 MSBuild 从简单的脚本构建的。当在项目中通过 ITE 添加翻译(带有资源的 dll)时,我发现当项目构建时(来自脚本或来自 IDE) - 翻译版本工作错误 - 按钮、标签等上的一些文本来自错误的位置(字面意思是来自另一个按钮、标签)。当项目从 IDE 编译时 - 一切正常。所以我开始比较构建和编译输出......

4

3 回答 3

12

您所看到的只是编译器内置 make 逻辑的产物。当您进行构建时,它会告诉编译器构建所有可用的源。因此,Delphi 处理每个源文件,并为它找到源的使用列表中的每个单元构建该文件。它递归地执行此操作。当您进行编译时,只会加载现有的 .dcu 文件,如果发现它们是最新的,则什么也不做。这实际上会导致发现单元的顺序不同,因为每个 .dcu 都会有效地“扁平化”使用列表。由于这些单元以不同的顺序被发现和加载,它们依次以不同的顺序链接。这就是为什么您的地图文件看起来如此不同的原因。给定相同的源,如果您连续进行两次构建或连续两次编译,则映射文件应该相同。

导致差异的其他原因更为常见,包括 PE 标头时间戳以及其他填充和对齐位。

于 2010-01-06T19:03:52.767 回答
3

我相信这个答案有两个部分。

IIRC,您看到的部分问题是编译器在进行编译/构建之前不会将内存清零。因此,出于对齐目的,未初始化内存中留下的任何内容都将成为输出中的填充物。

我似乎还记得应用程序的 pe 标头信息中包含一个日期时间戳。这将导致每次的差异。

我不是确认这一点的最佳人选,但我似乎从过去的讨论中回想起了这一点。

像艾伦鲍尔或巴里凯利这样的人可能能够提供更好/更准确的信息。

于 2010-01-06T15:35:48.780 回答
0

如果您在项目中使用编译器定义并且只是更改了这些,如果您进行编译,您将看不到对 dcu 和生成的模块(exe 或 dll)的任何更改。如果您进行完全重建,编译器定义将用于新创建的 dcu 和模块。

我在一个大型项目组中看到了这一点,我们在具有不同定义的不同项目中使用模块,并且所有 dcu 都存储在同一目录中。

Ergo:在这种情况下,编译器不会强制依赖定义。

也许你确实看到了同样的问题。

于 2010-01-08T15:40:40.410 回答