diff --git a/Library/Homebrew/build_options.rb b/Library/Homebrew/build_options.rb index 24c49931f8..077a8b3d85 100644 --- a/Library/Homebrew/build_options.rb +++ b/Library/Homebrew/build_options.rb @@ -85,4 +85,19 @@ class BuildOptions def unused_options Options.new(@options - @args) end + + # Some options are implicitly ON because they are not explictly turned off + # by their counterpart option. This applies only to with-/without- options. + # implicit_options are needed because `depends_on 'spam' => 'with-stuff'` + # complains if 'spam' has stuff as default and only defines `--without-stuff`. + def implicit_options + implicit = unused_options.map do |o| + if o.name =~ /^with-(.+)$/ && without?($1) + Option.new("without-#{$1}") # we loose the description, but that's ok + elsif o.name =~ /^without-(.+)$/ && with?($1) + Option.new("with-#{$1}") + end + end.compact + Options.new(implicit) + end end diff --git a/Library/Homebrew/cmd/audit.rb b/Library/Homebrew/cmd/audit.rb index 6bab710951..99aad13928 100644 --- a/Library/Homebrew/cmd/audit.rb +++ b/Library/Homebrew/cmd/audit.rb @@ -148,11 +148,18 @@ class FormulaAuditor problem <<-EOS.undent unless dep.tags.any? || f.name =~ /automake/ && dep.name == 'autoconf' #{dep} dependency should be "depends_on '#{dep}' => :build" EOS - when "git", "python", "ruby", "emacs", "mysql", "mercurial" + when "git", "ruby", "emacs", "mysql", "mercurial" problem <<-EOS.undent Don't use #{dep} as a dependency. We allow non-Homebrew #{dep} installations. EOS + when 'python', 'python2', 'python3' + problem <<-EOS.undent + Don't use #{dep} as a dependency (string). + We have special `depends_on :python` (or :python2 or :python3 ) + that works with brewed and system Python and allows us to support + bindings for 2.x and 3.x in parallel and much more. + EOS when "postgresql" # Postgis specifically requires a Homebrewed postgresql unless f.name == "postgis" @@ -232,7 +239,7 @@ class FormulaAuditor end if p =~ %r[^http://prdownloads\.] - problem "Don't use prdownloads in SourceForge urls (url is #{p}).\n" + + problem "Don't use prdownloads in SourceForge urls (url is #{p}).\n" + "\tSee: http://librelist.com/browser/homebrew/2011/1/12/prdownloads-is-bad/" end @@ -249,7 +256,7 @@ class FormulaAuditor # Check for http:// GitHub repo urls, https:// is preferred. urls.grep(%r[^http://github\.com/.*\.git$]) do |u| problem "Use https:// URLs for accessing GitHub repositories (url is #{u})." - end + end # Use new-style archive downloads urls.select { |u| u =~ %r[https://.*/(?:tar|zip)ball/] and not u =~ %r[\.git$] }.each do |u| @@ -427,6 +434,14 @@ class FormulaAuditor problem "Reference '#{$1}' without dashes" end + if text =~ /build\.with\?\s+['"]-?-?with-(.*)['"]/ + problem "No double 'with': Use `build.with? '#{$1}'` to check for \"--with-#{$1}\"" + end + + if text =~ /build\.without\?\s+['"]-?-?without-(.*)['"]/ + problem "No double 'without': Use `build.without? '#{$1}'` to check for \"--without-#{$1}\"" + end + if text =~ /ARGV\.(?!(debug\?|verbose\?|find[\(\s]))/ problem "Use build instead of ARGV to check options" end @@ -457,6 +472,52 @@ class FormulaAuditor end end + def audit_python + if text =~ /system\(?\s*['"]python/ + # Todo: In `def test` it is okay to do it this way. It's even recommended! + problem "Instead of `system 'python', ...`, call `system python, ...`." + end + + if text =~ /system\(?\s*python\.binary/ + problem "Instead of `system python.binary, ...`, call `system python, ...`." + end + + if text =~ /(def\s*)?which_python/ + problem "Replace `which_python` by `python.xy`, which returns e.g. 'python2.7'." + end + + if text =~ /which\(?["']python/ + problem "Don't locate python with `which 'python'`, use `python.binary` instead" + end + + if f.requirements.any?{ |r| r.kind_of?(PythonInstalled) } + # Don't check this for all formulae, because some are allowed to set the + # PYTHONPATH. E.g. python.rb itself needs to set it. + if text =~ /ENV\.append.*PYTHONPATH/ || text =~ /ENV\[['"]PYTHONPATH['"]\]\s*=[^=]/ + problem "Don't set the PYTHONPATH, instead declare `depends_on :python`." + end + end + + if text =~ /(\s*)def\s+caveats((.*\n)*?)(\1end)/ || /(\s*)def\s+caveats;(.*?)end/ + caveats_body = $2 + if caveats_body =~ /(python[23]?)\.(.*\w)/ + # So if in the body of caveats there is a `python.whatever` called, + # check that there is a guard like `if python` or similiar: + python = $1 + method = $2 + unless caveats_body =~ /(if python[23]?)|(if build\.with\?\s?\(?['"]python)|(unless build.without\?\s?\(?['"]python)/ + problem "Please guard `#{python}.#{method}` like so `#{python}.#{method} if #{python}`" + end + end + end + + # Todo: + # The python do ... end block is possibly executed twice. Once for + # python 2.x and once for 3.x. So if a `system 'make'` is called, a + # `system 'make clean'` should also be called at the end of the block. + + end + def audit audit_file audit_specs @@ -465,6 +526,7 @@ class FormulaAuditor audit_conflicts audit_patches audit_text + audit_python end private diff --git a/Library/Homebrew/dependency.rb b/Library/Homebrew/dependency.rb index cc378b7dfc..a6905bc37e 100644 --- a/Library/Homebrew/dependency.rb +++ b/Library/Homebrew/dependency.rb @@ -47,7 +47,7 @@ class Dependency end def missing_options - options - Tab.for_formula(to_formula).used_options + options - Tab.for_formula(to_formula).used_options - to_formula.build.implicit_options end def universal! diff --git a/Library/Homebrew/dependency_collector.rb b/Library/Homebrew/dependency_collector.rb index 3de385fbf5..74f94dc631 100644 --- a/Library/Homebrew/dependency_collector.rb +++ b/Library/Homebrew/dependency_collector.rb @@ -17,7 +17,7 @@ require 'set' class DependencyCollector # Define the languages that we can handle as external dependencies. LANGUAGE_MODULES = Set[ - :chicken, :jruby, :lua, :node, :ocaml, :perl, :python, :rbx, :ruby + :chicken, :jruby, :lua, :node, :ocaml, :perl, :python, :python2, :python3, :rbx, :ruby ].freeze attr_reader :deps, :requirements @@ -92,6 +92,9 @@ class DependencyCollector when :clt then CLTDependency.new(tags) when :arch then ArchRequirement.new(tags) when :hg then MercurialDependency.new(tags) + when :python then PythonInstalled.new(tags) + when :python2 then PythonInstalled.new("2", tags) + when :python3 then PythonInstalled.new("3", tags) else raise "Unsupported special dependency #{spec}" end diff --git a/Library/Homebrew/download_strategy.rb b/Library/Homebrew/download_strategy.rb index 6745219fb6..72a0652fbe 100644 --- a/Library/Homebrew/download_strategy.rb +++ b/Library/Homebrew/download_strategy.rb @@ -548,6 +548,7 @@ class MercurialDownloadStrategy < AbstractDownloadStrategy def cached_location; @clone; end def hgpath + # #{HOMEBREW_PREFIX}/share/python/hg is deprecated, but we levae it in for a while @path ||= %W[ #{which("hg")} #{HOMEBREW_PREFIX}/bin/hg diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index dab9726eda..bf64044b33 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -305,6 +305,21 @@ class Formula ] end + def python(options={:allowed_major_versions => [2, 3]}, &block) + require 'python_helper' + self.instance_eval{ python_helper(options, &block) } + end + + # Explicitly only execute the block for 2.x (if a python 2.x is available) + def python2 &block + python(:allowed_major_versions => [2], &block) + end + + # Explicitly only execute the block for 3.x (if a python 3.x is available) + def python3 &block + python(:allowed_major_versions => [3], &block) + end + def self.class_s name # remove invalid characters and then camelcase it name.capitalize.gsub(/[-_.\s]([a-zA-Z0-9])/) { $1.upcase } \ @@ -558,7 +573,7 @@ class Formula @exec_count ||= 0 @exec_count += 1 logd = HOMEBREW_LOGS/name - logfn = "#{logd}/%02d.%s" % [@exec_count, File.basename(cmd).split(' ').first] + logfn = "#{logd}/%02d.%s" % [@exec_count, File.basename(cmd.to_s).split(' ').first] mkdir_p(logd) rd, wr = IO.pipe @@ -567,7 +582,7 @@ class Formula $stdout.reopen wr $stderr.reopen wr args.collect!{|arg| arg.to_s} - exec(cmd, *args) rescue nil + exec(cmd.to_s, *args) rescue nil puts "Failed to execute: #{cmd}" exit! 1 # never gets here unless exec threw or failed end diff --git a/Library/Homebrew/keg.rb b/Library/Homebrew/keg.rb index a63af419d0..e1df0adb5b 100644 --- a/Library/Homebrew/keg.rb +++ b/Library/Homebrew/keg.rb @@ -210,15 +210,18 @@ class Keg < Pathname def link_dir foo, mode=OpenStruct.new root = self+foo return unless root.exist? - root.find do |src| next if src == root - dst = HOMEBREW_PREFIX+src.relative_path_from(self) dst.extend ObserverPathnameExtension if src.file? Find.prune if File.basename(src) == '.DS_Store' + # Don't link pyc files because Python overwrites these cached object + # files and next time brew wants to link, the pyc file is in the way. + if src.extname.to_s == '.pyc' && src.to_s =~ /site-packages/ + Find.prune + end case yield src.relative_path_from(root) when :skip_file, nil @@ -233,7 +236,6 @@ class Keg < Pathname elsif src.directory? # if the dst dir already exists, then great! walk the rest of the tree tho next if dst.directory? and not dst.symlink? - # no need to put .app bundles in the path, the user can just use # spotlight, or the open command and actual mac apps use an equivalent Find.prune if src.extname.to_s == '.app' diff --git a/Library/Homebrew/python_helper.rb b/Library/Homebrew/python_helper.rb new file mode 100644 index 0000000000..ef71b2a30e --- /dev/null +++ b/Library/Homebrew/python_helper.rb @@ -0,0 +1,80 @@ + +# The python_helper is used in the Formula class when the user calls +# `python`, `python2` or `python3`. + +# This method has a dual nature. For one, it takes a &block and sets up +# the ENV such that a Python, as defined in the requirements, is the default. +# If there are multiple `PythonInstalled` requirements, the block is evaluated +# once for each Python. This makes it possible to easily support 2.x and +# 3.x Python bindings without code duplication in formulae. +# If you need to special case stuff, set :allowed_major_versions. +# Second, inside the block, a formula author may call this method to access +# certain convienience methods for the currently selected Python, e.g. +# `python.site_packages`. +def python_helper(options={:allowed_major_versions => [2, 3]}, &block) + if !block_given? and !@current_python.nil? + # We are already inside of a `python do ... end` block, so just return + # the current_python or false if the version.major is not allowed. + if options[:allowed_major_versions].include?(@current_python.version.major) + @current_python + else + false + end + else + # Look for PythonInstalled requirements for this formula + python_reqs = requirements.select{ |r| r.kind_of?(PythonInstalled) } + if python_reqs.empty? + raise "If you use python in the formula, you have to add `depends_on :python` (or :python3)!" + end + # Now select those that are satisfied and matching the version.major + python_reqs = python_reqs.select do |p| + p.satisfied? && + options[:allowed_major_versions].include?(p.version.major) && + if p.optional? || p.recommended? + self.build.with?(p.name) + else + true + end + end + + # Allow to use an else-branch like so: `if python do ... end; else ... end` + return false if python_reqs.empty? + + # Sort by version, so the older 2.x will be used first and if no + # block_given? then 2.x is preferred because it is returned. + # Further note, having 3.x last allows us to run `2to3 --write .` + # which modifies the sources in-place (for some packages that need this). + python_reqs.sort_by{ |py| py.version }.map do |py| + # Now is the time to set the site_packages to the correct value + py.site_packages = lib/py.xy/'site-packages' + if block_given? + puts "brew: Python block (#{py.binary})..." if ARGV.verbose? + require 'superenv' + # Ensure env changes are only temporary by using `with_build_environment` + ENV.with_build_environment do + # In order to install into the Cellar, the dir must exist and be in the + # PYTHONPATH. This will be executed in the context of the formula + # so that lib points to the HOMEBREW_PREFIX/Cellar///lib + puts "brew: Setting PYTHONPATH=#{py.site_packages}" if ARGV.verbose? + mkdir_p py.site_packages + ENV.append 'PYTHONPATH', py.site_packages, ':' + ENV['PYTHON'] = py.binary + ENV.prepend 'CMAKE_INCLUDE_PATH', py.incdir, ':' + ENV.prepend 'PKG_CONFIG_PATH', py.pkg_config_path, ':' if py.pkg_config_path + ENV.prepend 'PATH', py.binary.dirname, ':' unless py.from_osx? + # Track the state of the currently selected python for this block, + # so if this python_helper is called again _inside_ the block, we can + # just return the right python (see `else`-branch a few lines down): + @current_python = py + res = instance_eval(&block) + @current_python = nil + res + end + else + puts "brew: Using #{py.binary}" if ARGV.verbose? + # We return here with intention, because no block_given? + return py + end + end + end +end diff --git a/Library/Homebrew/requirements.rb b/Library/Homebrew/requirements.rb index ad621867c5..c1c7fff7a1 100644 --- a/Library/Homebrew/requirements.rb +++ b/Library/Homebrew/requirements.rb @@ -3,6 +3,7 @@ require 'requirements/conflict_requirement' require 'requirements/language_module_dependency' require 'requirements/x11_dependency' require 'requirements/mpi_dependency' +require 'requirements/python_dependency' class XcodeDependency < Requirement fatal true diff --git a/Library/Homebrew/requirements/language_module_dependency.rb b/Library/Homebrew/requirements/language_module_dependency.rb index 7c293e0c58..e62e615309 100644 --- a/Library/Homebrew/requirements/language_module_dependency.rb +++ b/Library/Homebrew/requirements/language_module_dependency.rb @@ -27,7 +27,8 @@ class LanguageModuleDependency < Requirement when :node then %W{/usr/bin/env node -e require('#{@import_name}');} when :ocaml then %W{/usr/bin/env opam list #{@import_name} | grep #{@import_name}} when :perl then %W{/usr/bin/env perl -e use\ #{@import_name}} - when :python then %W{/usr/bin/env python -c import\ #{@import_name}} + when :python then %W{/usr/bin/env python2 -c import\ #{@import_name}} + when :python3 then %W{/usr/bin/env python3 -c import\ #{@import_name}} when :ruby then %W{/usr/bin/env ruby -rubygems -e require\ '#{@import_name}'} when :rbx then %W{/usr/bin/env rbx -rubygems -e require\ '#{@import_name}'} end @@ -42,6 +43,7 @@ class LanguageModuleDependency < Requirement when :ocaml then "opam install" when :perl then "cpan -i" when :python then "pip install" + when :python3 then "pip3 install" when :rbx then "rbx gem install" when :ruby then "gem install" end diff --git a/Library/Homebrew/requirements/python_dependency.rb b/Library/Homebrew/requirements/python_dependency.rb new file mode 100644 index 0000000000..194d434c72 --- /dev/null +++ b/Library/Homebrew/requirements/python_dependency.rb @@ -0,0 +1,296 @@ +require 'requirement' + +# We support Python 2.x and 3.x, either brewed or external. +# This requirement locates the correct CPython binary (no PyPy), provides +# support methods like `site_packages`, and writes our sitecustomize.py file. +# In `dependency_collector.rb`, special `:python` and `:python3` shortcuts are +# defined. You can specify a minimum version of the Python that needs to be +# present, but since not every package is ported to 3.x yet, +# `PythonInstalled("2")` is not satisfied by 3.x. +# In a formula that shall provide support for 2.x and 3.x, the idiom is: +# depends_on :python +# depends_on :python3 => :optional # or :recommended +# +# Todo: +# - Allow further options that choose: universal, framework?, brewed?... +class PythonInstalled < Requirement + attr_reader :min_version + attr_reader :if3then3 + attr_reader :site_packages + attr_accessor :site_packages + + fatal true # you can still make Python optional by `depends_on :python => :optional` + + class PythonVersion < Version + def major + to_a[0].to_s.to_i # Python's major.minor are always ints. + end + def minor + to_a[1].to_s.to_i + end + end + + def initialize(*tags) + # Extract the min_version if given. Default to python 2.X else + tags.flatten! + if /(\d+\.)*\d+/ === tags.first + @min_version = PythonVersion.new(tags.shift) + else + @min_version = PythonVersion.new("2.7") # default + end + + # often used idiom: e.g. sipdir = "share/sip" + python.if3then3 + if @min_version.major == 3 + @if3then3 = "3" + else + @if3then3 = "" + end + + # Set name according to the major version. + # The name is used to generate the options like --without-python3 + @name = "python" + @if3then3 + + # will be set later by the python_helper, because it needs the + # formula prefix to set site_packages + @site_packages = nil + + super tags + end + + # Note that during `satisfy` we still have the PATH as the user has set. + # We look for a brewed python or an external Python and store the loc of + # that binary for later usage. (See Formula#python) + satisfy :build_env => false do + @unsatisfied_because = "This formula needs #{@name}.\n" + if binary.nil? + @unsatisfied_because += "But no `#{@name}` found in your PATH! Consider to `brew install #{@name}`." + false + elsif pypy? + @unsatisfied_because += "Your #{@name} executable appears to be a PyPy, which is not supported." + false + elsif version.major != @min_version.major + @unsatisfied_because += "No Python #{@min_version.major}.x found!" + false + elsif version < @min_version + @unsatisfied_because += "Python version #{version} is too old (need at least #{@min_version})." + false + elsif @min_version.major == 2 && `python -c "import sys; print(sys.version_info.major)"`.strip == "3" + @unsatisfied_because += "Your `python` points to a Python 3.x. This is not supported." + false + else + true + end + end + + # The full path to the python or python3 executable, depending on `version`. + def binary + if brewed? + # If the python is brewed we always prefer it! + # Note, we don't support homebrew/versions/pythonXX.rb, though. + Formula.factory(@name).opt_prefix/"bin/python#{@min_version.major}" + else + p = which(@name) + raise "PythonInstalled: #{p} is not executable" if !p.nil? && !p.executable? + p + end + end + + # The python prefix (special cased for a brewed python to point into the opt_prefix) + def prefix + if brewed? + # Homebrew since a long while only supports frameworked python + HOMEBREW_PREFIX/"opt/#{name}/Frameworks/Python.framework/Versions/#{version.major}.#{version.minor}" + elsif from_osx? + # Python on OS X has been stripped off its includes (unless you install the CLT), therefore we use the MacOS.sdk. + Pathname.new("#{MacOS.sdk_path}/System/Library/Frameworks/Python.framework/Versions/#{version.major}.#{version.minor}") + else + # What Python knows about itself + Pathname.new(`#{binary} -c 'import sys;print(sys.prefix)'`.strip) + end + end + + # Get the actual x.y.z version by asking python (or python3 if @min_version>=3) + def version + @version ||= PythonVersion.new(`#{binary} -c 'import sys;print(sys.version[:5])'`.strip) + end + + # python.xy => "python2.7" is often used (and many formulae had this as `which_python`). + def xy + "python#{version.major}.#{version.minor}" + end + + # Homebrew's global site-packages. The local ones are populated by the + # python_helper method when the `prefix` of a formula is known. + def global_site_packages + HOMEBREW_PREFIX/"lib/#{xy}/site-packages" + end + + # Dir containing Python.h and others. + def incdir + if (from_osx? || brewed?) && framework? + prefix/"Headers" + else + # For all other we use Python's own standard method (works with a non-framework version, too) + Pathname.new(`#{binary} -c 'from distutils import sysconfig; print(sysconfig.get_python_inc())'`.strip) + end + end + + # Dir containing e.g. libpython2.7.dylib + def libdir + if brewed? || from_osx? + prefix/"lib/#{xy}/config" + else + Pathname.new(`#{binary} -c "from distutils import sysconfig; print(sysconfig.get_config_var('LIBPL'))"`.strip) + end + end + + # Pkgconfig (pc) files of python + def pkg_config_path + if from_osx? + # No matter if CLT-only or Xcode-only, the pc file is always here on OS X: + path = Pathname.new("/System/Library/Frameworks/Python.framework/Versions/#{version.major}.#{version.minor}/lib/pkgconfig") + path if path.exist? + else + prefix/"lib/pkgconfig" + end + end + + # Is the Python brewed (and linked)? + def brewed? + @brewed ||= begin + require 'formula' + f = Formula.factory(@name) + f.installed? && f.linked_keg.exist? + end + end + + # Is the python the one from OS X? + def from_osx? + @from_osx ||= begin + p = `#{binary} -c "import sys; print(sys.prefix)"`.strip + p.start_with?("/System/Library/Frameworks/Python.framework") + end + end + + # Is the `python` a PyPy? + def pypy? + @pypy ||= !(`#{binary} -c "import sys; print(sys.version)"`.downcase =~ /.*pypy.*/).nil? + end + + # Is this python a framework-style install (OS X only)? + def framework? + @framework ||= /Python[0-9]*\.framework/ === prefix.to_s + end + + def universal? + @universal ||= archs_for_command(binary).universal? + end + + def standard_caveats + if brewed? + "" # empty string, so we can concat this + else + <<-EOS.undent + For non-homebrew #{@name} (#{@min_version.major}.x), you need to amend your PYTHONPATH like so: + export PYTHONPATH=#{global_site_packages}:$PYTHONPATH + EOS + end + end + + def modify_build_environment + # Write our sitecustomize.py + file = global_site_packages/"sitecustomize.py" + ohai "Writing #{file}" if ARGV.verbose? || ARGV.homebrew_developer? + [".pyc", ".pyo", ".py"].map{ |f| + global_site_packages/"sitecustomize#{f}" + }.each{ |f| f.delete if f.exist? } + file.write(sitecustomize) + + # For non-system python's we add the opt_prefix/bin of python to the path. + ENV.prepend 'PATH', binary.dirname, ':' unless from_osx? + + ENV['PYTHONHOME'] = nil # to avoid fuck-ups. + ENV['PYTHONNOUSERSITE'] = '1' + # Python respects the ARCHFLAGS var if set. Shall we set them here? + # ENV['ARCHFLAGS'] = ??? # FIXME + ENV.append 'CMAKE_INCLUDE_PATH', incdir, ':' + ENV.append 'PKG_CONFIG_PATH', pkg_config_path, ':' if pkg_config_path + + # Udpate distutils.cfg (later we can remove this, but people still have + # their old brewed pythons and we have to update it here) + # Todo: If Jack's formula revisions arrive, we can get rid of this here! + if brewed? + require 'formula' + file = Formula.factory(@name).prefix/"Frameworks/Python.framework/Versions/#{version.major}.#{version.minor}/lib/#{xy}/distutils/distutils.cfg" + ohai "Writing #{file}" if ARGV.verbose? || ARGV.homebrew_developer? + file.delete if file.exist? + file.write <<-EOF.undent + [global] + verbose=1 + [install] + force=1 + prefix=#{HOMEBREW_PREFIX} + EOF + end + end + + def sitecustomize + <<-EOF.undent + # This file is created by Homebrew and is executed on each python startup. + # Don't print from here, or else universe will collapse. + import sys + + if sys.version_info.major == #{version.major} and sys.version_info.minor == #{version.minor}: + if sys.executable.startswith('#{HOMEBREW_PREFIX}'): + # Fix 1) + # A setuptools.pth and/or easy-install.pth sitting either in + # /Library/Python/2.7/site-packages or in + # ~/Library/Python/2.7/site-packages can inject the + # /System's Python site-packages. People then report + # "OSError: [Errno 13] Permission denied" because pip/easy_install + # attempts to install into + # /System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python + # See: https://github.com/mxcl/homebrew/issues/14712 + # Fix 2) + # Remove brewed Python's hard-coded Cellar-site-packages + sys.path = [ p for p in sys.path + if not (p.startswith('/System') or + p.startswith('#{HOMEBREW_PREFIX}/Cellar/python') and p.endswith('site-packages')) ] + # Fix 3) + # Set the sys.executable to use the opt_prefix + sys.executable = '#{HOMEBREW_PREFIX}/opt/#{name}/bin/python#{version.major}.#{version.minor}' + # Fix 4) + # Make LINKFORSHARED (and python-confing --ldflags) return the + # full path to the lib (yes, "Python" is actually the lib, not a + # dir) so that third-party software does not need to add the + # -F/#{HOMEBREW_PREFIX}/Frameworks switch. + # Assume Framework style build (default since months in brew) + try: + from _sysconfigdata import build_time_vars + build_time_vars['LINKFORSHARED'] = '-u _PyMac_Error #{HOMEBREW_PREFIX}/opt/#{name}/Frameworks/Python.framework/Versions/#{version.major}.#{version.minor}/Python' + except: + pass # remember: don't print here. Better to fail silent. + # Fix 5) + # For all Pythons of the right major.minor version: Tell about homebrew's + # site-packages location. This is needed for Python to parse *.pth. + import site + site.addsitedir('#{global_site_packages}') + EOF + end + + def message + @unsatisfied_because + end + + def <=> other + version <=> other.version + end + + def to_s + binary.to_s + end + + def hash + to_s.hash + end +end diff --git a/Library/Homebrew/superenv.rb b/Library/Homebrew/superenv.rb index 18a47ca0d6..022517534b 100644 --- a/Library/Homebrew/superenv.rb +++ b/Library/Homebrew/superenv.rb @@ -30,7 +30,7 @@ class << ENV alias_method :x11?, :x11 def reset - %w{CC CXX OBJC OBJCXX CPP MAKE LD + %w{CC CXX OBJC OBJCXX CPP MAKE LD LDSHARED CFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS LDFLAGS CPPFLAGS MACOS_DEPLOYMENT_TARGET SDKROOT CMAKE_PREFIX_PATH CMAKE_INCLUDE_PATH CMAKE_FRAMEWORK_PATH @@ -57,7 +57,7 @@ class << ENV ENV['HOMEBREW_BREW_FILE'] = HOMEBREW_BREW_FILE 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_FRAMEWORK_PATH'] = determine_cmake_frameworks_path ENV['CMAKE_INCLUDE_PATH'] = determine_cmake_include_path ENV['CMAKE_LIBRARY_PATH'] = determine_cmake_library_path ENV['ACLOCAL_PATH'] = determine_aclocal_path @@ -133,7 +133,6 @@ class << ENV paths << "#{MacOS::Xcode.prefix}/Toolchains/XcodeDefault.xctoolchain/usr/bin" end paths += deps.map{|dep| "#{HOMEBREW_PREFIX}/opt/#{dep}/bin" } - paths << "#{HOMEBREW_PREFIX}/opt/python/bin" if brewed_python? paths << "#{MacSystem.x11_prefix}/bin" if x11? paths += %w{/usr/bin /bin /usr/sbin /sbin} paths.to_path_s @@ -158,6 +157,14 @@ class << ENV paths.to_path_s end + def determine_cmake_frameworks_path + # XXX: keg_only_deps perhaps? but Qt does not link its Frameworks because of Ruby's Find.find ignoring symlinks!! + paths = deps.map{|dep| "#{HOMEBREW_PREFIX}/opt/#{dep}/Frameworks" } + paths << "#{HOMEBREW_PREFIX}/Frameworks" + paths << "#{MacOS.sdk_path}/System/Library/Frameworks" if MacSystem.xcode43_without_clt? + paths.to_path_s + end + def determine_cmake_include_path sdk = MacOS.sdk_path if MacSystem.xcode43_without_clt? paths = [] @@ -165,11 +172,6 @@ class << ENV paths << "#{sdk}/usr/include/libxml2" unless deps.include? 'libxml2' if MacSystem.xcode43_without_clt? paths << "#{sdk}/usr/include/apache2" - paths << if brewed_python? - "#{HOMEBREW_PREFIX}/opt/python/Frameworks/Python.framework/Headers" - else - "#{sdk}/System/Library/Frameworks/Python.framework/Versions/Current/include/python2.7" - end end paths << "#{sdk}/System/Library/Frameworks/OpenGL.framework/Versions/Current/Headers/" unless x11? paths << "#{MacSystem.x11_prefix}/include" if x11? @@ -227,11 +229,6 @@ class << ENV MacOS::Xcode.prefix || ENV['DEVELOPER_DIR'] end - def brewed_python? - require 'formula' - Formula.factory('python').linked_keg.directory? - end - public ### NO LONGER NECESSARY OR NO LONGER SUPPORTED diff --git a/Library/Homebrew/test/test_build_options.rb b/Library/Homebrew/test/test_build_options.rb index daf5ef96b2..cc5fd01d7b 100644 --- a/Library/Homebrew/test/test_build_options.rb +++ b/Library/Homebrew/test/test_build_options.rb @@ -42,4 +42,15 @@ class BuildOptionsTests < Test::Unit::TestCase def test_unused_options assert @build.unused_options.include?("--without-baz") end + + def test_implicit_options + # --without-baz is not explicitly specified on the command line + # therefore --with-baz should be implicitly assumed: + assert @build.implicit_options.include?("--with-baz") + # But all these should not be in the implict_options: + assert !@build.implicit_options.include?("--without-baz") + assert !@build.implicit_options.include?("--with-bar") + assert !@build.implicit_options.include?("--without-bar") + assert !@build.implicit_options.include?("--with-qux") + end end diff --git a/Library/Homebrew/test/test_python.rb b/Library/Homebrew/test/test_python.rb new file mode 100644 index 0000000000..7658efa85a --- /dev/null +++ b/Library/Homebrew/test/test_python.rb @@ -0,0 +1 @@ +#TODO! \ No newline at end of file diff --git a/Library/Homebrew/utils.rb b/Library/Homebrew/utils.rb index e959d9d642..60eead67c8 100644 --- a/Library/Homebrew/utils.rb +++ b/Library/Homebrew/utils.rb @@ -97,7 +97,7 @@ module Homebrew fork do yield if block_given? args.collect!{|arg| arg.to_s} - exec(cmd, *args) rescue nil + exec(cmd.to_s, *args) rescue nil exit! 1 # never gets here unless exec failed end Process.wait