Reproducible builds for native compiled binaries

This commit is contained in:
Bo Anderson 2024-03-08 21:26:25 +00:00
parent 4348e06888
commit 5582849ae7
No known key found for this signature in database
7 changed files with 35 additions and 13 deletions

View File

@ -139,12 +139,14 @@ class Build
with_env( with_env(
# For head builds, HOMEBREW_FORMULA_PREFIX should include the commit, # For head builds, HOMEBREW_FORMULA_PREFIX should include the commit,
# which is not known until after the formula has been staged. # which is not known until after the formula has been staged.
HOMEBREW_FORMULA_PREFIX: formula.prefix, HOMEBREW_FORMULA_PREFIX: formula.prefix,
# https://reproducible-builds.org/docs/build-path/
HOMEBREW_FORMULA_BUILDPATH: formula.buildpath,
# https://reproducible-builds.org/docs/source-date-epoch/ # https://reproducible-builds.org/docs/source-date-epoch/
SOURCE_DATE_EPOCH: formula.source_modified_time.to_i.to_s, SOURCE_DATE_EPOCH: formula.source_modified_time.to_i.to_s,
# Avoid make getting confused about timestamps. # Avoid make getting confused about timestamps.
# https://github.com/Homebrew/homebrew-core/pull/87470 # https://github.com/Homebrew/homebrew-core/pull/87470
TZ: "UTC0", TZ: "UTC0",
) do ) do
formula.patch formula.patch

View File

@ -109,6 +109,7 @@ module Superenv
# D - Generate debugging information # D - Generate debugging information
# f - Pass `-no_fixup_chains` to `ld` whenever it # f - Pass `-no_fixup_chains` to `ld` whenever it
# is invoked with `-undefined dynamic_lookup` # is invoked with `-undefined dynamic_lookup`
# o - Pass `-oso_prefix` to `ld` whenever it is invoked
# #
# These flags will also be present: # These flags will also be present:
# a - apply fix for apr-1-config path # a - apply fix for apr-1-config path

View File

@ -35,6 +35,18 @@ class DevelopmentTools
:clang :clang
end end
sig { returns(Version) }
def ld64_version
@ld64_version ||= begin
json = Utils.popen_read("/usr/bin/ld", "-version_details")
if $CHILD_STATUS.success?
Version.parse(JSON.parse(json)["version"])
else
Version::NULL
end
end
end
sig { returns(T::Boolean) } sig { returns(T::Boolean) }
def curl_handles_most_https_certificates? def curl_handles_most_https_certificates?
# The system Curl is too old for some modern HTTPS certificates on # The system Curl is too old for some modern HTTPS certificates on

View File

@ -35,15 +35,9 @@ module SharedEnvExtension
sig { returns(T::Boolean) } sig { returns(T::Boolean) }
def no_fixup_chains_support? def no_fixup_chains_support?
return false if MacOS.version <= :catalina
# NOTE: `-version_details` is supported in Xcode 10.2 at the earliest.
ld_version_details = JSON.parse(Utils.safe_popen_read("/usr/bin/ld", "-version_details"))
ld_version = Version.parse(ld_version_details["version"])
# This is supported starting Xcode 13, which ships ld64-711. # This is supported starting Xcode 13, which ships ld64-711.
# https://developer.apple.com/documentation/xcode-release-notes/xcode-13-release-notes # https://developer.apple.com/documentation/xcode-release-notes/xcode-13-release-notes
# https://en.wikipedia.org/wiki/Xcode#Xcode_11.0_-_14.x_(since_SwiftUI_framework)_2 # https://en.wikipedia.org/wiki/Xcode#Xcode_11.0_-_14.x_(since_SwiftUI_framework)_2
ld_version >= 711 DevelopmentTools.ld64_version >= 711
end end
end end

View File

@ -140,6 +140,9 @@ module Superenv
# See: https://github.com/python/cpython/issues/97524 # See: https://github.com/python/cpython/issues/97524
# https://github.com/pybind/pybind11/pull/4301 # https://github.com/pybind/pybind11/pull/4301
no_fixup_chains no_fixup_chains
# Strip build prefixes from linker where supported, for deterministic builds.
append_to_cccfg "o" if DevelopmentTools.ld64_version >= 512
end end
def no_weak_imports def no_weak_imports

View File

@ -50,7 +50,7 @@ module OS
when "10.14" then "10.2" when "10.14" then "10.2"
when "10.13" then "9.0" when "10.13" then "9.0"
when "10.12" then "8.0" when "10.12" then "8.0"
else "2.0" else "7.3"
end end
end end
@ -373,7 +373,7 @@ module OS
when "10.14" then "10.0.0" when "10.14" then "10.0.0"
when "10.13" then "9.0.0" when "10.13" then "9.0.0"
when "10.12" then "8.0.0" when "10.12" then "8.0.0"
else "1.0.0" else "7.3.0"
end end
end end

View File

@ -29,7 +29,7 @@ class Cmd
CXX_REGEX = /(?:c|g|clang)\+\+/.freeze CXX_REGEX = /(?:c|g|clang)\+\+/.freeze
attr_reader :config, :prefix, :cellar, :opt, :cachedir, :tmpdir, :sysroot, :deps attr_reader :config, :prefix, :cellar, :opt, :cachedir, :tmpdir, :sysroot, :deps
attr_reader :archflags, :optflags, :keg_regex, :formula_prefix attr_reader :archflags, :optflags, :keg_regex, :formula_prefix, :formula_buildpath
def initialize(arg0, args) def initialize(arg0, args)
@arg0 = arg0 @arg0 = arg0
@ -45,6 +45,7 @@ class Cmd
@optflags = ENV.fetch("HOMEBREW_OPTFLAGS", "").split @optflags = ENV.fetch("HOMEBREW_OPTFLAGS", "").split
@deps = Set.new(ENV.fetch("HOMEBREW_DEPENDENCIES", "").split(",")) @deps = Set.new(ENV.fetch("HOMEBREW_DEPENDENCIES", "").split(","))
@formula_prefix = ENV["HOMEBREW_FORMULA_PREFIX"] @formula_prefix = ENV["HOMEBREW_FORMULA_PREFIX"]
@formula_buildpath = ENV["HOMEBREW_FORMULA_BUILDPATH"]
# matches opt or cellar prefix and formula name # matches opt or cellar prefix and formula name
@keg_regex = %r{(#{Regexp.escape(opt)}|#{Regexp.escape(cellar)})/([\w+-.@]+)} @keg_regex = %r{(#{Regexp.escape(opt)}|#{Regexp.escape(cellar)})/([\w+-.@]+)}
end end
@ -310,6 +311,9 @@ class Cmd
args += path_flags("-isystem", isystem_paths) + path_flags("-I", include_paths) args += path_flags("-isystem", isystem_paths) + path_flags("-I", include_paths)
# Add -nostdinc when building against glibc@2.13 to avoid mixing system and brewed glibc headers. # Add -nostdinc when building against glibc@2.13 to avoid mixing system and brewed glibc headers.
args << "-nostdinc" if @deps.include?("glibc@2.13") args << "-nostdinc" if @deps.include?("glibc@2.13")
# Ideally this would be -ffile-prefix-map, but that requires a minimum of GCC 8, LLVM Clang 10 or Apple Clang 12
# and detecting the version dynamically based on what `HOMEBREW_CC` may have been rewritten to point to is awkward
args << "-fdebug-prefix-map=#{formula_buildpath}=." if formula_buildpath
args args
end end
@ -319,10 +323,12 @@ class Cmd
args << "-headerpad_max_install_names" args << "-headerpad_max_install_names"
args << "-no_weak_imports" if no_weak_imports? args << "-no_weak_imports" if no_weak_imports?
args << "-no_fixup_chains" if no_fixup_chains? args << "-no_fixup_chains" if no_fixup_chains?
args << "-oso_prefix" << formula_buildpath if oso_prefix? && formula_buildpath
when :ccld, :cxxld when :ccld, :cxxld
args << "-Wl,-headerpad_max_install_names" args << "-Wl,-headerpad_max_install_names"
args << "-Wl,-no_weak_imports" if no_weak_imports? args << "-Wl,-no_weak_imports" if no_weak_imports?
args << "-Wl,-no_fixup_chains" if no_fixup_chains? args << "-Wl,-no_fixup_chains" if no_fixup_chains?
args << "-Wl,-oso_prefix,#{formula_buildpath}" if oso_prefix? && formula_buildpath
end end
args args
end end
@ -431,6 +437,10 @@ class Cmd
@args.include?("-undefineddynamic_lookup") @args.include?("-undefineddynamic_lookup")
end end
def oso_prefix?
config.include?("o")
end
def calls_ld? def calls_ld?
return true if mode == :ld return true if mode == :ld
return false unless [:ccld, :cxxld].include?(mode) return false unless [:ccld, :cxxld].include?(mode)