Skip to content

Commit

Permalink
Merge pull request #9117 from MikeMcQuaid/handle-arm
Browse files Browse the repository at this point in the history
Handle macOS Homebrew on ARM
  • Loading branch information
MikeMcQuaid authored Nov 12, 2020
2 parents 8cffae8 + 2378a0b commit b43c0fe
Show file tree
Hide file tree
Showing 17 changed files with 102 additions and 36 deletions.
1 change: 1 addition & 0 deletions Library/Homebrew/.rubocop_todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Style/Documentation:
- 'keg_relocate.rb'
- 'os/linux/global.rb'
- 'os/mac/architecture_list.rb'
- 'os/mac/global.rb'
- 'os/mac/keg.rb'
- 'reinstall.rb'
- 'software_spec.rb'
Expand Down
2 changes: 1 addition & 1 deletion Library/Homebrew/brew.rb
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ class MissingEnvironmentVariables < RuntimeError; end
if e.formula.head? || e.formula.deprecated? || e.formula.disabled?
$stderr.puts <<~EOS
Please create pull requests instead of asking for help on Homebrew's GitHub,
Discourse, Twitter or IRC.
Discourse, Twitter or any other official channels.
EOS
end

Expand Down
4 changes: 3 additions & 1 deletion Library/Homebrew/dev-cmd/bottle.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
<% if root_url != "#{HOMEBREW_BOTTLE_DEFAULT_DOMAIN}/bottles" %>
root_url "<%= root_url %>"
<% end %>
<% if ![HOMEBREW_DEFAULT_PREFIX, LINUXBREW_DEFAULT_PREFIX].include?(prefix) %>
<% if ![HOMEBREW_DEFAULT_PREFIX,
HOMEBREW_MACOS_ARM_DEFAULT_PREFIX,
HOMEBREW_LINUX_DEFAULT_PREFIX].include?(prefix) %>
prefix "<%= prefix %>"
<% end %>
<% if cellar.is_a? Symbol %>
Expand Down
5 changes: 3 additions & 2 deletions Library/Homebrew/diagnostic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,9 @@ def please_create_pull_requests(what = "unsupported configuration")
<<~EOS
You will encounter build failures with some formulae.
Please create pull requests instead of asking for help on Homebrew's GitHub,
Discourse, Twitter or IRC. You are responsible for resolving any issues you
experience while you are running this #{what}.
Discourse, Twitter or any other official channels. You are responsible for
resolving any issues you experience while you are running this
#{what}.
EOS
end

Expand Down
31 changes: 23 additions & 8 deletions Library/Homebrew/extend/os/mac/diagnostic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ def fatal_setup_build_environment_checks

def supported_configuration_checks
%w[
check_for_unsupported_arch
check_for_unsupported_macos
].freeze
end
Expand Down Expand Up @@ -90,21 +91,35 @@ def check_for_non_prefixed_findutils
nil
end

def check_for_unsupported_macos
def check_for_unsupported_arch
return if Homebrew::EnvConfig.developer?
return unless Hardware::CPU.arm?

<<~EOS
You are running macOS on a #{Hardware::CPU.arch} CPU architecture.
We do not provide support for this (yet).
Reinstall Homebrew under Rosetta 2 until we support it.
#{please_create_pull_requests}
EOS
end

# TODO: remove when Big Sur is released.
return if MacOS.version == :big_sur && ENV["HOMEBREW_GITHUB_ACTIONS_BIG_SUR_TESTING"]
def check_for_unsupported_macos
return if Homebrew::EnvConfig.developer?

who = +"We"
if OS::Mac.prerelease?
what = "pre-release version"
# TODO: remove when Big Sur is supported.
what = if MacOS.version == :big_sur
return if ENV["HOMEBREW_GITHUB_ACTIONS_BIG_SUR_TESTING"]

"released but not yet supported version"
elsif OS::Mac.prerelease?
"pre-release version"
elsif OS::Mac.outdated_release?
who << " (and Apple)"
what = "old version"
else
return
"old version"
end
return if what.blank?

who.freeze

<<~EOS
Expand Down
12 changes: 6 additions & 6 deletions Library/Homebrew/extend/os/mac/hardware/cpu.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,11 @@ def universal_archs
[arch_64_bit, arch_32_bit].extend ArchitectureListExtension
end

# True when running under an Intel-based shell via Rosetta on an
# True when running under an Intel-based shell via Rosetta 2 on an
# Apple Silicon Mac. This can be detected via seeing if there's a
# conflict between what `uname` reports and the underlying `sysctl` flags,
# since the `sysctl` flags don't change behaviour under Rosetta.
def in_rosetta?
# since the `sysctl` flags don't change behaviour under Rosetta 2.
def in_rosetta2?
intel? && physical_cpu_arm64?
end

Expand Down Expand Up @@ -116,14 +116,14 @@ def sse4_2?
sysctl_bool("hw.optional.sse4_2")
end

private

# Note: this is more reliable than checking uname.
# `sysctl` returns the right answer even when running in Rosetta.
# `sysctl` returns the right answer even when running in Rosetta 2.
def physical_cpu_arm64?
sysctl_bool("hw.optional.arm64")
end

private

def sysctl_bool(key)
sysctl_int(key) == 1
end
Expand Down
1 change: 1 addition & 0 deletions Library/Homebrew/extend/os/mac/system_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def dump_verbose_config(f = $stdout)
f.puts "CLT: #{clt || "N/A"}"
f.puts "Xcode: #{xcode || "N/A"}"
f.puts "XQuartz: #{xquartz}" if xquartz
f.puts "Rosetta 2: #{Hardware::CPU.in_rosetta2?}" if Hardware::CPU.physical_cpu_arm64?
end
end
end
12 changes: 12 additions & 0 deletions Library/Homebrew/formula_installer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -235,12 +235,17 @@ def check_install_sanity
recursive_formulae = recursive_deps.map(&:to_formula)

recursive_dependencies = []
invalid_arch_dependencies = []
recursive_formulae.each do |dep|
dep_recursive_dependencies = dep.recursive_dependencies.map(&:to_s)
if dep_recursive_dependencies.include?(formula.name)
recursive_dependencies << "#{formula.full_name} depends on #{dep.full_name}"
recursive_dependencies << "#{dep.full_name} depends on #{formula.full_name}"
end

if (tab = Tab.for_formula(dep)) && tab.arch.present? && tab.arch.to_s != Hardware::CPU.arch.to_s
invalid_arch_dependencies << "#{dep} was built for #{tab.arch}"
end
end

unless recursive_dependencies.empty?
Expand All @@ -258,6 +263,13 @@ def check_install_sanity
EOS
end

unless invalid_arch_dependencies.empty?
raise CannotInstallFormulaError, <<~EOS
#{formula.full_name} dependencies not built for the #{Hardware::CPU.arch} CPU architecture:
#{invalid_arch_dependencies.join("\n ")}
EOS
end

pinned_unsatisfied_deps = recursive_deps.select do |dep|
dep.to_formula.pinned? && !dep.satisfied?(inherited_options_for(dep))
end
Expand Down
3 changes: 2 additions & 1 deletion Library/Homebrew/global.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@
"(KHTML, like Gecko) Version/10.0.3 Safari/602.4.8"

HOMEBREW_DEFAULT_PREFIX = "/usr/local"
LINUXBREW_DEFAULT_PREFIX = "/home/linuxbrew/.linuxbrew"
HOMEBREW_MACOS_ARM_DEFAULT_PREFIX = "/opt/homebrew"
HOMEBREW_LINUX_DEFAULT_PREFIX = "/home/linuxbrew/.linuxbrew"

require "fileutils"
require "os/global"
Expand Down
2 changes: 1 addition & 1 deletion Library/Homebrew/hardware.rb
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ def arch_flag(arch)
"-march=#{arch}"
end

def in_rosetta?
def in_rosetta2?
false
end
end
Expand Down
37 changes: 26 additions & 11 deletions Library/Homebrew/install.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ module Install
module_function

def perform_preinstall_checks(all_fatal: false, cc: nil)
check_prefix
check_cpu
attempt_directory_creation
check_cc_argv(cc)
Expand All @@ -28,20 +29,34 @@ def perform_build_from_source_checks(all_fatal: false)
Diagnostic.checks(:build_from_source_checks, fatal: all_fatal)
end

def check_prefix
if Hardware::CPU.intel? && HOMEBREW_PREFIX.to_s == HOMEBREW_MACOS_ARM_DEFAULT_PREFIX
odie "Cannot install in Homebrew on Intel processor in ARM default prefix (#{HOMEBREW_PREFIX})!"
elsif Hardware::CPU.arm? && HOMEBREW_PREFIX.to_s == HOMEBREW_DEFAULT_PREFIX
odie <<~EOS
Cannot install in Homebrew on ARM processor in Intel default prefix (#{HOMEBREW_PREFIX})!
Please create a new installation in #{HOMEBREW_MACOS_ARM_DEFAULT_PREFIX} using one of the
"Alternative Installs" from:
#{Formatter.url("https://docs.brew.sh/Installation")}
You can migrate your previously installed formula list with:
brew bundle dump
EOS
end
end

def check_cpu
return if Hardware::CPU.intel? && Hardware::CPU.is_64_bit?

message = "Sorry, Homebrew does not support your computer's CPU architecture!"
if Hardware::CPU.arm?
opoo message
return
elsif Hardware::CPU.ppc?
message += <<~EOS
For PowerPC Mac (PPC32/PPC64BE) support, see:
#{Formatter.url("https://github.com/mistydemeo/tigerbrew")}
EOS
end
abort message
# Handled by check_for_unsupported_arch in extend/os/mac/diagnostic.rb
return if Hardware::CPU.arm?

return unless Hardware::CPU.ppc?

odie <<~EOS
Sorry, Homebrew does not support your computer's CPU architecture!
For PowerPC Mac (PPC32/PPC64BE) support, see:
#{Formatter.url("https://github.com/mistydemeo/tigerbrew")}
EOS
end
private_class_method :check_cpu

Expand Down
6 changes: 5 additions & 1 deletion Library/Homebrew/os/global.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# typed: strict
# frozen_string_literal: true

require "os/linux/global" if OS.linux?
if OS.mac?
require "os/mac/global"
elsif OS.linux?
require "os/linux/global"
end
2 changes: 1 addition & 1 deletion Library/Homebrew/os/linux/global.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ module Homebrew
DEFAULT_PREFIX ||= if Homebrew::EnvConfig.force_homebrew_on_linux?
HOMEBREW_DEFAULT_PREFIX
else
LINUXBREW_DEFAULT_PREFIX
HOMEBREW_LINUX_DEFAULT_PREFIX
end.freeze
end
10 changes: 10 additions & 0 deletions Library/Homebrew/os/mac/global.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# typed: false
# frozen_string_literal: true

module Homebrew
DEFAULT_PREFIX ||= if Hardware::CPU.arm?
HOMEBREW_MACOS_ARM_DEFAULT_PREFIX
else
HOMEBREW_DEFAULT_PREFIX
end.freeze
end
3 changes: 2 additions & 1 deletion Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi
Original file line number Diff line number Diff line change
Expand Up @@ -13404,8 +13404,10 @@ class Object
HOMEBREW_LIBRARY = ::T.let(nil, ::T.untyped)
HOMEBREW_LIBRARY_PATH = ::T.let(nil, ::T.untyped)
HOMEBREW_LINKED_KEGS = ::T.let(nil, ::T.untyped)
HOMEBREW_LINUX_DEFAULT_PREFIX = ::T.let(nil, ::T.untyped)
HOMEBREW_LOCKS = ::T.let(nil, ::T.untyped)
HOMEBREW_LOGS = ::T.let(nil, ::T.untyped)
HOMEBREW_MACOS_ARM_DEFAULT_PREFIX = ::T.let(nil, ::T.untyped)
HOMEBREW_OFFICIAL_REPO_PREFIXES_REGEX = ::T.let(nil, ::T.untyped)
HOMEBREW_PATCHELF_RB_WRITE = ::T.let(nil, ::T.untyped)
HOMEBREW_PINNED_KEGS = ::T.let(nil, ::T.untyped)
Expand All @@ -13428,7 +13430,6 @@ class Object
HOMEBREW_VERSION = ::T.let(nil, ::T.untyped)
HOMEBREW_WWW = ::T.let(nil, ::T.untyped)
HOMEPAGE_URL = ::T.let(nil, ::T.untyped)
LINUXBREW_DEFAULT_PREFIX = ::T.let(nil, ::T.untyped)
MAXIMUM_STRING_MATCHES = ::T.let(nil, ::T.untyped)
OFFICIAL_CASK_TAPS = ::T.let(nil, ::T.untyped)
OFFICIAL_CMD_TAPS = ::T.let(nil, ::T.untyped)
Expand Down
2 changes: 2 additions & 0 deletions Library/Homebrew/tab.rb
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ def self.empty
"compiler" => DevelopmentTools.default_compiler,
"aliases" => [],
"runtime_dependencies" => nil,
"arch" => nil,
"source" => {
"path" => nil,
"tap" => nil,
Expand Down Expand Up @@ -345,6 +346,7 @@ def to_json(options = nil)
"aliases" => aliases,
"runtime_dependencies" => runtime_dependencies,
"source" => source,
"arch" => Hardware::CPU.arch,
"built_on" => built_on,
}

Expand Down
5 changes: 3 additions & 2 deletions docs/Installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ Just extract (or `git clone`) Homebrew wherever you want. Just avoid:
* `/tmp` subdirectories because Homebrew gets upset.
* `/sw` and `/opt/local` because build scripts get confused when Homebrew is there instead of Fink or MacPorts, respectively.

However do yourself a favour and install to `/usr/local`. Some things may
However do yourself a favour and install to `/usr/local` on macOS Intel, `/opt/homebrew` on macOS ARM
and `.home/linuxbrew/.linuxbrew` on Linux. Some things may
not build when installed elsewhere. One of the reasons Homebrew just
works relative to the competition is **because** we recommend installing
to `/usr/local`. *Pick another prefix at your peril!*
here. *Pick another prefix at your peril!*

```sh
mkdir homebrew && curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C homebrew
Expand Down

0 comments on commit b43c0fe

Please sign in to comment.