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:
Max Howell 2012-08-11 12:30:51 -04:00
parent 57df15afd0
commit 65d195dcaa
23 changed files with 545 additions and 106 deletions

1
Library/ENV/4.3/c++ Symbolic link
View File

@ -0,0 +1 @@
cc

140
Library/ENV/4.3/cc Executable file
View 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
View File

@ -0,0 +1 @@
cc

1
Library/ENV/4.3/clang++ Symbolic link
View File

@ -0,0 +1 @@
cc

1
Library/ENV/4.3/cpp Symbolic link
View File

@ -0,0 +1 @@
cc

1
Library/ENV/4.3/g++ Symbolic link
View File

@ -0,0 +1 @@
cc

1
Library/ENV/4.3/gcc Symbolic link
View File

@ -0,0 +1 @@
cc

View File

@ -0,0 +1 @@
cc

View File

@ -0,0 +1 @@
cc

1
Library/ENV/4.3/ld Symbolic link
View File

@ -0,0 +1 @@
cc

1
Library/ENV/4.3/llvm-g++ Symbolic link
View File

@ -0,0 +1 @@
cc

View File

@ -0,0 +1 @@
cc

1
Library/ENV/4.3/llvm-gcc Symbolic link
View File

@ -0,0 +1 @@
cc

View File

@ -0,0 +1 @@
cc

12
Library/ENV/4.3/xcrun Executable file
View 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

View 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

View File

@ -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

View File

@ -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

View File

@ -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|

View File

@ -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

View File

@ -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

View File

@ -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

View 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