| 
									
										
										
										
											2019-04-19 15:38:03 +09:00
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-22 16:56:37 -07:00
										 |  |  | class Keg | 
					
						
							|  |  |  |   def relocate_dynamic_linkage(relocation) | 
					
						
							| 
									
										
										
										
											2018-08-20 11:24:19 -07:00
										 |  |  |     # Patching the dynamic linker of glibc breaks it. | 
					
						
							| 
									
										
										
										
											2019-10-10 15:16:30 +01:00
										 |  |  |     return if name == "glibc" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-22 16:56:37 -07:00
										 |  |  |     # Patching patchelf using itself fails with "Text file busy" or SIGBUS. | 
					
						
							| 
									
										
										
										
											2019-10-10 15:16:30 +01:00
										 |  |  |     return if name == "patchelf" | 
					
						
							| 
									
										
										
										
											2018-06-22 16:56:37 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     elf_files.each do |file| | 
					
						
							|  |  |  |       file.ensure_writable do | 
					
						
							|  |  |  |         change_rpath(file, relocation.old_prefix, relocation.new_prefix) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def change_rpath(file, old_prefix, new_prefix) | 
					
						
							|  |  |  |     return if !file.elf? || !file.dynamic_elf? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     patchelf = DevelopmentTools.locate "patchelf" | 
					
						
							|  |  |  |     cmd_rpath = [patchelf, "--print-rpath", file] | 
					
						
							|  |  |  |     old_rpath = Utils.popen_read(*cmd_rpath, err: :out).strip | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # patchelf requires that the ELF file have a .dynstr section. | 
					
						
							|  |  |  |     # Skip ELF files that do not have a .dynstr section. | 
					
						
							|  |  |  |     return if ["cannot find section .dynstr", "strange: no string table"].include?(old_rpath) | 
					
						
							| 
									
										
										
										
											2018-07-16 23:17:16 +02:00
										 |  |  |     unless $CHILD_STATUS.success? | 
					
						
							| 
									
										
										
										
											2018-10-02 15:13:15 -07:00
										 |  |  |       raise ErrorDuringExecution.new(cmd_rpath, status: $CHILD_STATUS, output: [[:stderr, old_rpath]]) | 
					
						
							| 
									
										
										
										
											2018-07-16 23:17:16 +02:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2018-06-22 16:56:37 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     rpath = old_rpath | 
					
						
							|  |  |  |             .split(":") | 
					
						
							|  |  |  |             .map { |x| x.sub(old_prefix, new_prefix) } | 
					
						
							|  |  |  |             .select { |x| x.start_with?(new_prefix, "$ORIGIN") } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     lib_path = "#{new_prefix}/lib" | 
					
						
							|  |  |  |     rpath << lib_path unless rpath.include? lib_path | 
					
						
							|  |  |  |     new_rpath = rpath.join(":") | 
					
						
							|  |  |  |     cmd = [patchelf, "--force-rpath", "--set-rpath", new_rpath] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-18 15:22:09 +08:00
										 |  |  |     if file.with_interpreter? | 
					
						
							| 
									
										
										
										
											2018-06-22 16:56:37 -07:00
										 |  |  |       old_interpreter = Utils.safe_popen_read(patchelf, "--print-interpreter", file).strip | 
					
						
							|  |  |  |       new_interpreter = if File.readable? "#{new_prefix}/lib/ld.so" | 
					
						
							|  |  |  |         "#{new_prefix}/lib/ld.so" | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         old_interpreter.sub old_prefix, new_prefix | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |       cmd << "--set-interpreter" << new_interpreter if old_interpreter != new_interpreter | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return if old_rpath == new_rpath && old_interpreter == new_interpreter | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-22 16:56:37 -07:00
										 |  |  |     safe_system(*cmd, file) | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def detect_cxx_stdlibs(options = {}) | 
					
						
							|  |  |  |     skip_executables = options.fetch(:skip_executables, false) | 
					
						
							|  |  |  |     results = Set.new | 
					
						
							|  |  |  |     elf_files.each do |file| | 
					
						
							|  |  |  |       next unless file.dynamic_elf? | 
					
						
							|  |  |  |       next if file.binary_executable? && skip_executables | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-22 16:56:37 -07:00
										 |  |  |       dylibs = file.dynamically_linked_libraries | 
					
						
							|  |  |  |       results << :libcxx if dylibs.any? { |s| s.include? "libc++.so" } | 
					
						
							|  |  |  |       results << :libstdcxx if dylibs.any? { |s| s.include? "libstdc++.so" } | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |     results.to_a | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def elf_files | 
					
						
							|  |  |  |     hardlinks = Set.new | 
					
						
							|  |  |  |     elf_files = [] | 
					
						
							|  |  |  |     path.find do |pn| | 
					
						
							|  |  |  |       next if pn.symlink? || pn.directory? | 
					
						
							|  |  |  |       next if !pn.dylib? && !pn.binary_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] | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-22 16:56:37 -07:00
										 |  |  |       elf_files << pn | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |     elf_files | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def self.relocation_formulae | 
					
						
							|  |  |  |     ["patchelf"] | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2018-10-01 16:36:03 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   def self.bottle_dependencies | 
					
						
							|  |  |  |     @bottle_dependencies ||= begin | 
					
						
							|  |  |  |       formulae = relocation_formulae | 
					
						
							|  |  |  |       gcc = Formula["gcc"] | 
					
						
							|  |  |  |       if !ENV["HOMEBREW_FORCE_HOMEBREW_ON_LINUX"] && | 
					
						
							|  |  |  |          DevelopmentTools.non_apple_gcc_version("gcc") < gcc.version.to_i | 
					
						
							|  |  |  |         formulae += gcc.recursive_dependencies.map(&:name) | 
					
						
							|  |  |  |         formulae << gcc.name | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |       formulae | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2018-06-22 16:56:37 -07:00
										 |  |  | end |