Jack Nagel b1d78cf642 Move superenv make_fuss output back to stderr
In 6e3a585607116d06f47aac2ff5a649f2898216f0 ("Improve superenv
add/remove message."), more debugging information was added to the
"make_fuss" output generated by the superenv compiler
wrapper.

This resulted in some breakage in configure scripts that inspect stderr,
so in e1bd9b9e980c433878e60833f09964b8ca996657 ("Don't use stderr for
make_fuss output."), the output was moved to stdout. This only appeared
to solve the problem, since stdout is buffered but stderr is not.

Later, in fb749e47509b77b5bd89e7b14f0a1097d4af7f40, Homebrew started
generating logs even in verbose mode. This had the side effect of moving
stdout/stderr from a TTY to a pipe, and thus stdout was no longer
line-buffered.

Since it was not line-buffered, and Ruby's internal buffers were not
flushed, the debug output was being lost. This was addressed in
2d5724af8613c820b8c14f4171fe1de6a17f10c3 ("cc: ensure wrapper output is
always flushed").

This caused stdout to be flushed during configure, which resurfaced the
original bug that prompted e1bd9b9e980c433878e60833f09964b8ca996657.
This was fixed by disabling the debug output during configure, in
f1779837a46a58520560fba3850a0e2992284d0a.

Since the original bug has been addressed in a more robust way, we can
move the debug output back to stderr.

Fixes Homebrew/homebrew#23923.
2013-11-03 20:19:54 -06:00

260 lines
7.1 KiB
Ruby
Executable File

#!/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
module ExecLogExtension
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
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'
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\+\+$/
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
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?
allflags = case mode
when :ccld, :cxxld
cflags + args + cppflags + ldflags
when :cc, :cxx
cflags + args + cppflags
when :ccE
args + cppflags
when :cpp
args + cppflags
when :ld
ldflags + args
end.compact
make_fuss(allflags) if verbose? and cccfg? 'O'
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',
/^-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 =~ /^-W[alp],/
when '-macosx_version_min', '-dylib_install_name'
args << "-Wl,#{arg},#{whittler.next}"
when /^-isysroot/
# We set the sysroot
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
doit = case path.cleanpath
when %r{^#$brewfix}
# maybe homebrew is installed to /sw or /opt/brew
true
when %r{^/opt}, %r{^/sw}, %r{/usr/X11}
false
else
true
end
args << "-L#{path}" if doit and lset.add?(path.cleanpath)
else
args << arg
end
end
args
end
def cflags
args = []
if mode == :cxx
args << '-std=c++11' if cccfg? 'x'
args << '-stdlib=libc++' if cccfg? 'g'
args << '-stdlib=libstdc++' if cccfg? 'h'
end
return args unless cccfg? 'O'
args << '-pipe' << '-w' << '-Os'
# When bottling use the oldest supported CPU type.
if cccfg? 'bc'
# Custom bottle specified during the build
args << ENV['HOMEBREW_ARCHFLAGS']
elsif cccfg? 'bi6'
args << '-march=core2'
elsif cccfg? 'bi'
args << '-march=prescott'
elsif cccfg? 'bpA'
args << '-mcpu=7400'
elsif cccfg? 'bp'
args << '-mcpu=750'
else
args << '-march=native' if tool =~ /clang/
end
ENV['HOMEBREW_ARCHS'].split(',').each { |a| args << "-arch" << a } if cccfg? 'u'
args << "-std=#{@arg0}" if @arg0 =~ /c[89]9/
args
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{|d| d == "#$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
args = libpath.to_flags('-L')
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
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: #{dups}" unless dups.empty?
STDERR.puts "brew: superenv added: #{adds*' '}" unless adds.empty?
end
def verbose?
!ENV['VERBOSE'].nil? || !ENV['HOMEBREW_VERBOSE'].nil?
end
end
if __FILE__ == $PROGRAM_NAME
STDOUT.sync = STDERR.sync = true
##################################################################### 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
extend(ExecLogExtension) if ENV['HOMEBREW_LOG']
cmd = Cmd.new($0, ARGV)
exec "xcrun", cmd.tool, *cmd.args
end