Skip to content
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

Handle macOS Homebrew on ARM #9117

Merged
merged 3 commits into from
Nov 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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/.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?
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems Apple's recommended way to detect Rosetta 2 is to check sysctl.proc_translated.

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