Open garandria opened 6 months ago
I've een working on reproducible build stuff for 20 years (https://landley.net/aboriginal/about.html and https://lists.j-core.org/pipermail/j-core/2016-August/000314.html and so on) but "we changed the config and did an incremental build" is not a use case I've particularly been targeting.
The top level makefile is mostly just a wrapper, the build is done by scripts/make.sh which should reuse artifacts (ala generated/obj/*.o). You can set V=1 to see what the build is doing (same as the kernel build). The "distclean" target deletes .config, you probably want the "clean" target (again, same as the kernel build).
The build checks which commands need to be rebuilt, but the toybox global symbols (CONFIGTOYBOX*) are not checked, and can theoretically vary if you don't do a clean build. The reason I don't check if they changed is I don't (reliably) have a copy of the previous build's .config to compare it with, and considered doing that "pilot error".
The 0.8.5 release was 3 years ago, I don't remember specifically what's changed since then. (Rather a lot, including a significant chunk of the build plumbing. I note that the https://github.com/landley/toybox/blob/master/scripts/recreate-prereq.sh and https://github.com/landley/toybox/tree/master/scripts/prereq work was fairly recent, ala http://lists.landley.net/pipermail/toybox-landley.net/2024-April/030271.html)
The Toybox binary obtained by an incremental build may not be reproducible depending on some configuration options (while a traditional, clean build consistently leads to the same binary). It would be helpful to understand why this is occurring.
I'm describing and providing a minimal example hereafter.
Let us say that I have an initial config file
1.config
that I have just built. Then, I want few more options in my Toybox binary so I runmake menuconfig
and I enable for instanceCONFIG_CKSUM
andCONFIG_DU
which gives me2.config
. Instead of cleaning up the directory with amake distclean
, I can just build2.config
on top of the artefact of1.config
assuming that Make will perform an incremental build and reuse artefacts.For the example, I have done a clean build of
2.config
to compare the build outputs and build time. First, we can notice that incremental build is indeed faster than clean build (see the graph below). In addition, the toybox binary obtained by a clean build is bit-by-bit identical to the toybox binary obtained with an incremental build (I am simply using GNU cmp to compare two binaries). So everything seems fine: (1) a clean build of2.config
is the same as an incremental build of2.config
; (2) we reduce build time.However, If in addition to
CONFIG_CKSUM
andCONFIG_DU
I enableCONFIG_TOYBOX_HELP
andCONFIG_TOYBOX_HELP_DASHDASH
(which gives me say3.config
), the build time is still faster with incremental build but the output is not reproducible anymore (i.e., the binary is not bit-by-bit identical). Some other experiments suggest thatCONFIG_TOYBOX_HELP
is causing specifically the issue.I tried to dig a little bit into the binary and checked the output of the diffoscope but is not enough informative to understand the specific reasons why some options are causing the issue.
It has been demonstrated that configuration options can have an impact on the reproducibility of a build, as described in the paper Options Matter: Documenting and Fixing Non-Reproducible Builds in Highly-Configurable Systems for instance. However, for 2000 builds of Toybox's distinct configurations, all of them were reproducible when clean builds are performed.
So, it seems that the non-reproducibility of the builds here happens because of the incremental build. Do you have any insights on why is it happening?
I am building Toybox v0.8.5. The configuration files
{1,2,3}.config
as well as the output of the diffoscope for3.config
are available at https://gist.github.com/garandria/f8443b5fde20bf7fd1a66ca881721e46Note: I could share other cases with problematic options causing non-reproducibility on some configurations. But this case has the merit of being simple for investigating the root causes.