Bug #21995
closedmkmf generates a non-deterministic log file
Added by gemmaro (Gemma Kosaka) 5 months ago. Updated 11 days ago.
Description
Hello,
When compiling Ruby's C extensions with mkmf, it can generate a mkmf.log file with non-deterministic content, especially at the line below:
This can be problematic on some distributions/package-managers, since the mkmf.log file is included in the files generated by gem install.
Note about an example flow where randomized filenames occur:
extconf.rbhas calls tohave_funcgem installis run by the user- It invokes mkmf to process the
extconf.rbfile - The checks fail and print intermediate randomized filenames, which are recorded in
mkmf.logfile gem installincludesmkmf.login the packaged files- When the gem is built/packaged multiple times, a reproducibility problem occurs
As a background, the previously reported/related issues are:
-
Bug #15304: Package build with extensions is not reproducible
-
This mentions temporary filenames in the generated Makefile, and they are not reproducible.
-
The necessity/value of including
Makefile,gem_make.out, andmkmf.logfiles are questioned. -
So the pull request was created to omit these files when installing gems.
-
However, deleting these files might break compatibility, so the pull request was closed.
-
Note: There is an entry about
mkmf.login the RubyGems' changelog:2.2.2 / 2014-02-05¶
Bug fixes:¶
- [...]
- The
mkmf.logis now placed next togem_make.outwhen building extensions.
-
-
Bug #19329: "gem install" installs logs and other "noisy", non-reproducible files
- This points out that
gem installinstallsmkmf.logfile. - It was transferred at RubyGems GitHub repository.
- This points out that
-
There are some issues related to this topic on the GNU Guix channel
- For example, when I was packaging Ruby 4.0 for Guix, this reproducibility problem occured.
-
There should be other workarounds in the Nix community, apparently.
To wrap up, I think the followings are desirable:
- Conventional file locations should be kept as is on the RubyGems side.
- Just deleting these files breaks compatibilities.
- These might be helpful when users report issues to gem owners with detailed information.
- It is helpful if generated file contents are as reproducible as possible.
- In some contexts where reproducibility matters, this issue makes packaging Ruby gems a bit harder.
- Luckily, workarounds are possible in distribution package recipes such as deleting these files.
- -> the component that generates
mkmf.logis mkmf, so it might be resolvable by modifying mkmf itself.
Thank you,
gemmaro.
Updated by gemmaro (Gemma Kosaka) 5 months ago
Actions
#1
[ruby-core:125248]
I created a pull request about this.
Updated by hsbt (Hiroshi SHIBATA) 5 months ago
Actions
#2
[ruby-core:125434]
- Status changed from Open to Assigned
- Assignee set to hsbt (Hiroshi SHIBATA)
I will look this.
Updated by gemmaro (Gemma Kosaka) 5 months ago
Actions
#3
[ruby-core:125435]
Thanks for the reply! I'm sorry -- this pull request #note-1 currently fails CI, and I'm still investigating why. It's not ready for review yet, so it would be appreciated if you could revisit when it is.
Updated by Hanmac (Hans Mackowiak) 5 months ago
1Actions
#4
[ruby-core:125436]
i think the main question is:
Why is mkmf.log file is included in the files generated by gem install?
Shouldn't it be okay to skip these files?
Especially for distributions/package-managers?
Updated by nobu (Nobuyoshi Nakada) 4 months ago
Actions
#5
[ruby-core:125480]
- Status changed from Assigned to Rejected
mkmf.log is not intended to be installed.
Updated by hsbt (Hiroshi SHIBATA) 4 months ago
Actions
#6
[ruby-core:125481]
- Status changed from Rejected to Assigned
Could you clarify what you mean by "distributions/package-managers"? Also, do they actually include the RubyGems log files (like mkmf.log) in their packages?
Updated by gemmaro (Gemma Kosaka) 4 months ago
Actions
#7
[ruby-core:125482]
Could you clarify what you mean by "distributions/package-managers"?
"distributions/package-managers" in the issue description refers, broadly, to systems that allow software packages to cooperate -- automatically tracking dependencies, locating files, and managing environment variables -- while making them easily installable, upgradable, and removable. Here, however, I specifically mean systems with stricter reproducibility guarantees, such as the Guix or Nix package managers.
For those unfamiliar with such systems, these are conceptually similar to Bundler. For example, running guix shell ruby ruby-nokogiri drops you into a shell with Ruby and Nokogiri installed and the environment fully set up. The key difference is that these guarantee that installing the same package on the same architecture always produces bit-for-bit identical results.
Also, do they actually include the RubyGems log files (like mkmf.log) in their packages?
Yes, at least with Guix, some packages do include the log files.
results of guix locate commandresults of guix locate command
$ guix locate mkmf.log
ruby-json@2.1.0 /gnu/store/...-ruby-json-2.1.0/lib/ruby/vendor_ruby/extensions/x86_64-linux/3.3.0/json-2.1.0/mkmf.log
ruby-racc@1.5.2 /gnu/store/...-ruby-racc-1.5.2/lib/ruby/vendor_ruby/extensions/x86_64-linux/3.3.0/racc-1.5.2/mkmf.log
ruby-sqlite3@2.5.0 /gnu/store/...-ruby-sqlite3-2.5.0/lib/ruby/vendor_ruby/extensions/x86_64-linux/3.3.0/sqlite3-2.5.0/mkmf.log
ruby@3.3.9 /gnu/store/...-ruby-3.3.9/lib/ruby/gems/3.3.0/gems/rbs-3.4.0/ext/rbs_extension/mkmf.log
ruby@3.3.9 /gnu/store/...-ruby-3.3.9/lib/ruby/gems/3.3.0/gems/debug-1.9.2/ext/debug/mkmf.log
ruby@3.4.7 /gnu/store/...-ruby-3.4.7/lib/ruby/gems/3.4.0/gems/syslog-0.2.0/ext/syslog/mkmf.log
ruby@3.4.7 /gnu/store/...-ruby-3.4.7/lib/ruby/gems/3.4.0/gems/rbs-3.8.0/ext/rbs_extension/mkmf.log
ruby@3.4.7 /gnu/store/...-ruby-3.4.7/lib/ruby/gems/3.4.0/gems/nkf-0.2.0/ext/nkf/mkmf.log
ruby@3.4.7 /gnu/store/...-ruby-3.4.7/lib/ruby/gems/3.4.0/gems/debug-1.11.0/ext/debug/mkmf.log
ruby@3.4.6 /gnu/store/...-ruby-3.4.6/lib/ruby/gems/3.4.0/gems/syslog-0.2.0/ext/syslog/mkmf.log
ruby@3.4.6 /gnu/store/...-ruby-3.4.6/lib/ruby/gems/3.4.0/gems/rbs-3.8.0/ext/rbs_extension/mkmf.log
ruby@3.4.6 /gnu/store/...-ruby-3.4.6/lib/ruby/gems/3.4.0/gems/nkf-0.2.0/ext/nkf/mkmf.log
ruby@3.4.6 /gnu/store/...-ruby-3.4.6/lib/ruby/gems/3.4.0/gems/debug-1.11.0/ext/debug/mkmf.log
That said, as these files are increasingly being identified as a source of reproducibility check failures, existing packages may also start applying workarounds in their recipes, such as explicitly deleting these log files.
As I described in the issue, based on my research into the history of this topic, I had assumed that including log files such as mkmf.log in the files generated by gem install was intended behavior. That said, if gem install were changed to skip these files, I would consider that a step in the right direction (for reproducibility-aware package managers).
Updated by hsbt (Hiroshi SHIBATA) 3 months ago
1Actions
#8
[ruby-core:125886]
I agree with @nobu (Nobuyoshi Nakada) that these files are not meant to be installed, so I would like to fix this on the installation side rather than by making mkmf output deterministic.
There are two paths:
- For gem install, RubyGems should stop placing the build logs in the installed extension directory. This is tracked at https://github.com/ruby/rubygems/issues/6259, and I will open a pull request for it later.
- For the gems bundled with Ruby, the artifacts leak through rbinstall, so I opened https://github.com/ruby/ruby/pull/17578 to drop the in-tree build leftovers such as mkmf.log, Makefile and object files from the installed gem directory. The compiled extension is installed separately, so removing them is safe.
Together these should resolve the reproducibility problem you described.
Updated by hsbt (Hiroshi SHIBATA) about 2 months ago
Actions
#9
- Status changed from Assigned to Closed
Applied in changeset git|a0e70d5f2344995c79dcfbbcbbfba63b35123608.
[Bug #21995] Exclude C extension build artifacts from installed bundled gems
Bundled gem extensions are built in place under .bundle/gems, which
leaves mkmf.log, Makefile, object files and the in-tree shared library
behind. UnpackedGem#collect then packs them into the installed gem
directory, where they are non-reproducible and unused at run time. This
breaks bit-for-bit reproducibility for distributions like Guix and Nix.
Filter them out at collection so only sources ship.
https://bugs.ruby-lang.org/issues/21995
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
Updated by hsbt (Hiroshi SHIBATA) about 2 months ago
Actions
#10
[ruby-core:126144]
- Status changed from Closed to Assigned
I merged https://github.com/ruby/ruby/pull/17578 now. I need to consider newer bundler and old rubygems combination for rubygems side.
Updated by hsbt (Hiroshi SHIBATA) 11 days ago
Actions
#11
[ruby-core:126633]
- Status changed from Assigned to Closed
I also merged https://github.com/ruby/rubygems/pull/9700 for this request.
RubyGems 4.1 and Bundler 4.1 separates build artifacts from the current library directory.