Class: LinkageChecker

Inherits:
Object
  • Object
show all
Defined in:
Library/Homebrew/os/mac/linkage_checker.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(keg, formula = nil) ⇒ LinkageChecker

Returns a new instance of LinkageChecker



10
11
12
13
14
15
16
17
18
19
20
21
22
# File 'Library/Homebrew/os/mac/linkage_checker.rb', line 10

def initialize(keg, formula = nil)
  @keg = keg
  @formula = formula || resolve_formula(keg)
  @brewed_dylibs = Hash.new { |h, k| h[k] = Set.new }
  @system_dylibs = Set.new
  @broken_dylibs = Set.new
  @variable_dylibs = Set.new
  @indirect_deps = []
  @undeclared_deps = []
  @reverse_links = Hash.new { |h, k| h[k] = Set.new }
  @unnecessary_deps = []
  check_dylibs
end

Instance Attribute Details

#brewed_dylibsObject (readonly)

Returns the value of attribute brewed_dylibs



7
8
9
# File 'Library/Homebrew/os/mac/linkage_checker.rb', line 7

def brewed_dylibs
  @brewed_dylibs
end

#broken_dylibsObject (readonly)

Returns the value of attribute broken_dylibs



7
8
9
# File 'Library/Homebrew/os/mac/linkage_checker.rb', line 7

def broken_dylibs
  @broken_dylibs
end

#formulaObject (readonly)

Returns the value of attribute formula



6
7
8
# File 'Library/Homebrew/os/mac/linkage_checker.rb', line 6

def formula
  @formula
end

#kegObject (readonly)

Returns the value of attribute keg



6
7
8
# File 'Library/Homebrew/os/mac/linkage_checker.rb', line 6

def keg
  @keg
end

Returns the value of attribute reverse_links



8
9
10
# File 'Library/Homebrew/os/mac/linkage_checker.rb', line 8

def reverse_links
  @reverse_links
end

#system_dylibsObject (readonly)

Returns the value of attribute system_dylibs



7
8
9
# File 'Library/Homebrew/os/mac/linkage_checker.rb', line 7

def system_dylibs
  @system_dylibs
end

#undeclared_depsObject (readonly)

Returns the value of attribute undeclared_deps



8
9
10
# File 'Library/Homebrew/os/mac/linkage_checker.rb', line 8

def undeclared_deps
  @undeclared_deps
end

#unnecessary_depsObject (readonly)

Returns the value of attribute unnecessary_deps



8
9
10
# File 'Library/Homebrew/os/mac/linkage_checker.rb', line 8

def unnecessary_deps
  @unnecessary_deps
end

#variable_dylibsObject (readonly)

Returns the value of attribute variable_dylibs



7
8
9
# File 'Library/Homebrew/os/mac/linkage_checker.rb', line 7

def variable_dylibs
  @variable_dylibs
end

Instance Method Details

#broken_dylibs?Boolean

Returns:

  • (Boolean)


130
131
132
# File 'Library/Homebrew/os/mac/linkage_checker.rb', line 130

def broken_dylibs?
  !@broken_dylibs.empty?
end

#check_dylibsObject



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'Library/Homebrew/os/mac/linkage_checker.rb', line 24

def check_dylibs
  @keg.find do |file|
    next if file.symlink? || file.directory?
    next unless 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
    file.dynamically_linked_libraries(except: :LC_LOAD_WEAK_DYLIB).each do |dylib|
      @reverse_links[dylib] << file
      if dylib.start_with? "@"
        @variable_dylibs << dylib
      else
        begin
          owner = Keg.for Pathname.new(dylib)
        rescue NotAKegError
          @system_dylibs << dylib
        rescue Errno::ENOENT
          next if harmless_broken_link?(dylib)
          @broken_dylibs << dylib
        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
  end

  @indirect_deps, @undeclared_deps, @unnecessary_deps = check_undeclared_deps if formula
end

#check_undeclared_depsObject



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'Library/Homebrew/os/mac/linkage_checker.rb', line 59

def check_undeclared_deps
  filter_out = proc do |dep|
    next true if dep.build?
    next false unless dep.optional? || dep.recommended?
    formula.build.without?(dep)
  end
  declared_deps = formula.deps.reject { |dep| filter_out.call(dep) }.map(&:name)
  recursive_deps = keg.to_formula.runtime_dependencies.map { |dep| dep.to_formula.full_name }
  declared_dep_names = declared_deps.map { |dep| dep.split("/").last }
  indirect_deps = []
  undeclared_deps = []
  @brewed_dylibs.each_key do |full_name|
    name = full_name.split("/").last
    next if name == formula.name
    if recursive_deps.include?(name)
      indirect_deps << full_name unless declared_dep_names.include?(name)
    else
      undeclared_deps << full_name
    end
  end
  sort_by_formula_full_name!(indirect_deps)
  sort_by_formula_full_name!(undeclared_deps)
  unnecessary_deps = declared_dep_names.reject do |full_name|
    name = full_name.split("/").last
    next true if Formula[name].bin.directory?
    @brewed_dylibs.keys.map { |x| x.split("/").last }.include?(name)
  end
  [indirect_deps, undeclared_deps, unnecessary_deps]
end

#display_normal_outputObject



101
102
103
104
105
106
107
108
109
# File 'Library/Homebrew/os/mac/linkage_checker.rb', line 101

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 "Undeclared dependencies with linkage", @undeclared_deps
  display_items "Dependencies with no linkage", @unnecessary_deps
end

#display_reverse_outputObject



111
112
113
114
115
116
117
118
119
120
121
122
# File 'Library/Homebrew/os/mac/linkage_checker.rb', line 111

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.strip_prefix "#{@keg}/"
      puts "  #{unprefixed}"
    end
    puts unless dylib == sorted.last[0]
  end
end

#display_test_outputObject



124
125
126
127
128
# File 'Library/Homebrew/os/mac/linkage_checker.rb', line 124

def display_test_output
  display_items "Missing libraries", @broken_dylibs
  display_items "Possible unnecessary dependencies", @unnecessary_deps
  puts "No broken dylib links" if @broken_dylibs.empty?
end

#sort_by_formula_full_name!(arr) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
# File 'Library/Homebrew/os/mac/linkage_checker.rb', line 89

def sort_by_formula_full_name!(arr)
  arr.sort! do |a, b|
    if a.include?("/") && !b.include?("/")
      1
    elsif !a.include?("/") && b.include?("/")
      -1
    else
      a <=> b
    end
  end
end

#undeclared_deps?Boolean

Returns:

  • (Boolean)


134
135
136
# File 'Library/Homebrew/os/mac/linkage_checker.rb', line 134

def undeclared_deps?
  !@undeclared_deps.empty?
end

#unnecessary_deps?Boolean

Returns:

  • (Boolean)


138
139
140
# File 'Library/Homebrew/os/mac/linkage_checker.rb', line 138

def unnecessary_deps?
  !@unnecessary_deps.empty?
end