Skip to content

Commit

Permalink
Merge pull request #11644 from carlocab/cpuid-check
Browse files Browse the repository at this point in the history
formula_cellar_checks: check for `cpuid` instruction when needed
  • Loading branch information
carlocab committed Jul 6, 2021
2 parents f07c260 + 5ed4430 commit 10edae9
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 0 deletions.
6 changes: 6 additions & 0 deletions Library/Homebrew/extend/os/mac/keg.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,10 @@ class Keg
GENERIC_MUST_BE_WRITABLE_DIRECTORIES +
[HOMEBREW_PREFIX/"Frameworks"]
).sort.uniq.freeze

undef binary_executable_or_library_files

def binary_executable_or_library_files
mach_o_files
end
end
51 changes: 51 additions & 0 deletions Library/Homebrew/formula_cellar_checks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,36 @@ def check_service_command(formula)
"Service command does not exist" unless File.exist?(formula.service.command.first)
end

def check_cpuid_instruction(formula)
return unless formula.prefix.directory?
# TODO: add methods to `utils/ast` to allow checking for method use
return unless formula.path.read.include? "ENV.runtime_cpu_detection"
# Checking for `cpuid` only makes sense on Intel:
# https://en.wikipedia.org/wiki/CPUID
return unless Hardware::CPU.intel?

# macOS `objdump` is a bit slow, so we prioritise llvm's `llvm-objdump` (~5.7x faster)
# or binutils' `objdump` (~1.8x faster) if they are installed.
objdump = Formula["llvm"].opt_bin/"llvm-objdump" if Formula["llvm"].any_version_installed?
objdump ||= Formula["binutils"].opt_bin/"objdump" if Formula["binutils"].any_version_installed?
objdump ||= which("objdump")
objdump ||= which("objdump", ENV["HOMEBREW_PATH"])

unless objdump
return <<~EOS
No `objdump` found, so cannot check for a `cpuid` instruction. Install `objdump` with
brew install binutils
EOS
end

keg = Keg.new(formula.prefix)
return if keg.binary_executable_or_library_files.any? do |file|
cpuid_instruction?(file, objdump)
end

"No `cpuid` instruction detected. #{formula} should not use `ENV.runtime_cpu_detection`."
end

def audit_installed
@new_formula ||= false

Expand All @@ -303,6 +333,7 @@ def audit_installed
problem_if_output(check_shim_references(formula.prefix))
problem_if_output(check_plist(formula.prefix, formula.plist))
problem_if_output(check_python_symlinks(formula.name, formula.keg_only?))
problem_if_output(check_cpuid_instruction(formula))
end
alias generic_audit_installed audit_installed

Expand All @@ -311,6 +342,26 @@ def audit_installed
def relative_glob(dir, pattern)
File.directory?(dir) ? Dir.chdir(dir) { Dir[pattern] } : []
end

def cpuid_instruction?(file, objdump = "objdump")
@instruction_column_index ||= {}
@instruction_column_index[objdump] ||= if Utils.popen_read(objdump, "--version").include? "LLVM"
1 # `llvm-objdump` or macOS `objdump`
else
2 # GNU binutils `objdump`
end

has_cpuid_instruction = false
Utils.popen_read(objdump, "--disassemble", file) do |io|
until io.eof?
instruction = io.readline.split("\t")[@instruction_column_index[objdump]]&.strip
has_cpuid_instruction = instruction == "cpuid" if instruction.present?
break if has_cpuid_instruction
end
end

has_cpuid_instruction
end
end

require "extend/os/formula_cellar_checks"
4 changes: 4 additions & 0 deletions Library/Homebrew/keg.rb
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,10 @@ def delete_pyc_files!
find { |pn| FileUtils.rm_rf pn if pn.basename.to_s == "__pycache__" }
end

def binary_executable_or_library_files
elf_files
end

private

def resolve_any_conflicts(dst, dry_run: false, verbose: false, overwrite: false)
Expand Down

0 comments on commit 10edae9

Please sign in to comment.