Skip to content

Don't relocate Apple Silicon bottles for default prefix #19384

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
78c3bf9
Don't relocate Apple Silicon bottles for default prefix
samuelarogbonlo Feb 26, 2025
eacb107
Update implementation based on feedback: use env var for gradual roll…
samuelarogbonlo Feb 26, 2025
415582a
Merge branch 'master' into no-relocation-apple-silicon
samuelarogbonlo Feb 28, 2025
0c7cd61
Merge branch 'master' into no-relocation-apple-silicon
samuelarogbonlo Mar 2, 2025
382bc68
Implement binary relocation detection and tab storage
samuelarogbonlo Mar 10, 2025
90a8a37
Merge branch 'master' into no-relocation-apple-silicon
samuelarogbonlo Mar 10, 2025
5b8073c
Fix syntax and style issues
samuelarogbonlo Mar 10, 2025
5c90793
Trigger CI run
samuelarogbonlo Mar 10, 2025
28677ca
Move OS detection to extend/os files
samuelarogbonlo Mar 11, 2025
ee2f160
Remove direct OS.mac? calls
samuelarogbonlo Mar 11, 2025
4606f65
Fix syntax error
samuelarogbonlo Mar 11, 2025
7092e4f
Update formula_installer.rb with minimal changes
samuelarogbonlo Mar 11, 2025
b31e906
Address reviewer feedback: adjust approach to relocation
samuelarogbonlo Mar 11, 2025
585e362
Merge branch 'master' into no-relocation-apple-silicon
samuelarogbonlo Mar 20, 2025
296f9dd
Fix style issues
samuelarogbonlo Mar 20, 2025
9000799
Merge branch 'master' into no-relocation-apple-silicon
samuelarogbonlo Mar 20, 2025
f9f2fd6
Fix style issues
samuelarogbonlo Mar 20, 2025
fd2b54c
Fix parameter name in skip_relocation_for_apple_silicon?
samuelarogbonlo Mar 20, 2025
0ad6185
Fix parameter names and style issues
samuelarogbonlo Mar 20, 2025
9cc4cae
Fix parameter names and style issues
samuelarogbonlo Mar 20, 2025
bf23643
Fix parameter naming consistency for skip_relocation_for_apple_silicon?
samuelarogbonlo Mar 20, 2025
da8cc3c
Fix parameter name in skip_relocation_for_apple_silicon?
samuelarogbonlo Mar 20, 2025
8249c9b
Merge branch 'master' into no-relocation-apple-silicon
samuelarogbonlo Mar 29, 2025
7b8c03a
change how keg_only is handled
samuelarogbonlo Mar 29, 2025
9141156
change how keg is handled
samuelarogbonlo Mar 29, 2025
e019bd5
change how keg is handled
samuelarogbonlo Mar 29, 2025
6ebd623
change how keg is handled
samuelarogbonlo Mar 29, 2025
d22daaf
change how keg is handled
samuelarogbonlo Mar 29, 2025
b6a9754
cleanup for CI jobs
samuelarogbonlo Mar 29, 2025
ff01f23
change how keg is handled
samuelarogbonlo Mar 29, 2025
63c2de0
whitespace cleanup
samuelarogbonlo Mar 29, 2025
2ac554a
whitespace cleanup
samuelarogbonlo Mar 29, 2025
a75a672
whitespace cleanup
samuelarogbonlo Mar 29, 2025
c48fb91
Fix hash alignment in tab.rb
samuelarogbonlo Mar 29, 2025
bb22a2d
whitespace cleanup
samuelarogbonlo Mar 29, 2025
a3bc7d3
whitespace cleanup
samuelarogbonlo Mar 29, 2025
2315426
whitespace cleanup
samuelarogbonlo Mar 29, 2025
e3d7d8d
whitespace cleanup
samuelarogbonlo Mar 29, 2025
056b4c5
whitespace cleanup
samuelarogbonlo Mar 29, 2025
7de3307
whitespace cleanup
samuelarogbonlo Mar 29, 2025
02e1f9b
whitespace cleanup
samuelarogbonlo Mar 29, 2025
9f59138
whitespace cleanup
samuelarogbonlo Mar 29, 2025
c84bc6c
Merge branch 'master' into no-relocation-apple-silicon
samuelarogbonlo Mar 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Library/Homebrew/extend/os/bottles.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
# frozen_string_literal: true

require "extend/os/mac/utils/bottles" if OS.mac?
require "extend/os/linux/utils/bottles" if OS.linux?
18 changes: 18 additions & 0 deletions Library/Homebrew/extend/os/linux/utils/bottles.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# typed: strict
# frozen_string_literal: true

module Utils
module Bottles
class << self
module LinuxOverride
# Linux implementation stays with the default
sig { returns(T::Boolean) }
def on_macos?
false
end
end

prepend LinuxOverride
end
end
end
5 changes: 5 additions & 0 deletions Library/Homebrew/extend/os/mac/utils/bottles.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ def tag(tag = nil)

super
end

sig {returns(T::Boolean) }
def on_macos?
true
end
end

prepend MacOSOverride
Expand Down
2 changes: 2 additions & 0 deletions Library/Homebrew/formula_installer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1502,6 +1502,7 @@ def pour
tab.unused_options = []
tab.built_as_bottle = true
tab.poured_from_bottle = true
if Hardware::CPU.arm? && Utils::Bottles.on_macos?
tab.loaded_from_api = formula.loaded_from_api?
tab.installed_as_dependency = installed_as_dependency?
tab.installed_on_request = installed_on_request?
Expand Down Expand Up @@ -1730,3 +1731,4 @@ def puts_requirement_messages
end

require "extend/os/formula_installer"
end
10 changes: 9 additions & 1 deletion Library/Homebrew/keg_relocate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ def prepare_relocation_to_placeholders
alias generic_prepare_relocation_to_placeholders prepare_relocation_to_placeholders

def replace_locations_with_placeholders
# Skip relocation for Apple Silicon with default prefix
return [] if Utils::Bottles.skip_relocation_for_apple_silicon?(self)


relocation = prepare_relocation_to_placeholders.freeze
relocate_dynamic_linkage(relocation)
replace_text_in_files(relocation)
Expand All @@ -125,7 +129,11 @@ def prepare_relocation_to_locations
end
alias generic_prepare_relocation_to_locations prepare_relocation_to_locations

def replace_placeholders_with_locations(files, skip_linkage: false)
def replace_placeholders_with_locations(files = nil, skip_linkage: false)
# Skip relocation for Apple Silicon with default prefix
return if Utils::Bottles.skip_relocation_for_apple_silicon?(self)


relocation = prepare_relocation_to_locations.freeze
relocate_dynamic_linkage(relocation) unless skip_linkage
replace_text_in_files(relocation, files:)
Expand Down
4 changes: 3 additions & 1 deletion Library/Homebrew/tab.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ def self.empty
"tap_git_head" => nil,
},
"built_on" => DevelopmentTools.build_system_info,
"skip_relocation_for_apple_silicon" => false,
}

new(attributes)
Expand Down Expand Up @@ -139,7 +140,7 @@ class Tab < AbstractTab
# @api internal
attr_accessor :poured_from_bottle

attr_accessor :built_as_bottle, :changed_files, :stdlib, :aliases
attr_accessor :built_as_bottle, :changed_files, :stdlib, :aliases, :skip_relocation_for_apple_silicon
attr_writer :used_options, :unused_options, :compiler, :source_modified_time
attr_reader :tapped_from

Expand Down Expand Up @@ -403,6 +404,7 @@ def to_json(options = nil)
"unused_options" => unused_options.as_flags,
"built_as_bottle" => built_as_bottle,
"poured_from_bottle" => poured_from_bottle,
"skip_relocation_for_apple_silicon" => skip_relocation_for_apple_silicon,
"loaded_from_api" => loaded_from_api,
"installed_as_dependency" => installed_as_dependency,
"installed_on_request" => installed_on_request,
Expand Down
91 changes: 91 additions & 0 deletions Library/Homebrew/test/utils/bottles/bottles_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,95 @@ class #{Formulary.class_s(formula_name)} < Formula
end
end
end

describe "#skip_relocation_for_apple_silicon?" do
let(:keg) { double("keg") }

before do
allow(keg).to receive(:mach_o_files).and_return([])
end

it "returns true for Apple Silicon with default prefix when enabled by env var" do
allow(Hardware::CPU).to receive(:arm?).and_return(true)
allow(OS).to receive(:mac?).and_return(true)
allow(HOMEBREW_PREFIX).to receive(:to_s).and_return(HOMEBREW_MACOS_ARM_DEFAULT_PREFIX)
allow(ENV).to receive(:fetch).with("HOMEBREW_BOTTLE_SKIP_RELOCATION_ARM64", "false").and_return("true")

expect(described_class.skip_relocation_for_apple_silicon?).to be true
end

it "returns true for Apple Silicon with default prefix when no binaries need relocation" do
allow(Hardware::CPU).to receive(:arm?).and_return(true)
allow(OS).to receive(:mac?).and_return(true)
allow(HOMEBREW_PREFIX).to receive(:to_s).and_return(HOMEBREW_MACOS_ARM_DEFAULT_PREFIX)
allow(ENV).to receive(:fetch).with("HOMEBREW_BOTTLE_SKIP_RELOCATION_ARM64", "false").and_return("false")

expect(described_class.skip_relocation_for_apple_silicon?(keg)).to be true
end

it "returns false for Apple Silicon with default prefix when binaries need relocation" do
mach_o_file = double("mach_o_file")
allow(keg).to receive(:mach_o_files).and_return([mach_o_file])
allow(mach_o_file).to receive(:dylib?).and_return(true)
allow(mach_o_file).to receive(:dylib_id).and_return("/usr/local/lib/example.dylib")

allow(Hardware::CPU).to receive(:arm?).and_return(true)
allow(OS).to receive(:mac?).and_return(true)
allow(HOMEBREW_PREFIX).to receive(:to_s).and_return(HOMEBREW_MACOS_ARM_DEFAULT_PREFIX)
allow(ENV).to receive(:fetch).with("HOMEBREW_BOTTLE_SKIP_RELOCATION_ARM64", "false").and_return("false")

expect(described_class.skip_relocation_for_apple_silicon?(keg)).to be false
end

it "returns false for Intel Mac" do
allow(Hardware::CPU).to receive(:arm?).and_return(false)
allow(OS).to receive(:mac?).and_return(true)

expect(described_class.skip_relocation_for_apple_silicon?).to be false
expect(described_class.skip_relocation_for_apple_silicon?(keg)).to be false
end

it "returns false for custom prefix on Apple Silicon" do
allow(Hardware::CPU).to receive(:arm?).and_return(true)
allow(OS).to receive(:mac?).and_return(true)
allow(HOMEBREW_PREFIX).to receive(:to_s).and_return("/custom/path")

expect(described_class.skip_relocation_for_apple_silicon?).to be false
expect(described_class.skip_relocation_for_apple_silicon?(keg)).to be false
end
end

describe "#binaries_need_relocation?" do
let(:keg) { double("keg") }
let(:mach_o_file) { double("mach_o_file") }

it "returns true when dylib has /usr/local path" do
allow(OS).to receive(:mac?).and_return(true)
allow(keg).to receive(:mach_o_files).and_return([mach_o_file])
allow(mach_o_file).to receive(:dylib?).and_return(true)
allow(mach_o_file).to receive(:dylib_id).and_return("/usr/local/lib/libexample.dylib")
allow(mach_o_file).to receive(:dynamically_linked_libraries).and_return([])

expect(described_class.binaries_need_relocation?(keg)).to be true
end

it "returns true when linked libraries have /usr/local path" do
allow(OS).to receive(:mac?).and_return(true)
allow(keg).to receive(:mach_o_files).and_return([mach_o_file])
allow(mach_o_file).to receive(:dylib?).and_return(false)
allow(mach_o_file).to receive(:dynamically_linked_libraries).and_return(["/usr/local/lib/libexample.dylib"])

expect(described_class.binaries_need_relocation?(keg)).to be true
end

it "returns false when no paths need relocation" do
allow(OS).to receive(:mac?).and_return(true)
allow(keg).to receive(:mach_o_files).and_return([mach_o_file])
allow(mach_o_file).to receive(:dylib?).and_return(true)
allow(mach_o_file).to receive(:dylib_id).and_return("/opt/homebrew/lib/libexample.dylib")
allow(mach_o_file).to receive(:dynamically_linked_libraries).and_return(["/opt/homebrew/lib/libother.dylib"])

expect(described_class.binaries_need_relocation?(keg)).to be false
end
end
end
39 changes: 39 additions & 0 deletions Library/Homebrew/utils/bottles.rb
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,44 @@ def load_tab(formula)
end
end

# Determines if bottle relocation should be skipped for Apple Silicon with default prefix
sig { params(keg: T.nilable(Keg)).returns(T::Boolean) }
def skip_relocation_for_apple_silicon?(keg = nil)
return false unless Hardware::CPU.arm?
# Don't use OS.mac? directly - use the on_macos? method instead
return false unless on_macos?
return false unless HOMEBREW_PREFIX.to_s == HOMEBREW_MACOS_ARM_DEFAULT_PREFIX

# First check if enabled by env var for gradual rollout
return true if ENV.fetch("HOMEBREW_BOTTLE_SKIP_RELOCATION_ARM64", "false") == "true"

# If not explicitly enabled by env var, check if binaries need relocation
return false unless keg

!binaries_need_relocation?(keg)
end

# Define a platform-specific method that will be overriden
def on_macos?
false # Default implementation, will be overriden in OS/mac/bottles.rb
end


# Determines if binary files in a keg need relocation
sig {params(keg: Keg).returns(T::Boolean) }
def binaries_need_relocation?(keg)
# Don't use OS.mac? directly - use the on_macos? method instead
return false unless OS.mac?

keg.mach_o_files.any? do |file|
# Check if dylib ID contains paths that need relocation
(file.dylib? && file.dylib_id&.include?("/usr/local")) ||
# Check if linked libraries contain paths that need relocation
file.dynamically_linked_libraries.any? { |lib| lib.include?("/usr/local") }
end
end


private

def bottle_file_list(bottle_file)
Expand Down Expand Up @@ -350,3 +388,4 @@ def find_matching_tag(tag, no_older_versions: false)
end

require "extend/os/bottles"
# Trigger CI run
Loading