#!/bin/sh # Make sure this shim uses the same Ruby interpreter that is used by Homebrew. unset RUBYLIB unset RUBYOPT 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" -x "$0" "$@" #!/usr/bin/env ruby -W0 require "pathname" require "set" class Cmd attr_reader :config, :prefix, :cellar, :tmpdir, :sysroot attr_reader :archflags, :optflags def initialize(arg0, args) @arg0 = arg0 @args = args.freeze @config = ENV.fetch("HOMEBREW_CCCFG") { "" } @prefix = ENV["HOMEBREW_PREFIX"] @cellar = ENV["HOMEBREW_CELLAR"] @tmpdir = ENV["HOMEBREW_TEMP"] @sysroot = ENV["HOMEBREW_SDKROOT"] @archflags = ENV.fetch("HOMEBREW_ARCHFLAGS") { "" }.split(" ") @optflags = ENV.fetch("HOMEBREW_OPTFLAGS") { "" }.split(" ") end def mode if @arg0 == "cpp" || @arg0 == "ld" @arg0.to_sym elsif @args.include? "-c" if @arg0 =~ /(?:c|g|clang)\+\+/ :cxx else :cc end 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 "cpp" then "cpp" when /\w\+\+(-\d(\.\d)?)?$/ case ENV["HOMEBREW_CC"] when /clang/ "clang++" when /llvm-gcc/ "llvm-g++-4.2" when /gcc(-\d(\.\d)?)?$/ "g++" + $1.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. ENV["HOMEBREW_CC"] 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" # clang doesn't support these flags args << arg unless tool =~ /^clang/ 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 /^-W[alp],/, /^-Wno-/ 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/ sdk = enum.next # We set the sysroot for OS X SDKs args << "-isysroot" << sdk unless sdk.downcase.include? "osx" 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) path.start_with?(prefix, cellar, tmpdir) || !path.start_with?("/opt", "/sw", "/usr/X11") 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 args = path_flags("-L", library_paths) case mode when :ld args << "-headerpad_max_install_names" when :ccld, :cxxld args << "-Wl,-headerpad_max_install_names" end args 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 system_library_paths %W[#{sysroot}/usr/lib /usr/local/lib] 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 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 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 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 RUBY_VERSION >= "2.0" exec "#{dirname}/xcrun", tool, *args end