英文:
Potential downsides of /BREPRO MSVC linker option?
问题
我一直在调查我们产品构建过程中的不可重复性来源。这是一个主要是C#应用,但也包含我们自己构建的一些C++ DLL。我发现了有关MSVC链接器的一个未记录标志"/BREPRO"的提及。它似乎会将生成的DLL/EXE中的一些时间戳值替换为每次编译时不会更改的值。这个选项似乎至少从VS 2013开始就存在(如https://www.amossys.fr/fr/ressources/blog-technique/pe-timestamps-and-bepro-flag/中提到),但即使在VS 2022中,它仍未出现在链接器选项的文档中。我尝试将其添加到我们的一个DLL项目中,的确使输出的DLL在每次编译时都完全相同。这似乎是一件好事。
然而,由于这个选项会干涉PE文件中我不理解的底层内容,而且微软没有记录这个选项,我想知道使用它的潜在风险是什么?文章https://devblogs.microsoft.com/oldnewthing/20180103-00/?p=97705似乎暗示微软本身正在不再将时间戳视为时间戳,尽管它没有具体提到这个选项。
是否有人有关于这个选项的良好或不良经验可以分享?谢谢!
英文:
I have been investigating sources of non-reproducibility in our product's build process. It's a mostly C# app but it also has some C++ DLL's that we build ourselves. I came across some mentions of an undocumented flag for the MSVC linker called "/BREPRO". It seems to replace some timestamp values in the generated DLL/EXE with values that do not change every time you compile. This option seems to have been around since at least VS 2013 (as mentioned in https://www.amossys.fr/fr/ressources/blog-technique/pe-timestamps-and-bepro-flag/), but still does not appear in the documentation of linker options even in VS 2022. I tried adding it to one of our DLL projects, and it did indeed make the output DLL byte-identical every time I compiled it. This seems like a Good Thing.
However, because this option is messing with low-level stuff in the PE file that I do not understand, and Microsoft has not documented this option, I wonder, what are the potential downsides of using it? The article https://devblogs.microsoft.com/oldnewthing/20180103-00/?p=97705 seems to suggest that Microsoft itself is moving away from the timestamps really being timestamps, although it does not mention this option specifically.
Does anyone have good or bad experience with this option that they can share? Thanks!
答案1
得分: 1
这是您提供的文本的翻译:
我发现一个问题 - /BREPRO 似乎与 /LTCG:INCREMENTAL 链接器选项不兼容。您可以通过在VS2022中创建一个新的 C++ "Console App" 项目模板并切换到 Release 配置来看到这一点。这个模板在 Release 中设置了 /LTCG:INCREMENTAL。第一次构建时,输出如下所示:
构建已启动...
1>------ 构建已启动: 项目: ConsoleApplication1, 配置: Release x64 ------
1>ConsoleApplication1.cpp
1>正在生成代码
1>未找到以前的 IPDB,退回到全面编译。
1>因为未找到以前编译的可用 IPDB/IOBJ,所以所有 10 个函数都被编译。
1>生成代码已完成
1>ConsoleApplication1.vcxproj -> ConsoleApplication1\x64\Release\ConsoleApplication1.exe
========== 构建: 1 成功,0 失败,0 已更新,0 被跳过 ==========
========== 构建于下午 3:54 并耗时 03.072 秒 ==========
如果您触摸 ConsoleApplication1.cpp 文件但实际上没有更改其内容并再次构建,输出如下所示:
构建已启动...
1>------ 构建已启动: 项目: ConsoleApplication1, 配置: Release x64 ------
1>ConsoleApplication1.cpp
1>正在生成代码
1>已编译 10 个函数中的 0 个 (0.0%),其余从以前的编译中复制。
1> 当前编译中有 0 个函数是新的
1> 0 个函数的内联决策被重新评估,但保持不变
1>生成代码已完成
1>ConsoleApplication1.vcxproj -> ConsoleApplication1\x64\Release\ConsoleApplication1.exe
========== 构建: 1 成功,0 失败,0 已更新,0 被跳过 ==========
========== 构建于下午 3:55 并耗时 01.495 秒 ==========
因此,链接器检测到没有任何函数实际发生了更改。但是,如果您添加 /BREPRO 链接器选项并执行清理,然后构建,触摸,构建,第一次构建的输出与上面相同,但第二次构建的输出如下所示:
构建已启动...
1>------ 构建已启动: 项目: ConsoleApplication1, 配置: Release x64 ------
1>ConsoleApplication1.cpp
1>正在生成代码
1>以前的 IPDB 和 IOBJ 不匹配,退回到全面编译。
1>因为没有从以前的编译中找到可用的 IPDB/IOBJ,所以所有 10 个函数都被编译。
1>生成代码已完成
1>ConsoleApplication1.vcxproj -> ConsoleApplication1\x64\Release\ConsoleApplication1.exe
========== 构建: 1 成功,0 失败,0 已更新,0 被跳过 ==========
========== 构建于下午 3:56 并耗时 01.582 秒 ==========
因此,一种方式 /BREPRO 使链接器无法检测到函数未发生更改。在一个大型项目中,这可能会显著增加链接时间。
英文:
Well, I found one downside - /BREPRO seems to be incompatible with the /LTCG:INCREMENTAL linker option. You can see this by creating a new instance of the C++ "Console App" project template in VS2022 and switching to Release configuration. This template has /LTCG:INCREMENTAL set in Release. The first time you build, the output looks like this:
Build started...
1>------ Build started: Project: ConsoleApplication1, Configuration: Release x64 ------
1>ConsoleApplication1.cpp
1>Generating code
1>Previous IPDB not found, fall back to full compilation.
1>All 10 functions were compiled because no usable IPDB/IOBJ from previous compilation was found.
1>Finished generating code
1>ConsoleApplication1.vcxproj -> ConsoleApplication1\x64\Release\ConsoleApplication1.exe
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
========== Build started at 3:54 PM and took 03.072 seconds ==========
If you touch the file ConsoleApplication1.cpp without actually changing its contents and build again, the output looks like this:
Build started...
1>------ Build started: Project: ConsoleApplication1, Configuration: Release x64 ------
1>ConsoleApplication1.cpp
1>Generating code
1>0 of 10 functions ( 0.0%) were compiled, the rest were copied from previous compilation.
1> 0 functions were new in current compilation
1> 0 functions had inline decision re-evaluated but remain unchanged
1>Finished generating code
1>ConsoleApplication1.vcxproj -> ConsoleApplication1\x64\Release\ConsoleApplication1.exe
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
========== Build started at 3:55 PM and took 01.495 seconds ==========
So the linker detected that none of the functions actually changed. However, if you add the /BREPRO linker option and do a clean, then build, touch, build, the output for the first build is the same as above, but the output for the second build looks like this:
Build started...
1>------ Build started: Project: ConsoleApplication1, Configuration: Release x64 ------
1>ConsoleApplication1.cpp
1>Generating code
1>Previous IPDB and IOBJ mismatch, fall back to full compilation.
1>All 10 functions were compiled because no usable IPDB/IOBJ from previous compilation was found.
1>Finished generating code
1>ConsoleApplication1.vcxproj -> ConsoleApplication1\x64\Release\ConsoleApplication1.exe
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
========== Build started at 3:56 PM and took 01.582 seconds ==========
So somehow the /BREPRO made it impossible for the linker to detect that the functions hadn't changed. Presumably in a large project this could increase your linking time significantly.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论