aboutsummaryrefslogtreecommitdiffstats
path: root/Library/ENV/4.3/cc
blob: acc0227c21d6582cf52b874710d223cc54eaf023 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#!/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 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