superenv: build-environments that just work
1. A minimal build environment, we don't set CFLAGS, CPPFLAGS, LDFLAGS, etc. the rationale being, the less that is set, the less variables we are introducing that can break builds. 2. A set of scripts that replace cc, ld, etc. and inject the -I, -L, etc. flags we need into the args passed to the build-tools. Because we now have complete control over compiler instantiations we do a variety of clean-up tasks, like removing bad flags, enforcing universal builds and ensuring makefiles don't try to change the order of library and include paths from ones that work to ones that don't. The previous ENV-system is still available when --env=std is specified. superenv applies to Xcode >= 4.3 only currently.
This commit is contained in:
parent
57df15afd0
commit
65d195dcaa
1
Library/ENV/4.3/c++
Symbolic link
1
Library/ENV/4.3/c++
Symbolic link
@ -0,0 +1 @@
|
||||
cc
|
||||
140
Library/ENV/4.3/cc
Executable file
140
Library/ENV/4.3/cc
Executable file
@ -0,0 +1,140 @@
|
||||
#!/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 /^-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
|
||||
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
|
||||
1
Library/ENV/4.3/clang
Symbolic link
1
Library/ENV/4.3/clang
Symbolic link
@ -0,0 +1 @@
|
||||
cc
|
||||
1
Library/ENV/4.3/clang++
Symbolic link
1
Library/ENV/4.3/clang++
Symbolic link
@ -0,0 +1 @@
|
||||
cc
|
||||
1
Library/ENV/4.3/cpp
Symbolic link
1
Library/ENV/4.3/cpp
Symbolic link
@ -0,0 +1 @@
|
||||
cc
|
||||
1
Library/ENV/4.3/g++
Symbolic link
1
Library/ENV/4.3/g++
Symbolic link
@ -0,0 +1 @@
|
||||
cc
|
||||
1
Library/ENV/4.3/gcc
Symbolic link
1
Library/ENV/4.3/gcc
Symbolic link
@ -0,0 +1 @@
|
||||
cc
|
||||
1
Library/ENV/4.3/i686-apple-darwin11-llvm-g++-4.2
Symbolic link
1
Library/ENV/4.3/i686-apple-darwin11-llvm-g++-4.2
Symbolic link
@ -0,0 +1 @@
|
||||
cc
|
||||
1
Library/ENV/4.3/i686-apple-darwin11-llvm-gcc-4.2
Symbolic link
1
Library/ENV/4.3/i686-apple-darwin11-llvm-gcc-4.2
Symbolic link
@ -0,0 +1 @@
|
||||
cc
|
||||
1
Library/ENV/4.3/ld
Symbolic link
1
Library/ENV/4.3/ld
Symbolic link
@ -0,0 +1 @@
|
||||
cc
|
||||
1
Library/ENV/4.3/llvm-g++
Symbolic link
1
Library/ENV/4.3/llvm-g++
Symbolic link
@ -0,0 +1 @@
|
||||
cc
|
||||
1
Library/ENV/4.3/llvm-g++-4.2
Symbolic link
1
Library/ENV/4.3/llvm-g++-4.2
Symbolic link
@ -0,0 +1 @@
|
||||
cc
|
||||
1
Library/ENV/4.3/llvm-gcc
Symbolic link
1
Library/ENV/4.3/llvm-gcc
Symbolic link
@ -0,0 +1 @@
|
||||
cc
|
||||
1
Library/ENV/4.3/llvm-gcc-4.2
Symbolic link
1
Library/ENV/4.3/llvm-gcc-4.2
Symbolic link
@ -0,0 +1 @@
|
||||
cc
|
||||
12
Library/ENV/4.3/xcrun
Executable file
12
Library/ENV/4.3/xcrun
Executable file
@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
# This wrapper because 4.3 xcrun doesn't work with CLT-only configurations
|
||||
# But many build-systems expect it to work. This fixes that.
|
||||
# NOTE only works if they call xcrun without a full-path. Cross your fingers!
|
||||
|
||||
if [ $HOMEBREW_SDKROOT ]; then
|
||||
exec /usr/bin/xcrun "$@"
|
||||
else
|
||||
cmd="$1"
|
||||
shift
|
||||
exec "/usr/bin/$cmd" "$@"
|
||||
fi
|
||||
41
Library/ENV/libsuperenv.rb
Normal file
41
Library/ENV/libsuperenv.rb
Normal file
@ -0,0 +1,41 @@
|
||||
# Yes, a good deal of this could be imported from Homebrew-proper
|
||||
# But Homebrew-proper is dog-slow currently, and I didn't want every cc
|
||||
# instantiation to be slower be a tangible amount.
|
||||
|
||||
class String
|
||||
def directory?; File.directory? self end
|
||||
def basename; File.basename self end
|
||||
def cleanpath; require 'pathname'; Pathname.new(self).realpath.to_s rescue self end
|
||||
def chuzzle; s = chomp; s unless s.empty? end
|
||||
def dirname; File.dirname(self) end
|
||||
end
|
||||
|
||||
class NilClass
|
||||
def chuzzle; end
|
||||
def directory?; false end
|
||||
def split(x); [] end
|
||||
end
|
||||
|
||||
class Array
|
||||
def to_flags prefix
|
||||
select{|path| path.directory? }.uniq.map{|path| prefix+path }
|
||||
end
|
||||
end
|
||||
|
||||
module Kernel extend self
|
||||
alias :_exec :exec
|
||||
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
|
||||
_exec *args
|
||||
end
|
||||
end if ENV['HOMEBREW_LOG']
|
||||
|
||||
$brewfix = "#{__FILE__}/../../../".cleanpath.freeze
|
||||
$sdkroot = ENV['HOMEBREW_SDKROOT'].freeze
|
||||
@ -13,22 +13,6 @@ at_exit do
|
||||
error_pipe = nil
|
||||
|
||||
begin
|
||||
raise $! if $! # an exception was already thrown when parsing the formula
|
||||
|
||||
require 'extend/ENV'
|
||||
require 'hardware'
|
||||
require 'keg'
|
||||
|
||||
ENV.extend(HomebrewEnvExtension)
|
||||
ENV.setup_build_environment
|
||||
# we must do this or tools like pkg-config won't get found by configure scripts etc.
|
||||
ENV.prepend 'PATH', "#{HOMEBREW_PREFIX}/bin", ':' unless ORIGINAL_PATHS.include? HOMEBREW_PREFIX/'bin'
|
||||
|
||||
# Force any future invocations of sudo to require the user's password to be
|
||||
# re-entered. This is in-case any build script call sudo. Certainly this is
|
||||
# can be inconvenient for the user. But we need to be safe.
|
||||
system "/usr/bin/sudo -k"
|
||||
|
||||
# The main Homebrew process expects to eventually see EOF on the error
|
||||
# pipe in FormulaInstaller#build. However, if any child process fails to
|
||||
# terminate (i.e, fails to close the descriptor), this won't happen, and
|
||||
@ -41,6 +25,16 @@ at_exit do
|
||||
error_pipe.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
||||
end
|
||||
|
||||
raise $! if $! # an exception was already thrown when parsing the formula
|
||||
|
||||
require 'hardware'
|
||||
require 'keg'
|
||||
|
||||
# Force any future invocations of sudo to require the user's password to be
|
||||
# re-entered. This is in-case any build script call sudo. Certainly this is
|
||||
# can be inconvenient for the user. But we need to be safe.
|
||||
system "/usr/bin/sudo -k"
|
||||
|
||||
install(Formula.factory($0))
|
||||
rescue Exception => e
|
||||
unless error_pipe.nil?
|
||||
@ -56,27 +50,36 @@ at_exit do
|
||||
end
|
||||
|
||||
def install f
|
||||
f.recursive_requirements.each { |req| req.modify_build_environment }
|
||||
keg_only_deps = f.recursive_deps.uniq.select{|dep| dep.keg_only? }
|
||||
|
||||
f.recursive_deps.uniq.each do |dep|
|
||||
dep = Formula.factory dep
|
||||
if dep.keg_only?
|
||||
opt = HOMEBREW_PREFIX/:opt/dep.name
|
||||
require 'superenv'
|
||||
|
||||
raise "#{opt} not present\nReinstall #{dep}." unless opt.directory?
|
||||
ENV.setup_build_environment unless superenv?
|
||||
|
||||
ENV.prepend 'LDFLAGS', "-L#{opt}/lib"
|
||||
ENV.prepend 'CPPFLAGS', "-I#{opt}/include"
|
||||
ENV.prepend 'PATH', "#{opt}/bin", ':'
|
||||
keg_only_deps.each do |dep|
|
||||
opt = HOMEBREW_PREFIX/:opt/dep.name
|
||||
|
||||
pcdir = opt/'lib/pkgconfig'
|
||||
ENV.prepend 'PKG_CONFIG_PATH', pcdir, ':' if pcdir.directory?
|
||||
#TODO try to fix, if only one key, easy, otherwise check formula.version
|
||||
raise "#{opt} not present\nReinstall #{dep}. Sorry :(" unless opt.directory?
|
||||
|
||||
acdir = opt/'share/aclocal'
|
||||
ENV.prepend 'ACLOCAL_PATH', acdir, ':' if acdir.directory?
|
||||
if not superenv?
|
||||
ENV.prepend_path 'PATH', "#{opt}/bin"
|
||||
ENV.prepend_path 'PKG_CONFIG_PATH', "#{opt}/lib/pkgconfig"
|
||||
ENV.prepend_path 'PKG_CONFIG_PATH', "#{opt}/share/pkgconfig"
|
||||
ENV.prepend_path 'ACLOCAL_PATH', "#{opt}/share/aclocal"
|
||||
ENV.prepend_path 'CMAKE_PREFIX_PATH', opt
|
||||
ENV.prepend 'LDFLAGS', "-L#{opt}/lib" if (opt/:lib).directory?
|
||||
ENV.prepend 'CPPFLAGS', "-I#{opt}/include" if (opt/:include).directory?
|
||||
end
|
||||
end
|
||||
|
||||
if superenv?
|
||||
ENV.deps = keg_only_deps.map(&:to_s)
|
||||
ENV.setup_build_environment
|
||||
end
|
||||
|
||||
f.recursive_requirements.each { |req| req.modify_build_environment }
|
||||
|
||||
if f.fails_with? ENV.compiler
|
||||
cs = CompilerSelector.new f
|
||||
cs.select_compiler
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
require 'extend/ENV'
|
||||
require 'superenv'
|
||||
require 'hardware'
|
||||
|
||||
module Homebrew extend self
|
||||
def __env
|
||||
ENV.extend(HomebrewEnvExtension)
|
||||
ENV.setup_build_environment
|
||||
ENV.universal_binary if ARGV.build_universal?
|
||||
if $stdout.tty?
|
||||
@ -17,10 +16,11 @@ module Homebrew extend self
|
||||
|
||||
def build_env_keys env
|
||||
%w[ CC CXX LD CFLAGS CXXFLAGS CPPFLAGS LDFLAGS SDKROOT
|
||||
CMAKE_PREFIX_PATH CMAKE_INBLUDE_PATH CMAKE_FRAMEWORK_PATH MAKEFLAGS
|
||||
CMAKE_PREFIX_PATH CMAKE_INCLUDE_PATH CMAKE_FRAMEWORK_PATH MAKEFLAGS
|
||||
MACOSX_DEPLOYMENT_TARGET PKG_CONFIG_PATH HOMEBREW_BUILD_FROM_SOURCE
|
||||
HOMEBREW_DEBUG HOMEBREW_MAKE_JOBS HOMEBREW_VERBOSE HOMEBREW_USE_CLANG
|
||||
HOMEBREW_USE_GCC HOMEBREW_USE_LLVM HOMEBREW_SVN
|
||||
MAKE GIT CPP
|
||||
ACLOCAL_PATH OBJC PATH ].select{ |key| env[key] }
|
||||
end
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
require 'formula'
|
||||
require 'utils'
|
||||
require 'extend/ENV'
|
||||
require 'superenv'
|
||||
|
||||
module Homebrew extend self
|
||||
def audit
|
||||
@ -245,7 +245,6 @@ class FormulaAuditor
|
||||
|
||||
def audit_patches
|
||||
# Some formulae use ENV in patches, so set up an environment
|
||||
ENV.extend(HomebrewEnvExtension)
|
||||
ENV.setup_build_environment
|
||||
|
||||
Patches.new(f.patches).select { |p| p.external? }.each do |p|
|
||||
|
||||
@ -178,6 +178,8 @@ module HomebrewEnvExtension
|
||||
end
|
||||
|
||||
def fortran
|
||||
fc_flag_vars = %w{FCFLAGS FFLAGS}
|
||||
|
||||
if self['FC']
|
||||
ohai "Building with an alternative Fortran compiler. This is unsupported."
|
||||
self['F77'] = self['FC'] unless self['F77']
|
||||
@ -333,28 +335,6 @@ Please take one of the following actions:
|
||||
remove_from_cflags '-Qunused-arguments'
|
||||
end
|
||||
|
||||
# Snow Leopard defines an NCURSES value the opposite of most distros
|
||||
# See: http://bugs.python.org/issue6848
|
||||
def ncurses_define
|
||||
append 'CPPFLAGS', "-DNCURSES_OPAQUE=0"
|
||||
end
|
||||
|
||||
# Shortcuts for reading common flags
|
||||
def cc; self['CC'] or "gcc"; end
|
||||
def cxx; self['CXX'] or "g++"; end
|
||||
def cflags; self['CFLAGS']; end
|
||||
def cxxflags;self['CXXFLAGS']; end
|
||||
def cppflags;self['CPPFLAGS']; end
|
||||
def ldflags; self['LDFLAGS']; end
|
||||
|
||||
# Shortcuts for lists of common flags
|
||||
def cc_flag_vars
|
||||
%w{CFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS}
|
||||
end
|
||||
def fc_flag_vars
|
||||
%w{FCFLAGS FFLAGS}
|
||||
end
|
||||
|
||||
def m64
|
||||
append_to_cflags '-m64'
|
||||
append 'LDFLAGS', '-arch x86_64'
|
||||
@ -376,49 +356,6 @@ Please take one of the following actions:
|
||||
end
|
||||
end
|
||||
|
||||
def prepend key, value, separator = ' '
|
||||
# Value should be a string, but if it is a pathname then coerce it.
|
||||
value = value.to_s
|
||||
|
||||
[*key].each do |key|
|
||||
unless self[key].to_s.empty?
|
||||
self[key] = value + separator + self[key]
|
||||
else
|
||||
self[key] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def append key, value, separator = ' '
|
||||
# Value should be a string, but if it is a pathname then coerce it.
|
||||
value = value.to_s
|
||||
|
||||
[*key].each do |key|
|
||||
unless self[key].to_s.empty?
|
||||
self[key] = self[key] + separator + value
|
||||
else
|
||||
self[key] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def append_to_cflags f
|
||||
append cc_flag_vars, f
|
||||
end
|
||||
|
||||
def remove key, value
|
||||
[*key].each do |key|
|
||||
next if self[key].nil?
|
||||
self[key] = self[key].sub value, '' # can't use sub! on ENV
|
||||
self[key] = self[key].gsub /\s+/, ' ' # compact whitespace
|
||||
self[key] = nil if self[key].empty? # keep things clean
|
||||
end
|
||||
end
|
||||
|
||||
def remove_from_cflags f
|
||||
remove cc_flag_vars, f
|
||||
end
|
||||
|
||||
def replace_in_cflags before, after
|
||||
cc_flag_vars.each do |key|
|
||||
self[key] = self[key].sub before, after if self[key]
|
||||
@ -491,13 +428,65 @@ Please take one of the following actions:
|
||||
Hardware.processor_count
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class << ENV
|
||||
def remove_cc_etc
|
||||
keys = %w{CC CXX LD CPP CFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS LDFLAGS CPPFLAGS}
|
||||
removed = Hash[*keys.map{ |key| [key, self[key]] }.flatten]
|
||||
keys.each do |key|
|
||||
self[key] = nil
|
||||
delete(key)
|
||||
end
|
||||
removed
|
||||
end
|
||||
def cc_flag_vars
|
||||
%w{CFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS}
|
||||
end
|
||||
def append_to_cflags newflags
|
||||
append(cc_flag_vars, newflags)
|
||||
end
|
||||
def remove_from_cflags f
|
||||
remove cc_flag_vars, f
|
||||
end
|
||||
def append key, value, separator = ' '
|
||||
value = value.to_s
|
||||
[*key].each do |key|
|
||||
unless self[key].to_s.empty?
|
||||
self[key] = self[key] + separator + value.to_s
|
||||
else
|
||||
self[key] = value.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
def prepend key, value, separator = ' '
|
||||
[*key].each do |key|
|
||||
unless self[key].to_s.empty?
|
||||
self[key] = value.to_s + separator + self[key]
|
||||
else
|
||||
self[key] = value.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
def prepend_path key, path
|
||||
prepend key, path, ':' if File.directory? path
|
||||
end
|
||||
def remove key, value
|
||||
[*key].each do |key|
|
||||
next unless self[key]
|
||||
self[key] = self[key].sub(value, '')
|
||||
delete(key) if self[key].to_s.empty?
|
||||
end if value
|
||||
end
|
||||
def cc; self['CC'] or "cc"; end
|
||||
def cxx; self['CXX'] or "c++"; end
|
||||
def cflags; self['CFLAGS']; end
|
||||
def cxxflags;self['CXXFLAGS']; end
|
||||
def cppflags;self['CPPFLAGS']; end
|
||||
def ldflags; self['LDFLAGS']; end
|
||||
|
||||
# Snow Leopard defines an NCURSES value the opposite of most distros
|
||||
# See: http://bugs.python.org/issue6848
|
||||
def ncurses_define
|
||||
append 'CPPFLAGS', "-DNCURSES_OPAQUE=0"
|
||||
end
|
||||
end
|
||||
|
||||
@ -470,6 +470,8 @@ protected
|
||||
removed_ENV_variables = case if args.empty? then cmd.split(' ').first else cmd end
|
||||
when "xcodebuild"
|
||||
ENV.remove_cc_etc
|
||||
when /^make\b/
|
||||
ENV.append 'HOMEBREW_CCCFG', "O", ''
|
||||
end
|
||||
|
||||
if ARGV.verbose?
|
||||
@ -500,6 +502,8 @@ protected
|
||||
|
||||
rescue
|
||||
raise BuildError.new(self, cmd, args, $?)
|
||||
ensure
|
||||
ENV['HOMEBREW_CCCFG'] = ENV['HOMEBREW_CCCFG'].delete('O') if ENV['HOMEBREW_CCCFG']
|
||||
end
|
||||
|
||||
public
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
module MacOS extend self
|
||||
|
||||
MDITEM_BUNDLE_ID_KEY = "kMDItemCFBundleIdentifier"
|
||||
|
||||
def version
|
||||
require 'version'
|
||||
MacOSVersion.new(MACOS_VERSION.to_s)
|
||||
@ -212,12 +210,12 @@ module MacOS extend self
|
||||
end
|
||||
|
||||
def app_with_bundle_id id
|
||||
mdfind(MDITEM_BUNDLE_ID_KEY, id)
|
||||
path = mdfind(id).first
|
||||
Pathname.new(path) unless path.nil? or path.empty?
|
||||
end
|
||||
|
||||
def mdfind attribute, id
|
||||
path = `/usr/bin/mdfind "#{attribute} == '#{id}'"`.split("\n").first
|
||||
Pathname.new(path) unless path.nil? or path.empty?
|
||||
def mdfind id
|
||||
`/usr/bin/mdfind "kMDItemCFBundleIdentifier == '#{id}'"`.split("\n")
|
||||
end
|
||||
|
||||
def pkgutil_info id
|
||||
|
||||
240
Library/Homebrew/superenv.rb
Normal file
240
Library/Homebrew/superenv.rb
Normal file
@ -0,0 +1,240 @@
|
||||
require 'extend/ENV'
|
||||
require 'macos'
|
||||
|
||||
### Why `superenv`?
|
||||
# 1) Only specify the environment we need (NO LDFLAGS for cmake)
|
||||
# 2) Only apply compiler specific options when we are calling that compiler
|
||||
# 3) Force all incpaths and libpaths into the cc instantiation (less bugs)
|
||||
# 4) Cater toolchain usage to specific Xcode versions
|
||||
# 5) Remove flags that we don't want or that will break builds
|
||||
# 6) Simpler code
|
||||
# 7) Simpler formula that *just work*
|
||||
# 8) Build-system agnostic configuration of the tool-chain
|
||||
|
||||
def superenv_bin
|
||||
@bin ||= (HOMEBREW_REPOSITORY/"Library/ENV").children.reject{|d| d.basename.to_s > MacOS::Xcode.version }.max
|
||||
end
|
||||
|
||||
def superenv?
|
||||
not MacOS::Xcode.bad_xcode_select_path? and # because xcrun won't work
|
||||
not MacOS::Xcode.folder.nil? and # because xcrun won't work
|
||||
superenv_bin.directory? and
|
||||
not ARGV.include? "--env=std"
|
||||
end
|
||||
|
||||
class << ENV
|
||||
attr :deps, true
|
||||
|
||||
def reset
|
||||
%w{CC CXX LD CPP OBJC MAKE
|
||||
CFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS LDFLAGS CPPFLAGS
|
||||
MACOS_DEPLOYMENT_TARGET SDKROOT
|
||||
CMAKE_PREFIX_PATH CMAKE_INCLUDE_PATH CMAKE_FRAMEWORK_PATH
|
||||
HOMEBREW_CCCFG HOMEBREW_DEP_PREFIXES
|
||||
MAKEFLAGS MAKEJOBS}.
|
||||
each{ |x| delete(x) }
|
||||
delete('CDPATH') # avoid make issues that depend on changing directories
|
||||
delete('GREP_OPTIONS') # can break CMake
|
||||
delete('CLICOLOR_FORCE') # autotools doesn't like this
|
||||
|
||||
if MacOS.mountain_lion?
|
||||
# Fix issue with sed barfing on unicode characters on Mountain Lion
|
||||
delete('LC_ALL')
|
||||
ENV['LC_CTYPE'] = "C"
|
||||
end
|
||||
end
|
||||
|
||||
def setup_build_environment
|
||||
reset
|
||||
ENV['CC'] = 'cc'
|
||||
ENV['CXX'] = 'c++'
|
||||
ENV['LD'] = 'ld'
|
||||
ENV['CPP'] = 'cpp'
|
||||
ENV['MAKE'] = 'make'
|
||||
ENV['MAKEFLAGS'] ||= "-j#{Hardware.processor_count}"
|
||||
ENV['PATH'] = determine_path
|
||||
ENV['PKG_CONFIG_PATH'] = determine_pkg_config_path
|
||||
ENV['HOMEBREW_CC'] = determine_cc
|
||||
ENV['HOMEBREW_CCCFG'] = 'b' if ARGV.build_bottle?
|
||||
ENV['HOMEBREW_SDKROOT'] = "#{MacOS.sdk_path}" if MacSystem.xcode43_without_clt?
|
||||
ENV['CMAKE_PREFIX_PATH'] = determine_cmake_prefix_path
|
||||
ENV['CMAKE_FRAMEWORK_PATH'] = "#{MacOS.sdk_path}/System/Library/Frameworks" if MacSystem.xcode43_without_clt?
|
||||
ENV['CMAKE_INCLUDE_PATH'] = determine_cmake_include_path
|
||||
ENV['ACLOCAL_PATH'] = determine_aclocal_path
|
||||
end
|
||||
|
||||
def universal_binary
|
||||
append 'HOMEBREW_CCCFG', "u", ''
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def determine_cc
|
||||
if ARGV.include? '--use-gcc'
|
||||
"gcc"
|
||||
elsif ARGV.include? '--use-llvm'
|
||||
"llvm-gcc"
|
||||
elsif ARGV.include? '--use-clang'
|
||||
"clang"
|
||||
elsif ENV['HOMEBREW_USE_CLANG']
|
||||
opoo %{HOMEBREW_USE_CLANG is deprecated, use HOMEBREW_CC="clang" instead}
|
||||
"clang"
|
||||
elsif ENV['HOMEBREW_USE_LLVM']
|
||||
opoo %{HOMEBREW_USE_LLVM is deprecated, use HOMEBREW_CC="llvm" instead}
|
||||
"llvm-gcc"
|
||||
elsif ENV['HOMEBREW_USE_GCC']
|
||||
opoo %{HOMEBREW_USE_GCC is deprecated, use HOMEBREW_CC="gcc" instead}
|
||||
"gcc"
|
||||
elsif ENV['HOMEBREW_CC']
|
||||
case ENV['HOMEBREW_CC']
|
||||
when 'clang', 'gcc' then ENV['HOMEBREW_CC']
|
||||
when 'llvm', 'llvm-gcc' then 'llvm-gcc'
|
||||
else
|
||||
opoo "Invalid value for HOMEBREW_CC: #{ENV['HOMEBREW_CC']}"
|
||||
raise # use default
|
||||
end
|
||||
else
|
||||
raise
|
||||
end
|
||||
rescue
|
||||
"clang"
|
||||
end
|
||||
|
||||
def determine_path
|
||||
paths = [superenv_bin]
|
||||
if MacSystem.xcode43_without_clt?
|
||||
paths << "#{MacSystem.xcode43_developer_dir}/usr/bin"
|
||||
paths << "#{MacSystem.xcode43_developer_dir}/Toolchains/XcodeDefault.xctoolchain/usr/bin"
|
||||
end
|
||||
paths += deps.map{|dep| "#{HOMEBREW_PREFIX}/opt/#{dep}/bin" }
|
||||
paths << HOMEBREW_PREFIX/:bin
|
||||
paths << "#{MacSystem.x11_prefix}/bin"
|
||||
paths += %w{/usr/bin /bin /usr/sbin /sbin}
|
||||
paths.to_path_s
|
||||
end
|
||||
|
||||
def determine_pkg_config_path
|
||||
paths = deps.map{|dep| "#{HOMEBREW_PREFIX}/opt/#{dep}/lib/pkgconfig" }
|
||||
paths += deps.map{|dep| "#{HOMEBREW_PREFIX}/opt/#{dep}/share/pkgconfig" }
|
||||
paths << "#{HOMEBREW_REPOSITORY}/lib/pkgconfig"
|
||||
paths << "#{HOMEBREW_REPOSITORY}/share/pkgconfig"
|
||||
# we put our paths before X because we dupe some of the X libraries
|
||||
paths << "#{MacSystem.x11_prefix}/lib/pkgconfig" << "#{MacSystem.x11_prefix}/share/pkgconfig"
|
||||
# Mountain Lion no longer ships some .pcs; ensure we pick up our versions
|
||||
paths << "#{HOMEBREW_REPOSITORY}/Library/Homebrew/pkgconfig" if MacOS.mountain_lion?
|
||||
paths.to_path_s
|
||||
end
|
||||
|
||||
def determine_cmake_prefix_path
|
||||
paths = deps.map{|dep| "#{HOMEBREW_PREFIX}/opt/#{dep}" }
|
||||
paths << "#{MacOS.sdk_path}/usr" if MacSystem.xcode43_without_clt?
|
||||
paths << HOMEBREW_PREFIX.to_s # again always put ourselves ahead of X11
|
||||
paths << MacSystem.x11_prefix
|
||||
paths.to_path_s
|
||||
end
|
||||
|
||||
def determine_cmake_include_path
|
||||
sdk = MacOS.sdk_path if MacSystem.xcode43_without_clt?
|
||||
paths = %W{#{MacSystem.x11_prefix}/include/freetype2}
|
||||
paths << "#{sdk}/usr/include/libxml2" unless deps.include? 'libxml2'
|
||||
# TODO prolly shouldn't always do this?
|
||||
paths << "#{sdk}/System/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7" if MacSystem.xcode43_without_clt?
|
||||
paths.to_path_s
|
||||
end
|
||||
|
||||
def determine_aclocal_path
|
||||
paths = deps.map{|dep| "#{HOMEBREW_PREFIX}/opt/#{dep}/share/aclocal" }
|
||||
paths << "#{HOMEBREW_PREFIX}/share/aclocal"
|
||||
paths << "/opt/X11/share/aclocal"
|
||||
paths.to_path_s
|
||||
end
|
||||
|
||||
public
|
||||
|
||||
### NO LONGER NECESSARY OR NO LONGER SUPPORTED
|
||||
def noop(*args); end
|
||||
%w[m64 m32 gcc_4_0_1 fast O4 O3 O2 Os Og O1 libxml2 minimal_optimization
|
||||
no_optimization enable_warnings fortran x11
|
||||
macosxsdk remove_macosxsdk].each{|s| alias_method s, :noop }
|
||||
|
||||
### DEPRECATE THESE
|
||||
def compiler
|
||||
case ENV['HOMEBREW_CC']
|
||||
when "llvm-gcc" then :llvm
|
||||
when "gcc", "clang" then ENV['HOMEBREW_CC'].to_sym
|
||||
else
|
||||
raise
|
||||
end
|
||||
end
|
||||
def deparallelize
|
||||
delete('MAKEFLAGS')
|
||||
end
|
||||
alias_method :j1, :deparallelize
|
||||
def gcc
|
||||
ENV['CC'] = "gcc"
|
||||
ENV['CXX'] = "g++"
|
||||
end
|
||||
def llvm
|
||||
ENV['CC'] = "llvm-gcc"
|
||||
ENV['CXX'] = "llvm-g++"
|
||||
end
|
||||
def clang
|
||||
ENV['CC'] = "clang"
|
||||
ENV['CXX'] = "clang++"
|
||||
end
|
||||
def make_jobs
|
||||
ENV['MAKEFLAGS'] =~ /-\w*j(\d)+/
|
||||
[$1.to_i, 1].max
|
||||
end
|
||||
|
||||
end if superenv?
|
||||
|
||||
|
||||
if not superenv?
|
||||
ENV.extend(HomebrewEnvExtension)
|
||||
# we must do this or tools like pkg-config won't get found by configure scripts etc.
|
||||
ENV.prepend 'PATH', "#{HOMEBREW_PREFIX}/bin", ':' unless ORIGINAL_PATHS.include? HOMEBREW_PREFIX/'bin'
|
||||
else
|
||||
ENV.deps = []
|
||||
end
|
||||
|
||||
|
||||
class Array
|
||||
def to_path_s
|
||||
map(&:to_s).select{|s| s and File.directory? s }.join(':').chuzzle
|
||||
end
|
||||
end
|
||||
|
||||
# new code because I don't really trust the Xcode code now having researched it more
|
||||
module MacSystem extend self
|
||||
def xcode_clt_installed?
|
||||
File.executable? "/usr/bin/clang" and File.executable? "/usr/bin/lldb"
|
||||
end
|
||||
|
||||
def xcode43_without_clt?
|
||||
MacOS::Xcode.version >= "4.3" and not MacSystem.xcode_clt_installed?
|
||||
end
|
||||
|
||||
def x11_prefix
|
||||
@x11_prefix ||= %W[/usr/X11 /opt/X11
|
||||
#{MacOS.sdk_path}/usr/X11].find{|path| File.directory? "#{path}/include" }
|
||||
end
|
||||
|
||||
def xcode43_developer_dir
|
||||
@xcode43_developer_dir ||=
|
||||
tst(ENV['DEVELOPER_DIR']) ||
|
||||
tst(`xcode-select -print-path 2>/dev/null`) ||
|
||||
tst("/Applications/Xcode.app/Contents/Developer") ||
|
||||
MacOS.mdfind("com.apple.dt.Xcode").find{|path| tst(path) }
|
||||
raise unless @xcode43_developer_dir
|
||||
@xcode43_developer_dir
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def tst prefix
|
||||
prefix = prefix.to_s.chomp
|
||||
xcrun = "#{prefix}/usr/bin/xcrun"
|
||||
prefix if xcrun != "/usr/bin/xcrun" and File.executable? xcrun
|
||||
end
|
||||
end
|
||||
Loading…
x
Reference in New Issue
Block a user