diff --git a/Library/Homebrew/cmd/bottle.rb b/Library/Homebrew/cmd/bottle.rb
index 1975d7ccfe39289e536da2cd928d664b5e4b992a..50ce9470932ab935dd164caebe05e2379dac5ec9 100644
--- a/Library/Homebrew/cmd/bottle.rb
+++ b/Library/Homebrew/cmd/bottle.rb
@@ -57,15 +57,8 @@ module Homebrew
       # skip document file.
       next if Metafiles::EXTENSIONS.include? file.extname
 
-      # Check dynamic library linkage. Importantly, do not run otool on static
-      # libraries, which will falsely report "linkage" to themselves.
-      if file.mach_o_executable? || file.dylib? || file.mach_o_bundle?
-        linked_libraries = file.dynamically_linked_libraries
-        linked_libraries = linked_libraries.select { |lib| lib.include? string }
-        result ||= linked_libraries.any?
-      else
-        linked_libraries = []
-      end
+      linked_libraries = Keg.file_linked_libraries(file, string)
+      result ||= linked_libraries.any?
 
       if ARGV.verbose?
         print_filename(string, file) if linked_libraries.any?
@@ -195,9 +188,9 @@ module Homebrew
 
       begin
         unless ARGV.include? "--skip-relocation"
-          keg.relocate_install_names prefix, Keg::PREFIX_PLACEHOLDER,
+          keg.relocate_dynamic_linkage prefix, Keg::PREFIX_PLACEHOLDER,
             cellar, Keg::CELLAR_PLACEHOLDER
-          keg.relocate_text_files prefix, Keg::PREFIX_PLACEHOLDER,
+          keg.relocate_dynamic_files prefix, Keg::PREFIX_PLACEHOLDER,
             cellar, Keg::CELLAR_PLACEHOLDER
         end
 
@@ -264,7 +257,7 @@ module Homebrew
         ignore_interrupts do
           original_tab.write if original_tab
           unless ARGV.include? "--skip-relocation"
-            keg.relocate_install_names Keg::PREFIX_PLACEHOLDER, prefix,
+            keg.relocate_dynamic_linkage Keg::PREFIX_PLACEHOLDER, prefix,
               Keg::CELLAR_PLACEHOLDER, cellar
             keg.relocate_text_files Keg::PREFIX_PLACEHOLDER, prefix,
               Keg::CELLAR_PLACEHOLDER, cellar
diff --git a/Library/Homebrew/extend/os/keg_relocate.rb b/Library/Homebrew/extend/os/keg_relocate.rb
new file mode 100644
index 0000000000000000000000000000000000000000..2fde45d93a5b881418c0dbf421fa5277ddf60b90
--- /dev/null
+++ b/Library/Homebrew/extend/os/keg_relocate.rb
@@ -0,0 +1,5 @@
+require "keg_relocate"
+
+if OS.mac?
+  require "extend/os/mac/keg_relocate"
+end
diff --git a/Library/Homebrew/extend/os/mac/keg_relocate.rb b/Library/Homebrew/extend/os/mac/keg_relocate.rb
new file mode 100644
index 0000000000000000000000000000000000000000..80f6875168ef7ddb3fcbc109fdbd909b65cf43f6
--- /dev/null
+++ b/Library/Homebrew/extend/os/mac/keg_relocate.rb
@@ -0,0 +1,135 @@
+class Keg
+  def fix_dynamic_linkage
+    mach_o_files.each do |file|
+      file.ensure_writable do
+        change_dylib_id(dylib_id_for(file), file) if file.dylib?
+
+        each_install_name_for(file) do |bad_name|
+          # Don't fix absolute paths unless they are rooted in the build directory
+          next if bad_name.start_with?("/") && !bad_name.start_with?(HOMEBREW_TEMP.to_s)
+
+          new_name = fixed_name(file, bad_name)
+          change_install_name(bad_name, new_name, file) unless new_name == bad_name
+        end
+      end
+    end
+
+    generic_fix_dynamic_linkage
+  end
+
+  def relocate_dynamic_linkage(old_prefix, new_prefix, old_cellar, new_cellar)
+    mach_o_files.each do |file|
+      file.ensure_writable do
+        if file.dylib?
+          id = dylib_id_for(file).sub(old_prefix, new_prefix)
+          change_dylib_id(id, file)
+        end
+
+        each_install_name_for(file) do |old_name|
+          if old_name.start_with? old_cellar
+            new_name = old_name.sub(old_cellar, new_cellar)
+          elsif old_name.start_with? old_prefix
+            new_name = old_name.sub(old_prefix, new_prefix)
+          end
+
+          change_install_name(old_name, new_name, file) if new_name
+        end
+      end
+    end
+  end
+
+  # Detects the C++ dynamic libraries in place, scanning the dynamic links
+  # of the files within the keg.
+  # Note that this doesn't attempt to distinguish between libstdc++ versions,
+  # for instance between Apple libstdc++ and GNU libstdc++
+  def detect_cxx_stdlibs(options = {})
+    skip_executables = options.fetch(:skip_executables, false)
+    results = Set.new
+
+    mach_o_files.each do |file|
+      next if file.mach_o_executable? && skip_executables
+      dylibs = file.dynamically_linked_libraries
+      results << :libcxx unless dylibs.grep(/libc\+\+.+\.dylib/).empty?
+      results << :libstdcxx unless dylibs.grep(/libstdc\+\+.+\.dylib/).empty?
+    end
+
+    results.to_a
+  end
+
+  # If file is a dylib or bundle itself, look for the dylib named by
+  # bad_name relative to the lib directory, so that we can skip the more
+  # expensive recursive search if possible.
+  def fixed_name(file, bad_name)
+    if bad_name.start_with? PREFIX_PLACEHOLDER
+      bad_name.sub(PREFIX_PLACEHOLDER, HOMEBREW_PREFIX.to_s)
+    elsif bad_name.start_with? CELLAR_PLACEHOLDER
+      bad_name.sub(CELLAR_PLACEHOLDER, HOMEBREW_CELLAR.to_s)
+    elsif (file.dylib? || file.mach_o_bundle?) && (file.parent + bad_name).exist?
+      "@loader_path/#{bad_name}"
+    elsif file.mach_o_executable? && (lib + bad_name).exist?
+      "#{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
+
+  def each_install_name_for(file, &block)
+    dylibs = file.dynamically_linked_libraries
+    dylibs.reject! { |fn| fn =~ /^@(loader_|executable_|r)path/ }
+    dylibs.each(&block)
+  end
+
+  def dylib_id_for(file)
+    # 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.join(relative_dirname, basename).to_s
+  end
+
+  # Matches framework references like `XXX.framework/Versions/YYY/XXX` and
+  # `XXX.framework/XXX`, both with or without a slash-delimited prefix.
+  FRAMEWORK_RX = %r{(?:^|/)(([^/]+)\.framework/(?:Versions/[^/]+/)?\2)$}
+
+  def find_dylib_suffix_from(bad_name)
+    if (framework = bad_name.match(FRAMEWORK_RX))
+      framework[1]
+    else
+      File.basename(bad_name)
+    end
+  end
+
+  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
+
+  def mach_o_files
+    hardlinks = Set.new
+    mach_o_files = []
+    path.find do |pn|
+      next if pn.symlink? || pn.directory?
+      next unless 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
+
+  def self.file_linked_libraries(file, string)
+    # Check dynamic library linkage. Importantly, do not run otool on static
+    # libraries, which will falsely report "linkage" to themselves.
+    if file.mach_o_executable? || file.dylib? || file.mach_o_bund
+      file.dynamically_linked_libraries.select { |lib| lib.include? string }
+    else
+      []
+    end
+  end
+end
diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb
index e44c78087a5851492f7264cac66a2a41e67b3e72..375a529bbd9321b7d334e65beaeefb84bdd1e388 100644
--- a/Library/Homebrew/formula_installer.rb
+++ b/Library/Homebrew/formula_installer.rb
@@ -470,7 +470,7 @@ class FormulaInstaller
     link(keg)
 
     unless @poured_bottle && formula.bottle_specification.skip_relocation?
-      fix_install_names(keg)
+      fix_dynamic_linkage(keg)
     end
 
     if formula.post_install_defined?
@@ -687,10 +687,10 @@ class FormulaInstaller
     Homebrew.failed = true
   end
 
-  def fix_install_names(keg)
-    keg.fix_install_names
+  def fix_dynamic_linkage(keg)
+    keg.fix_dynamic_linkage
   rescue Exception => e
-    onoe "Failed to fix install names"
+    onoe "Failed to fix install linkage"
     puts "The formula built, but you may encounter issues using it or linking other"
     puts "formula against it."
     ohai e, e.backtrace if debug?
@@ -736,7 +736,7 @@ class FormulaInstaller
 
     keg = Keg.new(formula.prefix)
     unless formula.bottle_specification.skip_relocation?
-      keg.relocate_install_names Keg::PREFIX_PLACEHOLDER, HOMEBREW_PREFIX.to_s,
+      keg.relocate_dynamic_linkage Keg::PREFIX_PLACEHOLDER, HOMEBREW_PREFIX.to_s,
         Keg::CELLAR_PLACEHOLDER, HOMEBREW_CELLAR.to_s
     end
     keg.relocate_text_files Keg::PREFIX_PLACEHOLDER, HOMEBREW_PREFIX.to_s,
diff --git a/Library/Homebrew/keg_relocate.rb b/Library/Homebrew/keg_relocate.rb
index be41841f1fe754667e1d67af22f1e61f58b42c65..31732016896f3f1147433b2c22bcf7d157ef5047 100644
--- a/Library/Homebrew/keg_relocate.rb
+++ b/Library/Homebrew/keg_relocate.rb
@@ -2,21 +2,7 @@ class Keg
   PREFIX_PLACEHOLDER = "@@HOMEBREW_PREFIX@@".freeze
   CELLAR_PLACEHOLDER = "@@HOMEBREW_CELLAR@@".freeze
 
-  def fix_install_names
-    mach_o_files.each do |file|
-      file.ensure_writable do
-        change_dylib_id(dylib_id_for(file), file) if file.dylib?
-
-        each_install_name_for(file) do |bad_name|
-          # Don't fix absolute paths unless they are rooted in the build directory
-          next if bad_name.start_with?("/") && !bad_name.start_with?(HOMEBREW_TEMP.to_s)
-
-          new_name = fixed_name(file, bad_name)
-          change_install_name(bad_name, new_name, file) unless new_name == bad_name
-        end
-      end
-    end
-
+  def fix_dynamic_linkage
     symlink_files.each do |file|
       link = file.readlink
       # Don't fix relative symlinks
@@ -26,26 +12,10 @@ class Keg
       end
     end
   end
+  alias generic_fix_dynamic_linkage fix_dynamic_linkage
 
-  def relocate_install_names(old_prefix, new_prefix, old_cellar, new_cellar)
-    mach_o_files.each do |file|
-      file.ensure_writable do
-        if file.dylib?
-          id = dylib_id_for(file).sub(old_prefix, new_prefix)
-          change_dylib_id(id, file)
-        end
-
-        each_install_name_for(file) do |old_name|
-          if old_name.start_with? old_cellar
-            new_name = old_name.sub(old_cellar, new_cellar)
-          elsif old_name.start_with? old_prefix
-            new_name = old_name.sub(old_prefix, new_prefix)
-          end
-
-          change_install_name(old_name, new_name, file) if new_name
-        end
-      end
-    end
+  def relocate_dynamic_linkage(old_prefix, new_prefix, old_cellar, new_cellar)
+    []
   end
 
   def relocate_text_files(old_prefix, new_prefix, old_cellar, new_cellar)
@@ -70,22 +40,8 @@ class Keg
     end
   end
 
-  # Detects the C++ dynamic libraries in place, scanning the dynamic links
-  # of the files within the keg.
-  # Note that this doesn't attempt to distinguish between libstdc++ versions,
-  # for instance between Apple libstdc++ and GNU libstdc++
   def detect_cxx_stdlibs(options = {})
-    skip_executables = options.fetch(:skip_executables, false)
-    results = Set.new
-
-    mach_o_files.each do |file|
-      next if file.mach_o_executable? && skip_executables
-      dylibs = file.dynamically_linked_libraries
-      results << :libcxx unless dylibs.grep(/libc\+\+.+\.dylib/).empty?
-      results << :libstdcxx unless dylibs.grep(/libstdc\+\+.+\.dylib/).empty?
-    end
-
-    results.to_a
+    []
   end
 
   def each_unique_file_matching(string)
@@ -100,77 +56,10 @@ class Keg
     end
   end
 
-  # If file is a dylib or bundle itself, look for the dylib named by
-  # bad_name relative to the lib directory, so that we can skip the more
-  # expensive recursive search if possible.
-  def fixed_name(file, bad_name)
-    if bad_name.start_with? PREFIX_PLACEHOLDER
-      bad_name.sub(PREFIX_PLACEHOLDER, HOMEBREW_PREFIX.to_s)
-    elsif bad_name.start_with? CELLAR_PLACEHOLDER
-      bad_name.sub(CELLAR_PLACEHOLDER, HOMEBREW_CELLAR.to_s)
-    elsif (file.dylib? || file.mach_o_bundle?) && (file.parent + bad_name).exist?
-      "@loader_path/#{bad_name}"
-    elsif file.mach_o_executable? && (lib + bad_name).exist?
-      "#{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
-
   def lib
     path.join("lib")
   end
 
-  def each_install_name_for(file, &block)
-    dylibs = file.dynamically_linked_libraries
-    dylibs.reject! { |fn| fn =~ /^@(loader_|executable_|r)path/ }
-    dylibs.each(&block)
-  end
-
-  def dylib_id_for(file)
-    # 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.join(relative_dirname, basename).to_s
-  end
-
-  # Matches framework references like `XXX.framework/Versions/YYY/XXX` and
-  # `XXX.framework/XXX`, both with or without a slash-delimited prefix.
-  FRAMEWORK_RX = %r{(?:^|/)(([^/]+)\.framework/(?:Versions/[^/]+/)?\2)$}.freeze
-
-  def find_dylib_suffix_from(bad_name)
-    if (framework = bad_name.match(FRAMEWORK_RX))
-      framework[1]
-    else
-      File.basename(bad_name)
-    end
-  end
-
-  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
-
-  def mach_o_files
-    hardlinks = Set.new
-    mach_o_files = []
-    path.find do |pn|
-      next if pn.symlink? || pn.directory?
-      next unless 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
-
   def text_files
     text_files = []
     path.find do |pn|
@@ -203,4 +92,10 @@ class Keg
 
     symlink_files
   end
+
+  def self.file_linked_libraries(file, string)
+    []
+  end
 end
+
+require "extend/os/keg_relocate"