Class: LinkageChecker
- Inherits:
-
Object
- Object
- LinkageChecker
- Defined in:
- Library/Homebrew/linkage_checker.rb,
Library/Homebrew/extend/os/linux/linkage_checker.rb
Overview
typed: true frozen_string_literal: true
Constant Summary collapse
- SYSTEM_LIBRARY_ALLOWLIST =
Libraries provided by glibc and gcc.
%w[ ld-linux-x86-64.so.2 libanl.so.1 libc.so.6 libcrypt.so.1 libdl.so.2 libm.so.6 libmvec.so.1 libnsl.so.1 libpthread.so.0 libresolv.so.2 librt.so.1 libthread_db.so.1 libutil.so.1 libgcc_s.so.1 libgomp.so.1 libstdc++.so.6 ].freeze
Instance Attribute Summary collapse
- #formula ⇒ Object readonly private
- #keg ⇒ Object readonly private
- #store ⇒ Object readonly private
- #undeclared_deps ⇒ Object readonly private
Instance Method Summary collapse
- #broken_dylibs_with_expectations ⇒ Object private
- #broken_library_linkage? ⇒ Boolean private
- #check_dylibs(rebuild_cache:) ⇒ Object private
- #display_normal_output ⇒ Object private
- #display_reverse_output ⇒ Object private
- #display_test_output(puts_output: true) ⇒ Object private
-
#initialize(keg, formula = nil, cache_db:, rebuild_cache: false) ⇒ LinkageChecker
constructor
private
A new instance of LinkageChecker.
- #unexpected_broken_dylibs ⇒ Object private
- #unexpected_present_dylibs ⇒ Object private
Constructor Details
#initialize(keg, formula = nil, cache_db:, rebuild_cache: false) ⇒ LinkageChecker
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns a new instance of LinkageChecker.
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'Library/Homebrew/linkage_checker.rb', line 15 def initialize(keg, formula = nil, cache_db:, rebuild_cache: false) @keg = keg @formula = formula || resolve_formula(keg) @store = LinkageCacheStore.new(keg.to_s, cache_db) @system_dylibs = Set.new @broken_dylibs = Set.new @unexpected_broken_dylibs = nil @unexpected_present_dylibs = nil @variable_dylibs = Set.new @brewed_dylibs = Hash.new { |h, k| h[k] = Set.new } @reverse_links = Hash.new { |h, k| h[k] = Set.new } @broken_deps = Hash.new { |h, k| h[k] = [] } @indirect_deps = [] @undeclared_deps = [] @unnecessary_deps = [] @unwanted_system_dylibs = [] @version_conflict_deps = [] check_dylibs(rebuild_cache: rebuild_cache) end |
Instance Attribute Details
#formula ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
13 14 15 |
# File 'Library/Homebrew/linkage_checker.rb', line 13 def formula @formula end |
#keg ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
13 14 15 |
# File 'Library/Homebrew/linkage_checker.rb', line 13 def keg @keg end |
#store ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
13 14 15 |
# File 'Library/Homebrew/linkage_checker.rb', line 13 def store @store end |
#undeclared_deps ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
13 14 15 |
# File 'Library/Homebrew/linkage_checker.rb', line 13 def undeclared_deps @undeclared_deps end |
Instance Method Details
#broken_dylibs_with_expectations ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
114 115 116 117 118 119 120 121 122 123 124 |
# File 'Library/Homebrew/linkage_checker.rb', line 114 def broken_dylibs_with_expectations output = {} @broken_dylibs.each do |broken_lib| output[broken_lib] = if unexpected_broken_dylibs.include? broken_lib ["unexpected"] else ["expected"] end end output end |
#broken_library_linkage? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
81 82 83 84 |
# File 'Library/Homebrew/linkage_checker.rb', line 81 def broken_library_linkage? issues = [@broken_deps, @unwanted_system_dylibs, @version_conflict_deps] [issues, unexpected_broken_dylibs, unexpected_present_dylibs].flatten.any?(&:present?) end |
#check_dylibs(rebuild_cache:) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
# File 'Library/Homebrew/linkage_checker.rb', line 133 def check_dylibs(rebuild_cache:) keg_files_dylibs = nil if rebuild_cache store&.delete! else keg_files_dylibs = store&.fetch(:keg_files_dylibs) end keg_files_dylibs_was_empty = false keg_files_dylibs ||= {} if keg_files_dylibs.empty? keg_files_dylibs_was_empty = true @keg.find do |file| next if file.symlink? || file.directory? next if !file.dylib? && !file.binary_executable? && !file.mach_o_bundle? # weakly loaded dylibs may not actually exist on disk, so skip them # when checking for broken linkage keg_files_dylibs[file] = file.dynamically_linked_libraries(except: :LC_LOAD_WEAK_DYLIB) end end checked_dylibs = Set.new keg_files_dylibs.each do |file, dylibs| dylibs.each do |dylib| @reverse_links[dylib] << file next if checked_dylibs.include? dylib checked_dylibs << dylib if dylib.start_with? "@" @variable_dylibs << dylib next end begin owner = Keg.for Pathname.new(dylib) rescue NotAKegError @system_dylibs << dylib rescue Errno::ENOENT next if harmless_broken_link?(dylib) if (dep = dylib_to_dep(dylib)) @broken_deps[dep] |= [dylib] elsif MacOS.version >= :big_sur && dylib_found_via_dlopen(dylib) # If we cannot associate the dylib with a dependency, then it may be a system library. # In macOS Big Sur and later, system libraries do not exist on-disk and instead exist in a cache. # If dlopen finds the dylib, then the linkage is not broken. @system_dylibs << dylib else @broken_dylibs << dylib end else tap = Tab.for_keg(owner).tap f = if tap.nil? || tap.core_tap? owner.name else "#{tap}/#{owner.name}" end @brewed_dylibs[f] << dylib end end end if formula @indirect_deps, @undeclared_deps, @unnecessary_deps, @version_conflict_deps = check_formula_deps end return unless keg_files_dylibs_was_empty store&.update!(keg_files_dylibs: keg_files_dylibs) end |
#display_normal_output ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
37 38 39 40 41 42 43 44 45 46 47 |
# File 'Library/Homebrew/linkage_checker.rb', line 37 def display_normal_output display_items "System libraries", @system_dylibs display_items "Homebrew libraries", @brewed_dylibs display_items "Indirect dependencies with linkage", @indirect_deps display_items "Variable-referenced libraries", @variable_dylibs display_items "Missing libraries", @broken_dylibs display_items "Broken dependencies", @broken_deps display_items "Undeclared dependencies with linkage", @undeclared_deps display_items "Dependencies with no linkage", @unnecessary_deps display_items "Unwanted system libraries", @unwanted_system_dylibs end |
#display_reverse_output ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'Library/Homebrew/linkage_checker.rb', line 49 def display_reverse_output return if @reverse_links.empty? sorted = @reverse_links.sort sorted.each do |dylib, files| puts dylib files.each do |f| unprefixed = f.to_s.delete_prefix "#{keg}/" puts " #{unprefixed}" end puts if dylib != sorted.last.first end end |
#display_test_output(puts_output: true) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'Library/Homebrew/linkage_checker.rb', line 63 def display_test_output(puts_output: true) display_items "Missing libraries", broken_dylibs_with_expectations, puts_output: puts_output display_items "Unused missing linkage information", unexpected_present_dylibs, puts_output: puts_output display_items "Broken dependencies", @broken_deps, puts_output: puts_output display_items "Unwanted system libraries", @unwanted_system_dylibs, puts_output: puts_output display_items "Conflicting libraries", @version_conflict_deps, puts_output: puts_output if @broken_dylibs.empty? puts "No broken library linkage detected" elsif unexpected_broken_dylibs.empty? puts "No unexpected broken library linkage detected." else puts "Unexpected missing library linkage detected" end puts "Unexpected non-missing linkage detected" if unexpected_present_dylibs.present? end |
#unexpected_broken_dylibs ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'Library/Homebrew/linkage_checker.rb', line 86 def unexpected_broken_dylibs return @unexpected_broken_dylibs if @unexpected_broken_dylibs @unexpected_broken_dylibs = @broken_dylibs.reject do |broken_lib| @formula.class.allowed_missing_libraries.any? do |allowed_missing_lib| case allowed_missing_lib when Regexp allowed_missing_lib.match? broken_lib when String broken_lib.include? allowed_missing_lib end end end end |
#unexpected_present_dylibs ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'Library/Homebrew/linkage_checker.rb', line 101 def unexpected_present_dylibs @unexpected_present_dylibs ||= @formula.class.allowed_missing_libraries.reject do |allowed_missing_lib| @broken_dylibs.any? do |broken_lib| case allowed_missing_lib when Regexp allowed_missing_lib.match? broken_lib when String broken_lib.include? allowed_missing_lib end end end end |