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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
|
#!/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 servile?
# we are servile when we are called from configure etc.
# * we give the callee the tools it asks for
# * we leave ARGV alone
# when callee is make we optimize and force HOMEBREW_CC
not cccfg? 'O'
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
@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 ||= if servile? or @arg0 == 'ld'
@arg0
elsif @arg0.include? '++'
if ENV['HOMEBREW_CC'].chuzzle =~ /gcc/
'g++'
else
'clang++'
end
else
ENV['HOMEBREW_CC'].chuzzle or 'clang'
end
end
def args
args = if servile? or tool == 'ld'
@args.dup
else
refurbished_args
end
if tool != 'ld'
args.unshift("--sysroot=#$sdkroot")
else
args.unshift($sdkroot).unshift("-syslibroot")
end 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
make_fuss(args)
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
def make_fuss args
dels = @args - args
if ENV['VERBOSE']
adds = args - @args
puts "brew: Superenv removed: #{dels*' '}" unless dels.empty?
puts "brew: Superenv added: #{adds*' '}" unless adds.empty?
else
%w{CPPFLAGS LDFLAGS CXXFLAGS CFLAGS}.each do |flag|
next unless ENV[flag]
flags = dels.select{|del| ENV[flag].include? del }.join(' ')
puts "brew: superenv removed `#{flags}' from #{flag}" unless flags.empty?
end
end
end
end
####################################################################### sanity
abort "The build-tool has reset ENV. --env=std required." unless ENV['HOMEBREW_BREW_FILE']
######################################################################### main
cmd = Cmd.new($0, ARGV)
exec "xcrun", cmd.tool, *cmd.args
|