In ELFShim, #needed_libraries, #dynamic_elf? and #with_interpreter? check using patchelf gem.

Having HOMEBREW_PATCHELF_RB set in the ENV,
will conditionally install patchelf.rb gem,
use patchelf.rb in the above mentioned methods.
The installed vendored gems are listed in .gitignore
to maintain a clean state.
This commit is contained in:
rmnull 2020-06-02 18:36:13 +05:30
parent 67c843b91e
commit 486114282c
No known key found for this signature in database
GPG Key ID: 35BAB82D31EFAD91
4 changed files with 55 additions and 6 deletions

11
.gitignore vendored
View File

@ -129,9 +129,6 @@
**/vendor/bundle/ruby/*/gems/simplecov-*/
**/vendor/bundle/ruby/*/gems/simplecov-cobertura-*/
**/vendor/bundle/ruby/*/gems/simplecov-html-*/
**/vendor/bundle/ruby/*/gems/sorbet-*/
**/vendor/bundle/ruby/*/gems/sorbet-runtime-*/
**/vendor/bundle/ruby/*/gems/tapioca-*/
**/vendor/bundle/ruby/*/gems/term-ansicolor-*/
**/vendor/bundle/ruby/*/gems/thor-*/
**/vendor/bundle/ruby/*/gems/tins-*/
@ -140,6 +137,14 @@
**/vendor/bundle/ruby/*/gems/unicode-display_width-*/
**/vendor/bundle/ruby/*/gems/webrobots-*/
# Ignore conditional dependencies we don't wish to vendor
**/vendor/bundle/ruby/*/gems/bindata-*/
**/vendor/bundle/ruby/*/gems/elftools-*/
**/vendor/bundle/ruby/*/gems/patchelf-*/
**/vendor/bundle/ruby/*/gems/sorbet-*/
**/vendor/bundle/ruby/*/gems/sorbet-runtime-*/
**/vendor/bundle/ruby/*/gems/tapioca-*/
# Ignore `bin` contents (again).
/bin

View File

@ -23,6 +23,7 @@ end
gem "activesupport"
gem "concurrent-ruby"
gem "mechanize"
gem "patchelf" if ENV["HOMEBREW_PATCHELF_RB"]
gem "plist"
gem "rubocop-performance"
gem "rubocop-rspec"

View File

@ -74,7 +74,14 @@ module ELFShim
@with_interpreter = if binary_executable?
true
elsif dylib?
if which "readelf"
if HOMEBREW_PATCHELF_RB
begin
patchelf_patcher.interpreter.present?
rescue PatchELF::PatchError => e
opoo e
false
end
elsif which "readelf"
Utils.popen_read("readelf", "-l", to_path).include?(" INTERP ")
elsif which "file"
Utils.popen_read("file", "-L", "-b", to_path).include?(" interpreter ")
@ -89,7 +96,9 @@ module ELFShim
def dynamic_elf?
return @dynamic_elf if defined? @dynamic_elf
@dynamic_elf = if which "readelf"
@dynamic_elf = if HOMEBREW_PATCHELF_RB
patchelf_patcher.instance_variable_get(:@elf).segment_by_type(:DYNAMIC).present?
elsif which "readelf"
Utils.popen_read("readelf", "-l", to_path).include?(" DYNAMIC ")
elsif which "file"
!Utils.popen_read("file", "-L", "-b", to_path)[/dynamic|shared/].nil?
@ -127,7 +136,9 @@ module ELFShim
private
def needed_libraries(path)
if DevelopmentTools.locate "readelf"
if HOMEBREW_PATCHELF_RB
needed_libraries_using_patchelf_rb path
elsif DevelopmentTools.locate "readelf"
needed_libraries_using_readelf path
elsif DevelopmentTools.locate "patchelf"
needed_libraries_using_patchelf path
@ -138,6 +149,25 @@ module ELFShim
end
end
def needed_libraries_using_patchelf_rb(path)
patcher = path.patchelf_patcher
return [nil, []] unless patcher
soname = begin
patcher.soname
rescue PatchELF::PatchError => e
opoo e unless e.to_s.start_with? "Entry DT_SONAME not found, not a shared library?"
nil
end
needed = begin
patcher.needed
rescue PatchELF::PatchError => e
opoo e
[]
end
[soname, needed]
end
def needed_libraries_using_patchelf(path)
return [nil, []] unless path.dynamic_elf?
@ -172,6 +202,16 @@ module ELFShim
end
end
def patchelf_patcher
return unless HOMEBREW_PATCHELF_RB
@patchelf_patcher ||= begin
Homebrew.install_bundler_gems!
require "patchelf"
PatchELF::Patcher.new to_s, logging: false
end
end
def metadata
@metadata ||= Metadata.new(self)
end

View File

@ -1,5 +1,8 @@
# frozen_string_literal: true
# enables experimental readelf.rb, patchelf support.
HOMEBREW_PATCHELF_RB = ENV["HOMEBREW_PATCHELF_RB"].present?.freeze
module Homebrew
DEFAULT_PREFIX ||= if Homebrew::EnvConfig.force_homebrew_on_linux?
HOMEBREW_DEFAULT_PREFIX