1

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!

marzipan
  • 49
  • 2

1 Answers1

1

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.

marzipan
  • 49
  • 2
  • 1
    You do understand, however, that incremental linking -- by and large -- is meant for the development cycle, whereas `/Brepro` is squarely aimed at the release cycle. Still an interesting find. +1 – 0xC0000022L Aug 05 '23 at 20:51
  • @0xC0000022L good point! – marzipan Aug 28 '23 at 16:22