304 lines
8.3 KiB
Plaintext
Raw Normal View History

#!/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -W0
2014-04-20 18:00:29 -05:00
require File.expand_path("../libsuperenv", File.dirname(__FILE__))
2014-04-20 19:57:01 -05:00
require 'pathname'
require 'set'
require 'stringio'
class Logger
def initialize
@io = StringIO.new
end
def puts(*args)
@io.puts(*args)
end
def log!
return unless ENV.key? 'HOMEBREW_CC_LOG_PATH'
path = "#{ENV['HOMEBREW_CC_LOG_PATH']}.cc"
puts
File.open(path, File::WRONLY | File::APPEND | File::CREAT) { |f| f.write(@io.string) }
end
end
LOGGER = Logger.new
class Cmd
attr_reader :brewfix, :brewtmp, :sdkroot
2013-11-21 14:50:35 -06:00
def initialize path, args
2013-11-21 14:50:35 -06:00
@arg0 = File.basename(path).freeze
@args = args.freeze
2013-11-21 14:50:35 -06:00
@brewfix = ENV['HOMEBREW_PREFIX']
@brewtmp = ENV['HOMEBREW_TEMP']
2013-11-21 14:50:35 -06:00
@sdkroot = ENV['HOMEBREW_SDKROOT']
end
def mode
if @arg0 == 'cpp' or @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 and @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 !cccfg?("O") || tool == "ld" || configure?
args = @args.dup
else
args = refurbished_args
end
if tool != 'ld'
2013-11-21 14:50:35 -06:00
args << "--sysroot=#{sdkroot}"
else
2013-11-21 14:50:35 -06:00
args << "-syslibroot" << sdkroot
end if nclt?
allflags = case mode
when :ccld
2013-08-31 10:38:18 -05:00
cflags + args + cppflags + ldflags
when :cxxld
cxxflags + args + cppflags + ldflags
when :cc
2013-08-31 10:38:18 -05:00
cflags + args + cppflags
when :cxx
cxxflags + args + cppflags
when :ccE
args + cppflags
when :cpp
args + cppflags
when :ld
ldflags + args
end.compact
make_fuss(allflags)
allflags
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 '-m32'
# If ENV.m32 was set, we allow the "-m32" flag, but we don't add anything
args << '-m32' if cccfg? '3'
when /^-g\d?/, /^-gstabs\d+/, '-gstabs+', /^-ggdb\d?/, '-gdwarf-2',
/^-march=.+/, /^-mtune=.+/, /^-mcpu=.+/, '-m64',
2013-11-20 15:01:02 -06:00
/^-O[0-9zs]?$/, '-fast', '-no-cpp-precomp',
'-pedantic', '-pedantic-errors'
2014-03-20 23:16:06 -05:00
when '-fopenmp', '-lgomp', '-mno-fused-madd', '-fforce-addr', '-fno-defer-pop',
'-mno-dynamic-no-pic', '-fearly-inlining', '-finline-functions-called-once',
/^-finline-limit/, /^-f(?:no-)?check-new/, '-fno-delete-null-pointer-checks',
'-fcaller-saves', '-fthread-jumps', '-fno-reorder-blocks'
# clang doesn't support these flags
args << arg if not tool =~ /^clang/
when /^-W.*/
args << arg if arg =~ /^-W[alp],/ or arg =~ /^-Wno-/
when '-macosx_version_min', '-dylib_install_name'
args << "-Wl,#{arg},#{whittler.next}"
2014-03-21 13:00:15 -05:00
when '-multiply_definedsuppress'
args << "-Wl,-multiply_defined,suppress"
when '-undefineddynamic_lookup'
args << "-Wl,-undefined,dynamic_lookup"
when /^-isysroot/
# We set the sysroot
whittler.next
when '-dylib'
args << "-Wl,#{arg}"
when /^-I(.+)?/
# Support both "-Ifoo" (one argument) and "-I foo" (two arguments)
val = $1.chuzzle || whittler.next
path = canonical_path(val)
args << "-I#{val}" if keep?(path) and iset.add?(path)
when /^-L(.+)?/
val = $1.chuzzle || whittler.next
path = canonical_path(val)
args << "-L#{val}" if keep?(path) and lset.add?(path)
else
args << arg
end
end
args
end
def keep? path
2014-04-20 19:57:01 -05:00
case path
when %r{^#{Regexp.escape(brewfix)}}, %r{^#{Regexp.escape(brewtmp)}}
# maybe homebrew is installed to /sw or /opt/brew
true
when %r{^/opt}, %r{^/sw}, %r{/usr/X11}
false
else
true
end
end
def cflags
args = []
return args unless cccfg? 'O' or configure?
args << '-pipe'
args << '-w' unless configure?
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 cccfg? 'x'
args << '-stdlib=libc++' if cccfg? 'g'
args << '-stdlib=libstdc++' if cccfg? 'h'
args
end
def optflags
args = []
args << "-#{ENV['HOMEBREW_OPTIMIZATION_LEVEL']}"
args.concat ENV['HOMEBREW_OPTFLAGS'].split(' ') if ENV['HOMEBREW_OPTFLAGS']
args
end
def archflags
args = []
args.concat ENV['HOMEBREW_ARCHFLAGS'].split(' ') if cccfg? 'u'
args
end
def syspath
if nclt?
2013-11-21 14:50:35 -06:00
%W{#{sdkroot}/usr #{sdkroot}/usr/local}
else
%W{/usr /usr/local}
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
2013-11-21 14:50:35 -06:00
syspath.map{|d| "#{d}/lib" }.reject{|d| d == "#{brewfix}/lib" }
end
def cpath
cpath = ENV['CMAKE_PREFIX_PATH'].split(':').map{|d| "#{d}/include" } + ENV['CMAKE_INCLUDE_PATH'].split(':')
opt = cpath.grep(%r{^#{Regexp.escape(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
2014-04-20 19:54:32 -05:00
args = path_flags("-L", libpath)
case mode
when :ld then args << '-headerpad_max_install_names'
when :ccld then args << '-Wl,-headerpad_max_install_names'
when :cxxld
args << '-Wl,-headerpad_max_install_names'
args << '-stdlib=libc++' if cccfg? 'g'
args << '-stdlib=libstdc++' if cccfg? 'h'
end
args
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
2014-04-20 19:54:32 -05:00
path_flags("-isystem", sys) + path_flags("-I", opt)
end
def make_fuss args
return unless make_fuss?
dels = @args - args
adds = args - @args
dups = dels & args
LOGGER.puts "superenv removed: #{dels*' '}" unless dels.empty?
LOGGER.puts "superenv deduped: #{dups}" unless dups.empty?
LOGGER.puts "superenv added: #{adds*' '}" unless adds.empty?
end
def make_fuss?
2013-11-17 19:09:24 -06:00
cccfg? 'O' and not configure?
end
def configure?
# configure scripts generated with autoconf 2.61 or later export as_nl
ENV.key? 'as_nl'
end
def nclt?
2013-11-21 14:50:35 -06:00
sdkroot != nil
end
def cccfg? flags
flags.split('').all?{|c| ENV['HOMEBREW_CCCFG'].include? c } if ENV['HOMEBREW_CCCFG']
end
2014-04-20 19:57:01 -05:00
def canonical_path(path)
path = Pathname.new(path)
path = path.realpath if path.exist?
path.to_s
end
2014-04-20 19:54:32 -05:00
def path_flags(prefix, paths)
paths = paths.uniq.select { |path| File.directory?(path) }
paths.map! { |path| prefix + path }
end
end
2013-03-03 22:11:26 -06:00
if __FILE__ == $PROGRAM_NAME
##################################################################### sanity
abort "The build-tool has reset ENV. --env=std required." unless ENV['HOMEBREW_BREW_FILE']
2013-03-03 22:11:26 -06:00
case ENV['HOMEBREW_CC'].chuzzle when 'cc', nil
# those values are not allowed
ENV['HOMEBREW_CC'] = 'clang'
end
2013-03-03 22:11:26 -06:00
####################################################################### main
LOGGER.puts "#{File.basename($0)} called with: #{ARGV.join(" ")}"
2013-03-03 22:11:26 -06:00
cmd = Cmd.new($0, ARGV)
tool, args = cmd.tool, cmd.args
LOGGER.puts "superenv executed: #{tool} #{args.join(" ")}"
LOGGER.log!
exec "xcrun", tool, *args
2013-03-03 22:11:26 -06:00
end