aboutsummaryrefslogtreecommitdiffstats
path: root/Library
diff options
context:
space:
mode:
authorMax Howell2012-08-11 12:30:51 -0400
committerMax Howell2012-08-29 12:41:34 -0400
commit65d195dcaaa4304e127e0a264cf97ad7b6a7fd83 (patch)
tree7b8a04d1bdb8676e5e8b978da9824365edac9bae /Library
parent57df15afd009d11e8d683353a74287e0a22ba57b (diff)
downloadbrew-65d195dcaaa4304e127e0a264cf97ad7b6a7fd83.tar.bz2
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.
Diffstat (limited to 'Library')
l---------Library/ENV/4.3/c++1
-rwxr-xr-xLibrary/ENV/4.3/cc140
l---------Library/ENV/4.3/clang1
l---------Library/ENV/4.3/clang++1
l---------Library/ENV/4.3/cpp1
l---------Library/ENV/4.3/g++1
l---------Library/ENV/4.3/gcc1
l---------Library/ENV/4.3/i686-apple-darwin11-llvm-g++-4.21
l---------Library/ENV/4.3/i686-apple-darwin11-llvm-gcc-4.21
l---------Library/ENV/4.3/ld1
l---------Library/ENV/4.3/llvm-g++1
l---------Library/ENV/4.3/llvm-g++-4.21
l---------Library/ENV/4.3/llvm-gcc1
l---------Library/ENV/4.3/llvm-gcc-4.21
-rwxr-xr-xLibrary/ENV/4.3/xcrun12
-rw-r--r--Library/ENV/libsuperenv.rb41
-rwxr-xr-xLibrary/Homebrew/build.rb61
-rw-r--r--Library/Homebrew/cmd/--env.rb6
-rw-r--r--Library/Homebrew/cmd/audit.rb3
-rw-r--r--Library/Homebrew/extend/ENV.rb121
-rw-r--r--Library/Homebrew/formula.rb4
-rw-r--r--Library/Homebrew/macos.rb10
-rw-r--r--Library/Homebrew/superenv.rb240
23 files changed, 545 insertions, 106 deletions
diff --git a/Library/ENV/4.3/c++ b/Library/ENV/4.3/c++
new file mode 120000
index 000000000..2652f5f42
--- /dev/null
+++ b/Library/ENV/4.3/c++
@@ -0,0 +1 @@
+cc \ No newline at end of file
diff --git a/Library/ENV/4.3/cc b/Library/ENV/4.3/cc
new file mode 100755
index 000000000..8673c7527
--- /dev/null
+++ b/Library/ENV/4.3/cc
@@ -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
diff --git a/Library/ENV/4.3/clang b/Library/ENV/4.3/clang
new file mode 120000
index 000000000..2652f5f42
--- /dev/null
+++ b/Library/ENV/4.3/clang
@@ -0,0 +1 @@
+cc \ No newline at end of file
diff --git a/Library/ENV/4.3/clang++ b/Library/ENV/4.3/clang++
new file mode 120000
index 000000000..2652f5f42
--- /dev/null
+++ b/Library/ENV/4.3/clang++
@@ -0,0 +1 @@
+cc \ No newline at end of file
diff --git a/Library/ENV/4.3/cpp b/Library/ENV/4.3/cpp
new file mode 120000
index 000000000..2652f5f42
--- /dev/null
+++ b/Library/ENV/4.3/cpp
@@ -0,0 +1 @@
+cc \ No newline at end of file
diff --git a/Library/ENV/4.3/g++ b/Library/ENV/4.3/g++
new file mode 120000
index 000000000..2652f5f42
--- /dev/null
+++ b/Library/ENV/4.3/g++
@@ -0,0 +1 @@
+cc \ No newline at end of file
diff --git a/Library/ENV/4.3/gcc b/Library/ENV/4.3/gcc
new file mode 120000
index 000000000..2652f5f42
--- /dev/null
+++ b/Library/ENV/4.3/gcc
@@ -0,0 +1 @@
+cc \ No newline at end of file
diff --git a/Library/ENV/4.3/i686-apple-darwin11-llvm-g++-4.2 b/Library/ENV/4.3/i686-apple-darwin11-llvm-g++-4.2
new file mode 120000
index 000000000..2652f5f42
--- /dev/null
+++ b/Library/ENV/4.3/i686-apple-darwin11-llvm-g++-4.2
@@ -0,0 +1 @@
+cc \ No newline at end of file
diff --git a/Library/ENV/4.3/i686-apple-darwin11-llvm-gcc-4.2 b/Library/ENV/4.3/i686-apple-darwin11-llvm-gcc-4.2
new file mode 120000
index 000000000..2652f5f42
--- /dev/null
+++ b/Library/ENV/4.3/i686-apple-darwin11-llvm-gcc-4.2
@@ -0,0 +1 @@
+cc \ No newline at end of file
diff --git a/Library/ENV/4.3/ld b/Library/ENV/4.3/ld
new file mode 120000
index 000000000..2652f5f42
--- /dev/null
+++ b/Library/ENV/4.3/ld
@@ -0,0 +1 @@
+cc \ No newline at end of file
diff --git a/Library/ENV/4.3/llvm-g++ b/Library/ENV/4.3/llvm-g++
new file mode 120000
index 000000000..2652f5f42
--- /dev/null
+++ b/Library/ENV/4.3/llvm-g++
@@ -0,0 +1 @@
+cc \ No newline at end of file
diff --git a/Library/ENV/4.3/llvm-g++-4.2 b/Library/ENV/4.3/llvm-g++-4.2
new file mode 120000
index 000000000..2652f5f42
--- /dev/null
+++ b/Library/ENV/4.3/llvm-g++-4.2
@@ -0,0 +1 @@
+cc \ No newline at end of file
diff --git a/Library/ENV/4.3/llvm-gcc b/Library/ENV/4.3/llvm-gcc
new file mode 120000
index 000000000..2652f5f42
--- /dev/null
+++ b/Library/ENV/4.3/llvm-gcc
@@ -0,0 +1 @@
+cc \ No newline at end of file
diff --git a/Library/ENV/4.3/llvm-gcc-4.2 b/Library/ENV/4.3/llvm-gcc-4.2
new file mode 120000
index 000000000..2652f5f42
--- /dev/null
+++ b/Library/ENV/4.3/llvm-gcc-4.2
@@ -0,0 +1 @@
+cc \ No newline at end of file
diff --git a/Library/ENV/4.3/xcrun b/Library/ENV/4.3/xcrun
new file mode 100755
index 000000000..3d2dd642e
--- /dev/null
+++ b/Library/ENV/4.3/xcrun
@@ -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
diff --git a/Library/ENV/libsuperenv.rb b/Library/ENV/libsuperenv.rb
new file mode 100644
index 000000000..dcd97efce
--- /dev/null
+++ b/Library/ENV/libsuperenv.rb
@@ -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
diff --git a/Library/Homebrew/build.rb b/Library/Homebrew/build.rb
index dd3e02442..6742f4203 100755
--- a/Library/Homebrew/build.rb
+++ b/Library/Homebrew/build.rb
@@ -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
diff --git a/Library/Homebrew/cmd/--env.rb b/Library/Homebrew/cmd/--env.rb
index 79323c300..b5d1253fe 100644
--- a/Library/Homebrew/cmd/--env.rb
+++ b/Library/Homebrew/cmd/--env.rb
@@ -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
diff --git a/Library/Homebrew/cmd/audit.rb b/Library/Homebrew/cmd/audit.rb
index 18382de59..8244d40aa 100644
--- a/Library/Homebrew/cmd/audit.rb
+++ b/Library/Homebrew/cmd/audit.rb
@@ -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|
diff --git a/Library/Homebrew/extend/ENV.rb b/Library/Homebrew/extend/ENV.rb
index 90ff517b1..69947879e 100644
--- a/Library/Homebrew/extend/ENV.rb
+++ b/Library/Homebrew/extend/ENV.rb
@@ -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
diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb
index 78209feb7..08e01a7d7 100644
--- a/Library/Homebrew/formula.rb
+++ b/Library/Homebrew/formula.rb
@@ -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
diff --git a/Library/Homebrew/macos.rb b/Library/Homebrew/macos.rb
index e6b0fbee3..a50639d20 100644
--- a/Library/Homebrew/macos.rb
+++ b/Library/Homebrew/macos.rb
@@ -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
diff --git a/Library/Homebrew/superenv.rb b/Library/Homebrew/superenv.rb
new file mode 100644
index 000000000..8061abaf4
--- /dev/null
+++ b/Library/Homebrew/superenv.rb
@@ -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