452 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			452 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
| #!/bin/sh
 | |
| # Make sure this shim uses the same Ruby interpreter that is used by Homebrew.
 | |
| if [ -z "$HOMEBREW_RUBY_PATH" ]
 | |
| then
 | |
|   echo "${0##*/}: The build tool has reset ENV; --env=std required." >&2
 | |
|   exit 1
 | |
| fi
 | |
| exec "$HOMEBREW_RUBY_PATH" --enable-frozen-string-literal --disable=gems,did_you_mean,rubyopt -x "$0" "$@"
 | |
| #!/usr/bin/env ruby -W0
 | |
| 
 | |
| require "pathname"
 | |
| require "set"
 | |
| 
 | |
| def mac?
 | |
|   RUBY_PLATFORM[/darwin/]
 | |
| end
 | |
| 
 | |
| def high_sierra_or_later?
 | |
|   mac? && ENV["HOMEBREW_MACOS_VERSION_NUMERIC"].to_s.to_i >= 101300
 | |
| end
 | |
| 
 | |
| def linux?
 | |
|   RUBY_PLATFORM[/linux/]
 | |
| end
 | |
| 
 | |
| class Cmd
 | |
|   attr_reader :config, :prefix, :cellar, :opt, :cachedir, :tmpdir, :sysroot, :deps
 | |
|   attr_reader :archflags, :optflags, :keg_regex, :formula_prefix
 | |
| 
 | |
|   def initialize(arg0, args)
 | |
|     @arg0 = arg0
 | |
|     @args = args.freeze
 | |
|     @config = ENV.fetch("HOMEBREW_CCCFG") { "" }
 | |
|     @prefix = ENV["HOMEBREW_PREFIX"]
 | |
|     @cellar = ENV["HOMEBREW_CELLAR"]
 | |
|     @cachedir = ENV["HOMEBREW_CACHE"]
 | |
|     @opt = ENV["HOMEBREW_OPT"]
 | |
|     @tmpdir = ENV["HOMEBREW_TEMP"]
 | |
|     @sysroot = ENV["HOMEBREW_SDKROOT"]
 | |
|     @archflags = ENV.fetch("HOMEBREW_ARCHFLAGS") { "" }.split(" ")
 | |
|     @optflags = ENV.fetch("HOMEBREW_OPTFLAGS") { "" }.split(" ")
 | |
|     @deps = Set.new(ENV.fetch("HOMEBREW_DEPENDENCIES") { "" }.split(","))
 | |
|     @formula_prefix = ENV["HOMEBREW_FORMULA_PREFIX"]
 | |
|     # matches opt or cellar prefix and formula name
 | |
|     @keg_regex = %r[(#{Regexp.escape(opt)}|#{Regexp.escape(cellar)})/([\w+-.@]+)]
 | |
|   end
 | |
| 
 | |
|   def mode
 | |
|     if @arg0 == "cpp"
 | |
|       :cpp
 | |
|     elsif ["ld", "ld.gold", "gold"].include? @arg0
 | |
|       :ld
 | |
|     elsif @args.include? "-c"
 | |
|       if @arg0 =~ /(?:c|g|clang)\+\+/
 | |
|         :cxx
 | |
|       else
 | |
|         :cc
 | |
|       end
 | |
|     elsif @args.include?("-xc++-header") || @args.each_cons(2).include?(["-x", "c++-header"])
 | |
|       :cxx
 | |
|     elsif @args.include? "-E"
 | |
|       :ccE
 | |
|     else
 | |
|       if @arg0 =~ /(?:c|g|clang)\+\+/
 | |
|         :cxxld
 | |
|       else
 | |
|         :ccld
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def tool
 | |
|     @tool ||= case @arg0
 | |
|     when "ld" then "ld"
 | |
|     when "gold", "ld.gold" then "ld.gold"
 | |
|     when "cpp" then "cpp"
 | |
|     when /llvm_(clang(\+\+)?)/
 | |
|      "#{ENV["HOMEBREW_PREFIX"]}/opt/llvm/bin/#{$1}"
 | |
|     when /\w\+\+(-\d+(\.\d)?)?$/
 | |
|       case ENV["HOMEBREW_CC"]
 | |
|       when /clang/
 | |
|         "clang++"
 | |
|       when /llvm-gcc/
 | |
|         "llvm-g++-4.2"
 | |
|       when /(g)?cc(-\d+(\.\d)?)?$/
 | |
|         "g++" + $2.to_s
 | |
|       end
 | |
|     else
 | |
|       # Note that this is a universal fallback, so that we'll always invoke
 | |
|       # HOMEBREW_CC regardless of what name under which the tool was invoked.
 | |
|       if ENV["HOMEBREW_CC"] == "llvm_clang"
 | |
|         "#{ENV["HOMEBREW_PREFIX"]}/opt/llvm/bin/clang"
 | |
|       else
 | |
|         ENV["HOMEBREW_CC"]
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def args
 | |
|     if @args.length == 1 && @args[0] == "-v"
 | |
|       # Don't add linker arguments if -v passed as sole option. This stops gcc
 | |
|       # -v with no other arguments from outputting a linker error. Some
 | |
|       # software uses gcc -v (wrongly) to sniff the GCC version.
 | |
|       return @args.dup
 | |
|     end
 | |
| 
 | |
|     if !refurbish_args? || tool == "ld" || configure?
 | |
|       args = @args.dup
 | |
|     else
 | |
|       args = refurbished_args
 | |
|     end
 | |
| 
 | |
|     if sysroot
 | |
|       if tool == "ld"
 | |
|         args << "-syslibroot" << sysroot
 | |
|       else
 | |
|         args << "-isysroot#{sysroot}" << "--sysroot=#{sysroot}"
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     case mode
 | |
|     when :ccld
 | |
|       cflags + args + cppflags + ldflags
 | |
|     when :cxxld
 | |
|       cxxflags + args + cppflags + ldflags
 | |
|     when :cc
 | |
|       cflags + args + cppflags
 | |
|     when :cxx
 | |
|       cxxflags + args + cppflags
 | |
|     when :ccE
 | |
|       args + cppflags
 | |
|     when :cpp
 | |
|       args + cppflags
 | |
|     when :ld
 | |
|       ldflags + args
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def refurbished_args
 | |
|     @lset = Set.new(library_paths + system_library_paths)
 | |
|     @iset = Set.new(isystem_paths + include_paths)
 | |
| 
 | |
|     args = []
 | |
|     enum = @args.each
 | |
| 
 | |
|     loop do
 | |
|       case arg = enum.next
 | |
|       when "-arch"
 | |
|         if permit_arch_flags?
 | |
|           args << arg << enum.next
 | |
|         else
 | |
|           enum.next
 | |
|         end
 | |
|       when "-m32", "-m64"
 | |
|         args << arg if permit_arch_flags?
 | |
|       when /^-Xarch_/
 | |
|         refurbished = refurbish_arg(enum.next, enum)
 | |
|         unless refurbished.empty?
 | |
|           args << arg
 | |
|           args += refurbished
 | |
|         end
 | |
|       else
 | |
|         args += refurbish_arg(arg, enum)
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     args
 | |
|   end
 | |
| 
 | |
|   def refurbish_arg(arg, enum)
 | |
|     args = []
 | |
| 
 | |
|     case arg
 | |
|     when /^-g\d?$/, /^-gstabs\d+/, "-gstabs+", /^-ggdb\d?/,
 | |
|       /^-march=.+/, /^-mtune=.+/, /^-mcpu=.+/,
 | |
|       /^-O[0-9zs]?$/, "-fast", "-no-cpp-precomp",
 | |
|       "-pedantic", "-pedantic-errors", "-Wno-long-double",
 | |
|       "-Wno-unused-but-set-variable"
 | |
|     when "-fopenmp", "-lgomp", "-mno-fused-madd", "-fforce-addr", "-fno-defer-pop",
 | |
|       "-mno-dynamic-no-pic", "-fearly-inlining", /^-f(?:no-)?inline-functions-called-once/,
 | |
|       /^-finline-limit/, /^-f(?:no-)?check-new/, "-fno-delete-null-pointer-checks",
 | |
|       "-fcaller-saves", "-fthread-jumps", "-fno-reorder-blocks", "-fcse-skip-blocks",
 | |
|       "-frerun-cse-after-loop", "-frerun-loop-opt", "-fcse-follow-jumps",
 | |
|       "-fno-regmove", "-fno-for-scope", "-fno-tree-pre", "-fno-tree-dominator-opts",
 | |
|       "-fuse-linker-plugin", "-frounding-math"
 | |
|       # clang doesn't support these flags
 | |
|       args << arg unless tool =~ /^clang/
 | |
|     when "-Xpreprocessor", "-Xclang"
 | |
|       # used for -Xpreprocessor -fopenmp
 | |
|       args << arg << enum.next
 | |
|     when /-mmacosx-version-min=(\d+)\.(\d+)/
 | |
|       arg = "-mmacosx-version-min=10.9" if high_sierra_or_later? && $1 == "10" && $2.to_i < 9
 | |
|       args << arg
 | |
|     when "--fast-math"
 | |
|       arg = "-ffast-math" if tool =~ /^clang/
 | |
|       args << arg
 | |
|     when "-Wno-deprecated-register"
 | |
|       # older gccs don't support these flags
 | |
|       args << arg unless tool =~ /^g..-4.[02]/
 | |
|     when /^-Wl,-z,defs/
 | |
|       # -Wl,-undefined,error is already the default
 | |
|     when /^-W[alp],/, /^-Wno-/, "-Werror=implicit-function-declaration"
 | |
|       args << arg
 | |
|     when /^-W.*/
 | |
|       # prune warnings
 | |
|     when "-macosx_version_min", "-dylib_install_name"
 | |
|       args << "-Wl,#{arg},#{enum.next}"
 | |
|     when "-multiply_definedsuppress"
 | |
|       args << "-Wl,-multiply_defined,suppress"
 | |
|     when "-undefineddynamic_lookup"
 | |
|       args << "-Wl,-undefined,dynamic_lookup"
 | |
|     when /^-isysroot/, /^--sysroot/
 | |
|       if mac?
 | |
|         sdk = enum.next
 | |
|         # We set the sysroot for macOS SDKs
 | |
|         args << "-isysroot#{sdk}" unless sdk.downcase.include? "osx"
 | |
|       else
 | |
|         args << arg << enum.next
 | |
|       end
 | |
|     when "-dylib"
 | |
|       args << "-Wl,#{arg}"
 | |
|     when /^-I(.+)?/
 | |
|       # Support both "-Ifoo" (one argument) and "-I foo" (two arguments)
 | |
|       val  = chuzzle($1) || enum.next
 | |
|       path = canonical_path(val)
 | |
|       args << "-I#{val}" if keep?(path) && @iset.add?(path)
 | |
|     when /^-L(.+)?/
 | |
|       val  = chuzzle($1) || enum.next
 | |
|       path = canonical_path(val)
 | |
|       args << "-L#{val}" if keep?(path) && @lset.add?(path)
 | |
|     else
 | |
|       args << arg
 | |
|     end
 | |
| 
 | |
|     args
 | |
|   end
 | |
| 
 | |
|   def keep?(path)
 | |
|     # Allow references to self
 | |
|     if formula_prefix && path.start_with?("#{formula_prefix}/")
 | |
|       true
 | |
|     # first two paths: reject references to Cellar or opt paths
 | |
|     # for unspecified dependencies
 | |
|     elsif path.start_with?(cellar) || path.start_with?(opt)
 | |
|       dep = path[keg_regex, 2]
 | |
|       dep && @deps.include?(dep)
 | |
|     elsif path.start_with?(prefix, cachedir, tmpdir)
 | |
|       true
 | |
|     elsif path.start_with?("/opt/local", "/opt/boxen/homebrew", "/opt/X11", "/sw", "/usr/X11")
 | |
|       # ignore MacPorts, Boxen's Homebrew, X11, fink
 | |
|       false
 | |
|     elsif mac?
 | |
|       true
 | |
|     else
 | |
|       false
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def cflags
 | |
|     args = []
 | |
| 
 | |
|     return args unless refurbish_args? || configure?
 | |
| 
 | |
|     args << "-pipe"
 | |
|     args << "-w" unless configure?
 | |
|     args << "-#{ENV["HOMEBREW_OPTIMIZATION_LEVEL"]}"
 | |
|     args.concat(optflags)
 | |
|     args.concat(archflags)
 | |
|     args << "-std=#{@arg0}" if @arg0 =~ /c[89]9/
 | |
|     args
 | |
|   end
 | |
| 
 | |
|   def cxxflags
 | |
|     args = cflags
 | |
|     args << "-std=c++11" if cxx11?
 | |
|     args << "-stdlib=libc++" if libcxx?
 | |
|     args << "-stdlib=libstdc++" if libstdcxx?
 | |
|     args
 | |
|   end
 | |
| 
 | |
|   def cppflags
 | |
|     path_flags("-isystem", isystem_paths) + path_flags("-I", include_paths)
 | |
|   end
 | |
| 
 | |
|   def ldflags_mac(args)
 | |
|     case mode
 | |
|     when :ld
 | |
|       args << "-headerpad_max_install_names"
 | |
|       args << "-no_weak_imports" if no_weak_imports?
 | |
|     when :ccld, :cxxld
 | |
|       args << "-Wl,-headerpad_max_install_names"
 | |
|       args << "-Wl,-no_weak_imports" if no_weak_imports?
 | |
|     end
 | |
|     args
 | |
|   end
 | |
| 
 | |
|   def ldflags_linux(args)
 | |
|     unless mode == :ld
 | |
|       wl = "-Wl,"
 | |
|       args << "-B#{@opt}/glibc/lib"
 | |
|     end
 | |
|     args += rpath_flags("#{wl}-rpath=", rpath_paths)
 | |
|     args += ["#{wl}--dynamic-linker=#{dynamic_linker_path}"] if dynamic_linker_path
 | |
|     args
 | |
|   end
 | |
| 
 | |
|   def ldflags
 | |
|     args = path_flags("-L", library_paths)
 | |
|     if mac?
 | |
|       ldflags_mac(args)
 | |
|     elsif linux?
 | |
|       ldflags_linux(args)
 | |
|     else
 | |
|       args
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def isystem_paths
 | |
|     path_split("HOMEBREW_ISYSTEM_PATHS")
 | |
|   end
 | |
| 
 | |
|   def include_paths
 | |
|     path_split("HOMEBREW_INCLUDE_PATHS")
 | |
|   end
 | |
| 
 | |
|   def library_paths
 | |
|     path_split("HOMEBREW_LIBRARY_PATHS")
 | |
|   end
 | |
| 
 | |
|   def rpath_paths
 | |
|     path_split("HOMEBREW_RPATH_PATHS")
 | |
|   end
 | |
| 
 | |
|   def dynamic_linker_path
 | |
|     chuzzle(ENV["HOMEBREW_DYNAMIC_LINKER"])
 | |
|   end
 | |
| 
 | |
|   def system_library_paths
 | |
|     paths = ["#{sysroot}/usr/lib"]
 | |
|     paths << "/usr/local/lib" unless sysroot || ENV["SDKROOT"]
 | |
|     paths
 | |
|   end
 | |
| 
 | |
|   def configure?
 | |
|     # configure scripts generated with autoconf 2.61 or later export as_nl
 | |
|     ENV.key? "as_nl"
 | |
|   end
 | |
| 
 | |
|   def refurbish_args?
 | |
|     config.include?("O")
 | |
|   end
 | |
| 
 | |
|   def cxx11?
 | |
|     config.include?("x")
 | |
|   end
 | |
| 
 | |
|   def libcxx?
 | |
|     config.include?("g")
 | |
|   end
 | |
| 
 | |
|   def libstdcxx?
 | |
|     config.include?("h")
 | |
|   end
 | |
| 
 | |
|   def permit_arch_flags?
 | |
|     config.include?("K")
 | |
|   end
 | |
| 
 | |
|   def no_weak_imports?
 | |
|     config.include?("w")
 | |
|   end
 | |
| 
 | |
|   def canonical_path(path)
 | |
|     path = Pathname.new(path)
 | |
|     path = path.realpath if path.exist?
 | |
|     path.to_s
 | |
|   end
 | |
| 
 | |
|   def path_flags(prefix, paths)
 | |
|     paths = paths.uniq.select { |path| File.directory?(path) }
 | |
|     paths.map! { |path| prefix + path }
 | |
|   end
 | |
| 
 | |
|   # Unlike path_flags, do not prune non-existent directories.
 | |
|   # formula.lib for example does not yet exist, but should not be pruned.
 | |
|   def rpath_flags(prefix, paths)
 | |
|     paths.uniq.map { |path| prefix + path }
 | |
|   end
 | |
| 
 | |
|   def path_split(key)
 | |
|     ENV.fetch(key) { "" }.split(File::PATH_SEPARATOR)
 | |
|   end
 | |
| 
 | |
|   def chuzzle(val)
 | |
|     return val if val.nil?
 | |
|     val = val.chomp
 | |
|     return val unless val.empty?
 | |
|   end
 | |
| end
 | |
| 
 | |
| def log(basename, argv, tool, args)
 | |
|   return unless ENV.key?("HOMEBREW_CC_LOG_PATH")
 | |
| 
 | |
|   adds = args - argv
 | |
|   dels = argv - args
 | |
| 
 | |
|   s = +""
 | |
|   s << "#{basename} called with: #{argv.join(" ")}\n"
 | |
|   s << "superenv removed:  #{dels.join(" ")}\n" unless dels.empty?
 | |
|   s << "superenv added:    #{adds.join(" ")}\n" unless adds.empty?
 | |
|   s << "superenv executed: #{tool} #{args.join(" ")}\n\n"
 | |
|   File.open("#{ENV["HOMEBREW_CC_LOG_PATH"]}.cc", "a+") { |f| f.write(s) }
 | |
| end
 | |
| 
 | |
| def remove_superbin_from_path(paths)
 | |
|   superbin = Pathname.new(__FILE__).dirname.realpath
 | |
|   paths.reject do |x|
 | |
|     path = Pathname.new(x)
 | |
|     path.directory? && path.realpath == superbin
 | |
|   end
 | |
| end
 | |
| 
 | |
| if __FILE__ == $PROGRAM_NAME
 | |
|   ##################################################################### sanity
 | |
| 
 | |
|   if (cc = ENV["HOMEBREW_CC"]).nil? || cc.empty? || cc == "cc"
 | |
|     # those values are not allowed
 | |
|     ENV["HOMEBREW_CC"] = "clang"
 | |
|   end
 | |
| 
 | |
|   ####################################################################### main
 | |
| 
 | |
|   dirname, basename = File.split($0)
 | |
| 
 | |
|   cmd = Cmd.new(basename, ARGV)
 | |
|   tool = cmd.tool
 | |
|   args = cmd.args
 | |
| 
 | |
|   log(basename, ARGV, tool, args)
 | |
| 
 | |
|   args << { :close_others => false }
 | |
|   if mac?
 | |
|     exec "#{dirname}/xcrun", tool, *args
 | |
|   else
 | |
|     paths = ENV["PATH"].split(":")
 | |
|     paths = remove_superbin_from_path(paths)
 | |
|     paths.unshift "#{ENV["HOMEBREW_PREFIX"]}/bin"
 | |
|     ENV["PATH"] = paths.join(":")
 | |
|     exec tool, *args
 | |
|   end
 | |
| end
 | 
