Модуль: OS::Mac::Keg Приватный
- Расширен модулем:
- T::Helpers
- Включает:
- SystemCommand::Mixin
- Включён в:
- Keg
- Определён в:
- extend/os/mac/keg.rb,
extend/os/mac/keg_relocate.rb
Этот модуль является частью приватного API. Этот модуль можно использовать только в репозитории Homebrew/brew. Третьим сторонам по возможности следует избегать использования этого модуля, поскольку он может быть удалён или изменён без предупреждения.
Определено в пространстве имён
Модули: ClassMethods
Краткое описание констант свернуть
- VARIABLE_REFERENCE_RX =
Эта константа является частью приватного API. Эту константу можно использовать только в репозитории Homebrew/brew. Третьим сторонам по возможности следует избегать использования этой константы, поскольку она может быть удалена или изменена без предупреждения.
/^@(loader_|executable_|r)path/- FRAMEWORK_RX =
Эта константа является частью приватного API. Эту константу можно использовать только в репозитории Homebrew/brew. Третьим сторонам по возможности следует избегать использования этой константы, поскольку она может быть удалена или изменена без предупреждения.
Соответствует ссылкам на фреймворки, например
XXX.framework/Versions/YYY/XXXиXXX.framework/XXX, как с префиксом, разделённым косой чертой, так и без него. %r{(?:^|/)(([^/]+)\.framework/(?:Versions/[^/]+/)?\2)$}
Краткое описание методов экземпляра свернуть
- #binary_executable_or_library_files ⇒ Array<MachOShim> приватный
- #change_dylib_id(id, file) ⇒ Boolean приватный
- #change_install_name(old, new, file) ⇒ Boolean приватный
- #change_rpath(old, new, file) ⇒ Boolean приватный
- #codesign_patched_binary(file) ⇒ void приватный
- #consistent_reproducible_symlink_permissions! ⇒ void приватный
Необходимо для обеспечения одинаковых разрешений символических ссылок в macOS и Linux и создания воспроизводимых бутылок.
- #delete_rpath(rpath, file) ⇒ Boolean приватный
- #dylib_id_for(file) ⇒ String приватный
- #each_linkage_for(file, linkage_type, resolve_variable_references: false, &block) ⇒ void приватный
- #egrep_args ⇒ Array<(String, String)> приватный
- #find_dylib(bad_name) ⇒ ::Pathname? приватный
- #find_dylib_suffix_from(bad_name) ⇒ String приватный
- #fix_dynamic_linkage ⇒ void приватный
- #fixed_name(file, bad_name) ⇒ String приватный
Если файл сам является dylib или бандлом, искать dylib с именем bad_name относительно каталога lib, чтобы при возможности пропустить более затратный рекурсивный поиск.
- #formula_preserve_rpath? ⇒ Boolean приватный
- #loader_name_for(file, target) ⇒ String приватный
- #mach_o_files ⇒ Array<MachOShim> приватный
- #prepare_codesign_writable_files(file, &_block) ⇒ void приватный
- #prepare_debug_symbols ⇒ void приватный
- #prepare_relocation_to_locations ⇒ ::Keg::Relocation приватный
- #recursive_fgrep_args ⇒ String приватный
- #relocate_dynamic_linkage(relocation, skip_protodesc_cold: false) ⇒ void приватный
- #relocated_name_for(old_name, relocation) ⇒ String? приватный
Методы, включённые из SystemCommand::Mixin
#system_command, #system_command!
Подробное описание методов экземпляра
#binary_executable_or_library_files ⇒ Array<MachOShim>
Этот метод является частью закрытого API. Этот метод можно использовать только в репозитории Homebrew/brew. Третьим сторонам по возможности следует избегать использования этого метода, поскольку он может быть удалён или изменён без предупреждения.
106 | # File 'extend/os/mac/keg.rb', line 106 def binary_executable_or_library_files = mach_o_files |
#change_dylib_id(id, file) ⇒ Boolean
Этот метод является частью закрытого API. Этот метод можно использовать только в репозитории Homebrew/brew. Третьим сторонам по возможности следует избегать использования этого метода, поскольку он может быть удалён или изменён без предупреждения.
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | # File 'extend/os/mac/keg.rb', line 43 def change_dylib_id(id, file) return false if file.dylib_id == id require_relocation! odebug "Changing dylib ID of #{file}\n from #{file.dylib_id}\n to #{id}" file.change_dylib_id(id, strict: false) true rescue MachO::MachOError onoe <<~EOS Failed changing dylib ID of #{file} from #{file.dylib_id} to #{id} EOS raise end |
#change_install_name(old, new, file) ⇒ Boolean
Этот метод является частью закрытого API. Этот метод можно использовать только в репозитории Homebrew/brew. Третьим сторонам по возможности следует избегать использования этого метода, поскольку он может быть удалён или изменён без предупреждения.
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | # File 'extend/os/mac/keg.rb', line 60 def change_install_name(old, new, file) return false if old == new require_relocation! odebug "Changing install name in #{file}\n from #{old}\n to #{new}" file.change_install_name(old, new, strict: false) true rescue MachO::MachOError onoe <<~EOS Failed changing install name in #{file} from #{old} to #{new} EOS raise end |
#change_rpath(old, new, file) ⇒ Boolean
Этот метод является частью закрытого API. Этот метод можно использовать только в репозитории Homebrew/brew. Третьим сторонам по возможности следует избегать использования этого метода, поскольку он может быть удалён или изменён без предупреждения.
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | # File 'extend/os/mac/keg.rb', line 77 def change_rpath(old, new, file) return false if old == new require_relocation! odebug "Changing rpath in #{file}\n from #{old}\n to #{new}" file.change_rpath(old, new, strict: false) true rescue MachO::MachOError onoe <<~EOS Failed changing rpath in #{file} from #{old} to #{new} EOS raise end |
#codesign_patched_binary(file) ⇒ void
Этот метод является частью закрытого API. Этот метод можно использовать только в репозитории Homebrew/brew. Третьим сторонам по возможности следует избегать использования этого метода, поскольку он может быть удалён или изменён без предупреждения.
Этот метод возвращает неопределённое значение.
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | # File 'extend/os/mac/keg.rb', line 109 def codesign_patched_binary(file) return if MacOS.version < :big_sur unless ::Hardware::CPU.arm? result = system_command("codesign", args: ["--verify", file], print_stderr: false) return unless result.stderr.match?(/invalid signature/i) end odebug "Codesigning #{file}" prepare_codesign_writable_files(file) do # Use quiet_system to squash notifications about resigning binaries # which already have valid signatures. return if quiet_system("codesign", "--sign", "-", "--force", "--preserve-metadata=entitlements,requirements,flags,runtime", file) # If the codesigning fails, it may be a bug in Apple's codesign utility # A known workaround is to copy the file to another inode, then move it back # erasing the previous file. Then sign again. # # TODO: remove this once the bug in Apple's codesign utility is fixed Dir::Tmpname.create("workaround") do |tmppath| FileUtils.cp file, tmppath FileUtils.mv tmppath, file, force: true end # Try signing again odebug "Codesigning (2nd try) #{file}" result = system_command("codesign", args: [ "--sign", "-", "--force", "--preserve-metadata=entitlements,requirements,flags,runtime", file ], print_stderr: false) return if result.success? # If it fails again, error out onoe <<~EOS Failed applying an ad-hoc signature to #{file}: #{result.stderr} EOS end end |
#consistent_reproducible_symlink_permissions! ⇒ void
Этот метод является частью закрытого API. Этот метод можно использовать только в репозитории Homebrew/brew. Третьим сторонам по возможности следует избегать использования этого метода, поскольку он может быть удалён или изменён без предупреждения.
Этот метод возвращает неопределённое значение.
Необходим для обеспечения единообразных прав доступа к символическим ссылкам в macOS и Linux, что позволяет создавать воспроизводимые bottle-пакеты.
194 195 196 197 198 | # File 'extend/os/mac/keg.rb', line 194 def path.find do |file| file.lchmod 0777 if file.symlink? end end |
#delete_rpath(rpath, file) ⇒ Boolean
Этот метод является частью закрытого API. Этот метод можно использовать только в репозитории Homebrew/brew. Третьим сторонам по возможности следует избегать использования этого метода, поскольку он может быть удалён или изменён без предупреждения.
94 95 96 97 98 99 100 101 102 103 | # File 'extend/os/mac/keg.rb', line 94 def delete_rpath(rpath, file) odebug "Deleting rpath #{rpath} in #{file}" file.delete_rpath(rpath, strict: false) true rescue MachO::MachOError onoe <<~EOS Failed deleting rpath #{rpath} in #{file} EOS raise end |
#dylib_id_for(file) ⇒ String
Этот метод является частью закрытого API. Этот метод можно использовать только в репозитории Homebrew/brew. Третьим сторонам по возможности следует избегать использования этого метода, поскольку он может быть удалён или изменён без предупреждения.
152 153 154 155 156 157 158 159 160 161 162 163 164 | # File 'extend/os/mac/keg_relocate.rb', line 152 def dylib_id_for(file) # Swift dylib IDs should be /usr/lib/swift return file.dylib_id if file.dylib_id.start_with?("/usr/lib/swift/libswift") # Preserve @rpath install names if the formula has specified preserve_rpath return file.dylib_id if file.dylib_id.start_with?("@rpath") && formula_preserve_rpath? # The new dylib ID should have the same basename as the old dylib ID, not # the basename of the file itself. basename = File.basename(file.dylib_id) relative_dirname = file.dirname.relative_path_from(path) (opt_record/relative_dirname/basename).to_s end |
#each_linkage_for(file, linkage_type, resolve_variable_references: false, &block) ⇒ void
Этот метод является частью закрытого API. Этот метод можно использовать только в репозитории Homebrew/brew. Третьим сторонам по возможности следует избегать использования этого метода, поскольку он может быть удалён или изменён без предупреждения.
Этот метод возвращает неопределённое значение.
145 146 147 148 149 | # File 'extend/os/mac/keg_relocate.rb', line 145 def each_linkage_for(file, linkage_type, resolve_variable_references: false, &block) file.public_send(linkage_type, resolve_variable_references:) .grep_v(VARIABLE_REFERENCE_RX) .each(&block) end |
#egrep_args ⇒ Array<(String, String)>
Этот метод является частью закрытого API. Этот метод можно использовать только в репозитории Homebrew/brew. Третьим сторонам по возможности следует избегать использования этого метода, поскольку он может быть удалён или изменён без предупреждения.
263 264 265 266 267 | # File 'extend/os/mac/keg_relocate.rb', line 263 def egrep_args grep_bin = "egrep" grep_args = "--files-with-matches" [grep_bin, grep_args] end |
#find_dylib(bad_name) ⇒ ::Pathname?
Этот метод является частью закрытого API. Этот метод можно использовать только в репозитории Homebrew/brew. Третьим сторонам по возможности следует избегать использования этого метода, поскольку он может быть удалён или изменён без предупреждения.
199 200 201 202 203 204 | # File 'extend/os/mac/keg_relocate.rb', line 199 def find_dylib(bad_name) return unless lib.directory? suffix = "/#{find_dylib_suffix_from(bad_name)}" lib.find { |pn| break pn if pn.to_s.end_with?(suffix) } end |
#find_dylib_suffix_from(bad_name) ⇒ String
Этот метод является частью закрытого API. Этот метод можно использовать только в репозитории Homebrew/brew. Третьим сторонам по возможности следует избегать использования этого метода, поскольку он может быть удалён или изменён без предупреждения.
190 191 192 193 194 195 196 | # File 'extend/os/mac/keg_relocate.rb', line 190 def find_dylib_suffix_from(bad_name) if (framework = bad_name.match(FRAMEWORK_RX)) T.must(framework[1]) else File.basename(bad_name) end end |
#fix_dynamic_linkage ⇒ void
Этот метод является частью закрытого API. Этот метод можно использовать только в репозитории Homebrew/brew. Третьим сторонам по возможности следует избегать использования этого метода, поскольку он может быть удалён или изменён без предупреждения.
Этот метод возвращает неопределённое значение.
58 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 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | # File 'extend/os/mac/keg_relocate.rb', line 58 def fix_dynamic_linkage mach_o_files.each do |file| file.ensure_writable do modified = T.let(false, T::Boolean) needs_codesigning = T.let(false, T::Boolean) modified = change_dylib_id(dylib_id_for(file), file) if file.dylib? needs_codesigning ||= modified each_linkage_for(file, :dynamically_linked_libraries) do |bad_name| # Don't fix absolute paths unless they are rooted in the build directory. new_name = if bad_name.start_with?("/") && !rooted_in_build_directory?(bad_name) bad_name else fixed_name(file, bad_name) end loader_name = loader_name_for(file, new_name) modified = change_install_name(bad_name, loader_name, file) if loader_name != bad_name needs_codesigning ||= modified end each_linkage_for(file, :rpaths) do |bad_name| new_name = opt_name_for(bad_name) loader_name = loader_name_for(file, new_name) next if loader_name == bad_name modified = change_rpath(bad_name, loader_name, file) needs_codesigning ||= modified end # Strip duplicate rpaths and rpaths rooted in the build directory. # We do this separately from the rpath relocation above to avoid # failing to relocate an rpath whose variable duplicate we deleted. each_linkage_for(file, :rpaths, resolve_variable_references: true) do |bad_name| next if !rooted_in_build_directory?(bad_name) && file.rpaths.count(bad_name) == 1 modified = delete_rpath(bad_name, file) needs_codesigning ||= modified end # codesign the file if needed codesign_patched_binary(file.to_s) if needs_codesigning end end super end |
#fixed_name(file, bad_name) ⇒ String
Этот метод является частью закрытого API. Этот метод можно использовать только в репозитории Homebrew/brew. По возможности сторонним разработчикам следует избегать использования этого метода, поскольку он может быть удалён или изменён без предупреждения.
Если file — это сама dylib или связка, найдите dylib с именем bad_name относительно каталога lib, чтобы при возможности пропустить более затратный рекурсивный поиск.
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | # File 'extend/os/mac/keg_relocate.rb', line 123 def fixed_name(file, bad_name) if bad_name.start_with? ::Keg::PREFIX_PLACEHOLDER bad_name.sub(::Keg::PREFIX_PLACEHOLDER, HOMEBREW_PREFIX) elsif bad_name.start_with? ::Keg::CELLAR_PLACEHOLDER bad_name.sub(::Keg::CELLAR_PLACEHOLDER, HOMEBREW_CELLAR) elsif (file.dylib? || file.mach_o_bundle?) && (file.dirname/bad_name).exist? "@loader_path/#{bad_name}" elsif file.mach_o_executable? && (lib/bad_name).exist? "#{lib}/#{bad_name}" elsif file.mach_o_executable? && (libexec/"lib"/bad_name).exist? "#{libexec}/lib/#{bad_name}" elsif (abs_name = find_dylib(bad_name)) && abs_name.exist? abs_name.to_s else opoo "Could not fix #{bad_name} in #{file}" bad_name end end |
#formula_preserve_rpath? ⇒ Boolean
Этот метод является частью закрытого API. Этот метод можно использовать только в репозитории Homebrew/brew. По возможности сторонним разработчикам следует избегать использования этого метода, поскольку он может быть удалён или изменён без предупреждения.
167 168 169 170 171 | # File 'extend/os/mac/keg_relocate.rb', line 167 def formula_preserve_rpath? ::Formula[name].preserve_rpath? rescue FormulaUnavailableError false end |
#loader_name_for(file, target) ⇒ String
Этот метод является частью закрытого API. Этот метод можно использовать только в репозитории Homebrew/brew. По возможности сторонним разработчикам следует избегать использования этого метода, поскольку он может быть удалён или изменён без предупреждения.
107 108 109 110 111 112 113 114 115 116 117 | # File 'extend/os/mac/keg_relocate.rb', line 107 def loader_name_for(file, target) # Use @loader_path-relative install names for other Homebrew-installed binaries. if ENV["HOMEBREW_RELOCATABLE_INSTALL_NAMES"] && target.start_with?(HOMEBREW_PREFIX) dylib_suffix = find_dylib_suffix_from(target) target_dir = ::Pathname.new(target.delete_suffix(dylib_suffix)).cleanpath "@loader_path/#{target_dir.relative_path_from(file.dirname)/dylib_suffix}" else target end end |
#mach_o_files ⇒ Array<MachOShim>
Этот метод является частью закрытого API. Этот метод можно использовать только в репозитории Homebrew/brew. По возможности сторонним разработчикам следует избегать использования этого метода, поскольку он может быть удалён или изменён без предупреждения.
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 | # File 'extend/os/mac/keg_relocate.rb', line 207 def mach_o_files hardlinks = Set.new mach_o_files = [] path.find do |pn| next if pn.symlink? || pn.directory? pn = MachOPathname.wrap(pn) next if !pn.dylib? && !pn.mach_o_bundle? && !pn.mach_o_executable? # if we've already processed a file, ignore its hardlinks (which have the same dev ID and inode) # this prevents relocations from being performed on a binary more than once next unless hardlinks.add? [pn.stat.dev, pn.stat.ino] mach_o_files << pn end mach_o_files end |
#prepare_codesign_writable_files(file, &_block) ⇒ void
Этот метод является частью закрытого API. Этот метод можно использовать только в репозитории Homebrew/brew. По возможности сторонним разработчикам следует избегать использования этого метода, поскольку он может быть удалён или изменён без предупреждения.
Этот метод возвращает неопределённое значение.
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | # File 'extend/os/mac/keg.rb', line 153 def prepare_codesign_writable_files(file, &_block) result = system_command("codesign", args: [ "--display", "--file-list", "-", file ], print_stderr: false) return unless result.success? files = result.stdout.lines.map { |f| Pathname(f.chomp) } saved_perms = {} files.each do |f| unless f.writable? saved_perms[f] = f.stat.mode FileUtils.chmod "u+rw", f.to_path end end yield ensure saved_perms&.each do |f, p| f.chmod p if p end end |
#prepare_debug_symbols ⇒ void
Этот метод является частью закрытого API. Этот метод можно использовать только в репозитории Homebrew/brew. По возможности сторонним разработчикам следует избегать использования этого метода, поскольку он может быть удалён или изменён без предупреждения.
Этот метод возвращает неопределённое значение.
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | # File 'extend/os/mac/keg.rb', line 175 def prepare_debug_symbols binary_executable_or_library_files.each do |file| file = file.to_s odebug "Extracting symbols #{file}" result = system_command("dsymutil", args: [file], print_stderr: false) next if result.success? # If it fails again, error out ofail <<~EOS Failed to extract symbols from #{file}: #{result.stderr} EOS end end |
#prepare_relocation_to_locations ⇒ ::Keg::Relocation
Этот метод является частью закрытого API. Этот метод можно использовать только в репозитории Homebrew/brew. По возможности сторонним разработчикам следует избегать использования этого метода, поскольку он может быть удалён или изменён без предупреждения.
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 | # File 'extend/os/mac/keg_relocate.rb', line 227 def prepare_relocation_to_locations relocation = super brewed_perl = runtime_dependencies&.any? do |dep| dep = T.cast(dep, T::Hash[String, T.untyped]) dep["full_name"] == "perl" && dep["declared_directly"] end perl_path = if brewed_perl || name == "perl" "#{HOMEBREW_PREFIX}/opt/perl/bin/perl" elsif tab.built_on.present? && (preferred_perl_version = tab.built_on&.[]("preferred_perl")&.presence) && preferred_perl_version.match?(/^\d+\.\d+$/) && (perl_path = "/usr/bin/perl#{preferred_perl_version}") && File.exist?(perl_path) perl_path else "/usr/bin/perl#{MacOS.preferred_perl_version}" end relocation.add_replacement_pair(:perl, ::Keg::PERL_PLACEHOLDER, perl_path) if (openjdk = openjdk_dep_name_if_applicable) openjdk_path = HOMEBREW_PREFIX/"opt"/openjdk/"libexec/openjdk.jdk/Contents/Home" relocation.add_replacement_pair(:java, ::Keg::JAVA_PLACEHOLDER, openjdk_path.to_s) end relocation end |
#recursive_fgrep_args ⇒ String
Этот метод является частью закрытого API. Этот метод можно использовать только в репозитории Homebrew/brew. По возможности сторонним разработчикам следует избегать использования этого метода, поскольку он может быть удалён или изменён без предупреждения.
256 257 258 259 260 | # File 'extend/os/mac/keg_relocate.rb', line 256 def recursive_fgrep_args # Don't recurse into symlinks; the man page says this is the default, but # it's wrong. -O is a BSD-grep-only option. "-lrO" end |
#relocate_dynamic_linkage(relocation, skip_protodesc_cold: false) ⇒ void
Этот метод является частью закрытого API. Этот метод можно использовать только в репозитории Homebrew/brew. По возможности сторонним разработчикам следует избегать использования этого метода, поскольку он может быть удалён или изменён без предупреждения.
Этот метод возвращает неопределённое значение.
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 | # File 'extend/os/mac/keg_relocate.rb', line 27 def relocate_dynamic_linkage(relocation, skip_protodesc_cold: false) mach_o_files.each do |file| file.ensure_writable do modified = T.let(false, T::Boolean) needs_codesigning = T.let(false, T::Boolean) if file.dylib? id = relocated_name_for(file.dylib_id, relocation) modified = change_dylib_id(id, file) if id needs_codesigning ||= modified end each_linkage_for(file, :dynamically_linked_libraries) do |old_name| new_name = relocated_name_for(old_name, relocation) modified = change_install_name(old_name, new_name, file) if new_name needs_codesigning ||= modified end each_linkage_for(file, :rpaths) do |old_name| new_name = relocated_name_for(old_name, relocation) modified = change_rpath(old_name, new_name, file) if new_name needs_codesigning ||= modified end # codesign the file if needed codesign_patched_binary(file.to_s) if needs_codesigning end end end |
#relocated_name_for(old_name, relocation) ⇒ String?
Этот метод является частью закрытого API. Этот метод можно использовать только в репозитории Homebrew/brew. По возможности сторонним разработчикам следует избегать использования этого метода, поскольку он может быть удалён или изменён без предупреждения.
174 175 176 177 178 179 180 181 182 183 | # File 'extend/os/mac/keg_relocate.rb', line 174 def relocated_name_for(old_name, relocation) old_prefix, new_prefix = relocation.replacement_pair_for(:prefix) old_cellar, new_cellar = relocation.replacement_pair_for(:cellar) if old_name.start_with? old_cellar old_name.sub(old_cellar, new_cellar) elsif old_name.start_with? old_prefix old_name.sub(old_prefix, new_prefix) end end |
© 2009–present Homebrew contributors
Licensed under the BSD 2-Clause License.
https://docs.brew.sh/rubydoc/OS/Mac/Keg.html