#!/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -W0 #TODO make it work with homebrew/dupes/gcc #TODO? If we find -mmacosx-version-min=10.8, change sdkroot? warn visibly if no such SDK? #TODO fix pkg-config files, should point to /usr/local or /usr/local/opt #TODO create mechanism to specify build effects like %w{-O0 -O4 vanilla-arg-parsing sdk=10.6} etc. require "#{File.dirname __FILE__}/../libsuperenv" require 'set' def cccfg? flags flags.split('').all?{|c| ENV['HOMEBREW_CCCFG'].include? c } if ENV['HOMEBREW_CCCFG'] end def nclt? $sdkroot != nil end def syspath if nclt? %W{#$sdkroot/usr #$sdkroot/usr/local} else %W{/usr /usr/local} end end def exec *args path = File.expand_path('~/Library/Logs/Homebrew/cc.log') open(path, 'a') do |f| f.print '[', $0 f.print " -%s" % ENV['HOMEBREW_CCCFG'] if ENV['HOMEBREW_CCCFG'] f.print '] ' f.puts args.join(' ') f.puts end Kernel.exec *args end if ENV['HOMEBREW_LOG'] class Cmd def initialize path, args @arg0 = path.basename.freeze @args = args.freeze end def mode if @arg0 == 'cpp' or @arg0 == 'ld' @arg0.to_sym elsif @args.include? '-c' :cc elsif @args.include? '-E' :cpp else :ccld end end def tool @tool ||= case @arg0 when 'ld' then 'ld' when 'cc', 'c99', 'c89' # Ideally we would run `cx9`, however these tools are POSIX compliant # and don't support many flags. We need -isystem for instance, but also # reliability is generally much higher if we just get clang/gcc to do # the work since Makefiles are dumb and include a lot of excess flags. ENV['HOMEBREW_CC'] when 'c++' if ENV['HOMEBREW_CC'] =~ /gcc/ 'g++' else 'clang++' end else @arg0 end end def args args = if not cccfg? 'O' or tool == 'ld' @args.dup else refurbished_args end if tool != 'ld' args << "--sysroot=#$sdkroot" else args << "-syslibroot" << $sdkroot end if nclt? case mode when :cpp %w{-E} + args + cppflags when :ld ldflags + args when :cc cflags + args + cppflags when :ccld cflags + args + cppflags + ldflags end.compact end def refurbished_args lset = Set.new(libpath + syslibpath) iset = Set.new(cpath.flatten) args = [] whittler = @args.each loop do case arg = whittler.next when '-arch', /^-Xarch_/ whittler.next when /^-g\d?/, /^-gstabs\d+/, '-gstabs+', /^-ggdb\d?/, '-gdwarf-2', /^-march=.+/, /^-mtune=.+/, '-m64', '-m32', /^-O[0-9zs]?/, '-fast', '-pedantic', '-pedantic-errors' when '-fopenmp', '-lgomp' # clang doesn't support OpenMP args << arg if not tool =~ /^clang/ when /^-W.*/ args << arg if arg =~ /^-Wl,/ when '-macosx_version_min', '-dylib_install_name' args << "-Wl,#{arg},#{whittler.next}" when '-dylib' args << "-Wl,#{arg}" when /^-I(.+)/ # it is okay to add a space after the -I; so let's support it path = $1.chuzzle || whittler.next args << "-I#{path}" if iset.add?(path.cleanpath) when /^-L(.+)/ path = $1.chuzzle || whittler.next case path.cleanpath when %r{^/opt}, %r{^/sw}, %r{/usr/X11} # NOOP else args << "-L#{path}" if lset.add?(path.cleanpath) end else args << arg end end make_fuss(args) args end def cflags if cccfg? 'Ob' %w{-mtune=generic -Oz} elsif cccfg? 'O' args = %w{-pipe -w -Os} args << '-march=native' if tool =~ /clang/ args += %w{-arch i386 -arch x86_64} if cccfg? 'u' args << "--std=#{@arg0}" if @arg0 =~ /c[89]9/ args else [] end end def syslibpath # We reject brew's lib as we explicitly add this as a -L flag, thus it # is given higher priority by cc, so it surpasses the system libpath. # NOTE this only counts if Homebrew is installed at /usr/local syspath.map{|d| "#{d}/lib" }.reject{ "#$brewfix/lib" } end def syscpath isystem, _ = cpath isystem + syspath.map{|d| "#{d}/include" } end def cpath cpath = ENV['CMAKE_PREFIX_PATH'].split(':').map{|d| "#{d}/include" } + ENV['CMAKE_INCLUDE_PATH'].split(':') opt = cpath.select{|prefix| prefix =~ %r{^#$brewfix/opt} } sys = cpath - opt [sys, opt] end def libpath ENV['CMAKE_PREFIX_PATH'].split(':').map{|d| "#{d}/lib" } + ENV['CMAKE_LIBRARY_PATH'].split(':') - syslibpath end def ldflags libpath.to_flags('-L') end def cppflags sys, opt = cpath # we want our keg-only includes to be found before system includes *and* # before any other includes the build-system adds sys.to_flags('-isystem') + opt.to_flags('-I') end def make_fuss args dels = @args - args adds = args - @args dups = dels & args STDERR.puts "brew: superenv removed: #{dels*' '}" unless dels.empty? STDERR.puts "brew: superenv deduped: #{dels}" unless dups.empty? STDERR.puts "brew: superenv added: #{adds*' '}" unless adds.empty? end end ####################################################################### sanity abort "The build-tool has reset ENV. --env=std required." unless ENV['HOMEBREW_BREW_FILE'] case ENV['HOMEBREW_CC'].chuzzle when 'cc', nil # those values are not allowed ENV['HOMEBREW_CC'] = 'clang' end ######################################################################### main cmd = Cmd.new($0, ARGV) exec "xcrun", cmd.tool, *cmd.args