Delphi 编译和构建在同一项目上生成不同的二进制文件
在新的 VCL 应用程序中,编译和构建操作生成相同的二进制文件和映射文件(即使“在项目中包含版本信息”,.exe 文件末尾也有细微差别)选项已关闭 - 已经讨论过)。映射文件的字节与字节相同。但是当我添加任何第三方组件时,构建和编译生成的二进制文件和映射(!)文件明显不同!
在两个版本的 Delphi 上进行了测试:
- 版本 7.0(构建 8.1)
- CodeGear™ RAD Studio 2007 版本 11.0.2902.10471(+2007 年 12 月更新)
重现步骤:
- 创建新的 VCL 应用程序。可能添加任何本机 Delphi 组件(我尝试了 Standart、Additional、Win32 和 System 选项卡中的所有组件)。
- 在项目选项的链接器选项卡上打开详细地图文件。
- 构建项目。
- 重命名输出.exe 和.map 文件(例如:project1.exe 重命名为project1b.exe,project1.map 重命名为project1b.map)。
- 编译项目。
- 重命名输出.exe 和.map 文件(例如:project1.exe 重命名为project1c.exe,project1.map 重命名为project1c.map)。
- 比较步骤 4 和 6 中的文件。(我使用 WinMerge 2.12.4.0)。
我们有一些不同的 .exe 文件和完全相同的 .map 文件。然后,如果我们再次重复所有步骤,但在项目中使用第三方组件(我尝试 ODAC、DOA、DevExpress 和自制),我们会得到更多不同的 .exe 和不同的 .map 文件。
为什么?有什么建议吗?
更新
关于我如何找到这个以及为什么我对它感兴趣的一些信息:
项目是使用 MSBuild 从简单脚本构建的。当在项目中通过 ITE(带有资源的 dll)添加翻译时,我发现当项目构建时(从脚本或从 IDE) - 翻译版本工作错误 - 按钮、标签等上的一些文本来自错误的位置(实际上是来自另一个地方)按钮、标签)。当项目从 IDE 编译时 - 一切正常。所以我开始比较构建和编译输出......
In a fresh VCL application Compile and Build operation produce the same binary and map file (with minor differences at the end of .exe file even if "include version information in project" option is switched off - already discussed). Map file is the same byte to byte. But wen I add any third-party component the binary and map(!) file produced by Build and Compile are significantly different!
Tested on two versions of Delphi:
- Version 7.0 (Build 8.1)
- CodeGear™ RAD Studio 2007 Version 11.0.2902.10471 (+December 2007 Update)
Step to reproduce:
- Create New VCL Application. Possibly add any native Delphi component (I try all components from Standart, Additional, Win32 and System tab).
- Turn on Detailed Map file on Linker tab of the Project Options.
- Build project.
- Rename output .exe and .map file (for example: project1.exe to project1b.exe and project1.map to project1b.map).
- Compile project.
- Rename output .exe and .map file (for example: project1.exe to project1c.exe and project1.map to project1c.map).
- Compare files from step 4 and 6. (I use WinMerge
2.12.4.0).
We have little different .exe files and fully identical .map files. Then if we repeat all steps again but use in the project third-party component (I try ODAC, DOA, DevExpress and selfmade) we get more different .exe and different .map files.
Why? Any suggestions?
UPDATE
Some information about how I found this and why it's interests me:
Project is build from simple script with MSBuild. When in the project was added translation thru ITE (dll with resources) I found that when project was Build (from script or from IDE) - translated version work wrong - some text on button, labels etc. got from wrong place (literally from another button, labels). When project Compiled from IDE - everything is ok. So I start compare Build and Compile output...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您所看到的只是编译器内置 make 逻辑的产物。当您进行构建时,它会告诉编译器构建所有可用的源。因此,Delphi 处理每个源文件,并为它找到源的使用列表中的每个单元构建该文件。它递归地执行此操作。当您进行编译时,只会加载现有的 .dcu 文件,如果发现它们是最新的,则不会执行任何操作。这实际上会导致发现单元的顺序不同,因为每个 .dcu 都会有效地“展平”使用列表。由于这些单元以不同的顺序被发现和加载,因此它们依次以不同的顺序链接。这就是为什么您的地图文件看起来如此不同。给定相同的源,如果您连续进行两次构建或连续两次编译,映射文件应该是相同的。
造成差异的其他原因更为常见,包括 PE 标头时间戳以及其他填充和对齐位等。
What you're seeing is simply an artifact of the built-in make logic of the compiler. When you do a build, it tells the compiler to build all available sources. So Delphi processes each source file and for each unit in the uses lists for which it finds source, it will then build that file. It does this recursively. When you do a compile, only the existing .dcu files are loaded and if they're found to be up-to-date, nothing is done. This can actually lead to a different order in which the units are discovered since each .dcu will effectively "flatten" the uses list. Since the units are discovered and loaded in a different order, they are in-turn, linked in a different order. This is why your map files look so different. Given the same sources, the map file should be the same if you do two builds in a row or two compiles in a row.
Other causes for differences are more mundane and include things like the PE header time stamp, and other bits of padding and alignments.
我认为这个答案有两个部分。
IIRC,您看到的部分问题是编译器在进行编译/构建之前不会将内存清零。因此,出于对齐目的,未初始化内存中剩余的任何内容都会成为输出中的填充物。
我似乎还记得应用程序的 pe 标头信息中包含一个日期时间戳。这每次都会造成差异。
我不是确认这一点的最佳人选,但这似乎是我从过去的讨论中回忆起的。
像艾伦·鲍尔或巴里·凯利这样的人可能能够提供更好/更准确的信息。
There is two parts to this answer I believe.
Part of the problem your seeing, IIRC, is that the compiler doesn't zero out memory before doing a compile/build. Thus anything left in uninitialized memory becomes filler in the output for alignment purposes.
I also seem to recall that there is a date time stamp included in the pe header information for the application. that will cause a difference every time.
I'm not the best person to confirm this but this is what I seem to recall from past discussions.
People like Allen Bauer or Barry Kelly would probably be able to give better/more accurate information on this.
如果您在项目中使用编译器定义并且只是更改了这些定义,那么如果进行编译,您将不会看到 dcu 和生成的模块(exe 或 dll)有任何更改。如果您进行完全重建,编译器定义将在新创建的 dcu 和模块中使用。
我在一个大型项目组中看到过这种情况,我们在不同的项目中使用具有不同定义的模块,并且所有 dcu 都存储在同一目录中。
因此:在这种情况下,编译器不会强制执行对定义的依赖性。
也许您确实看到了同样的问题。
If you use compiler defines in your project and just changed those, if you do a compile, you won't see any changes to the dcu's and the resulting module (exe or dll). If you do a full rebuild the compiler defines are used in the newly created dcu's and modules.
I have seen this in a large project group where we use modules in different projects with different defines and all dcu's are stored in the same directory.
Ergo: The compiler does not enforce the dependancies on the defines in this case.
Perhaps you did see the same issue.