152 lines
4.5 KiB
Plaintext
Raw Normal View History

#!/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 for easier to understand code, don't monkey-patch ENV, just set via a hash from a helper class
#TODO create mechanism to specify build effects like %w{-O0 -O4 vanilla-arg-parsing sdk=10.6} etc.
#TODO DSL for lame-env (and rename to typical-env or something better)
#TODO consider always setting CC to cc and instead having HOMEBREW_CC to force cc choice in end toolchain
# in verbose mode print out things like "gcc called, but redirecting to clang" if that happens
#TODO `brew sh`: https://github.com/mxcl/homebrew/issues/14381#issuecomment-8017538
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 cmake_prefixes
@prefixes ||= ENV['CMAKE_PREFIX_PATH'].split(':').reject do |path|
case path
when '/usr/local' then !nclt?
when '/usr', '/', "#$sdkroot/usr" then true
end
end
end
class Cmd
def initialize path, args
@cmd = path.basename.freeze
@args = args.freeze
end
def mode
if @cmd == 'cpp' or @cmd == 'ld'
@cmd.to_sym
elsif @args.include? '-c'
:cc
elsif @args.include? '-E'
:cpp
else
:ccld
end
end
def tool
case @cmd
when /gcc/ then 'gcc'
when /g\+\+/ then 'g++'
when 'clang', 'clang++'
@cmd
when 'ld', 'cpp', 'cc'
ENV['HOMEBREW_CC'].chuzzle or 'clang'
when 'c++'
case ENV['HOMEBREW_CC']
when /gcc/ then 'g++'
else 'clang++'
end
else
abort "Unknown command: #{@cmd}"
end
end
def args
args = if cccfg? 'O'
refurbished_args
else
@args.dup
end
args.unshift("--sysroot=#$sdkroot") if nclt?
case mode
when :cpp
%w{-E} + cppflags + args
when :ld
ldflags + args
when :cc
cflags + cppflags + args
when :ccld
cflags + cppflags + ldflags + args
end.compact
end
def refurbished_args
iset = Set.new(cmake_prefixes.map{|prefix| "#{prefix}/include" })
lset = Set.new
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',
%r{^-[IL]/opt/local}, %r{^-[IL]/sw}, # no macports/fink
%r{^-[IL]/usr/X11}, %r{^-[IL]/opt/X11}, # we add X11 ourselves
'-pedantic', '-pedantic-errors'
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(.+)/
lib = $1.chuzzle || whittler.next
args << "-l#{lib}" if lset.add?(lib)
else
args << arg
end
end
rms = @args - args
%w{CPPFLAGS LDFLAGS CXXFLAGS CFLAGS}.each do |flag|
unison = ENV[flag].split(' ') & rms
puts "Warning! #{unison*' '} removed from #{flag.upcase} by superenv" unless unison.empty?
end
args
end
def cflags
if cccfg? 'Ob'
%w{-mtune=generic -Oz}
elsif cccfg? 'O'
u = '-arch i386 -arch x86_64' if cccfg? 'u'
c = case tool when 'clang', 'clang++' then '-march=native' end
%w{-pipe -w -Os} << u << c
else
[]
end
end
def ldflags
cmake_prefixes.map{|prefix| "#{prefix}/lib" }.to_flags('-L')
end
def cppflags
all = cmake_prefixes.map{|prefix| "#{prefix}/include" }
opt = all.select{|prefix| prefix =~ %r{^#$brewfix/opt} }
sys = all - opt + ENV['CMAKE_INCLUDE_PATH'].split(':')
# we want our keg-only includes to be found before system includes so that
# they override the system options.
sys.to_flags('-isystem') + opt.to_flags('-I')
end
end
####################################################################### sanity
abort "The build-tool has reset ENV. --lame-env required." unless ENV['HOMEBREW_BREW_FILE']
######################################################################### main
cmd = Cmd.new($0, ARGV)
exec "xcrun", cmd.tool, *cmd.args