module PyCall::LibPython::Finder
Constants
- DEFAULT_PYTHON
- LIBPREFIX
- LIBSUFFIX
Public Class Methods
candidate_names(python_config)
click to toggle source
# File lib/pycall/libpython/finder.rb, line 69 def candidate_names(python_config) names = [] names << python_config[:LDLIBRARY] if python_config[:LDLIBRARY] suffix = python_config[:SHLIB_SUFFIX] if python_config[:LIBRARY] ext = File.extname(python_config[:LIBRARY]) names << python_config[:LIBRARY].delete_suffix(ext) + suffix end dlprefix = if windows? then "" else "lib" end sysdata = { v_major: python_config[:version_major], VERSION: python_config[:VERSION], ABIFLAGS: python_config[:ABIFLAGS], } [ "python%{VERSION}%{ABIFLAGS}" % sysdata, "python%{VERSION}" % sysdata, "python%{v_major}" % sysdata, "python" ].each do |stem| names << "#{dlprefix}#{stem}#{suffix}" end names.compact! names.uniq! debug_report("candidate_names: #{names}") return names end
candidate_paths(python_config) { |python_config| ... }
click to toggle source
# File lib/pycall/libpython/finder.rb, line 99 def candidate_paths(python_config) # The candidate library that linked by executable yield python_config[:linked_libpython] lib_dirs = make_libpaths(python_config) lib_basenames = candidate_names(python_config) # candidates by absolute paths lib_dirs.each do |dir| lib_basenames.each do |name| yield File.join(dir, name) end end # library names for searching in system library paths lib_basenames.each do |name| yield name end end
find_libpython(python = nil)
click to toggle source
# File lib/pycall/libpython/finder.rb, line 40 def find_libpython(python = nil) debug_report("find_libpython(#{python.inspect})") python, python_config = find_python_config(python) suffix = python_config[:SHLIB_SUFFIX] use_conda = (ENV.fetch("CONDA_PREFIX", nil) == File.dirname(python_config[:executable])) python_home = if !ENV.key?("PYTHONHOME") || use_conda python_config[:PYTHONHOME] else ENV["PYTHONHOME"] end ENV["PYTHONHOME"] = python_home candidate_paths(python_config) do |path| debug_report("Candidate: #{path}") normalized = normalize_path(path, suffix) if normalized debug_report("Trying to dlopen: #{normalized}") begin return dlopen(normalized) rescue Fiddle::DLError debug_report "dlopen(#{normalized.inspect}) => #{$!.class}: #{$!.message}" end else debug_report("Not found.") end end end
find_python_config(python = nil)
click to toggle source
# File lib/pycall/libpython/finder.rb, line 28 def find_python_config(python = nil) python ||= DEFAULT_PYTHON Array(python).each do |python_cmd| begin python_config = investigate_python_config(python_cmd) return [python_cmd, python_config] unless python_config.empty? rescue end end raise ::PyCall::PythonNotFound end
investigate_python_config(python)
click to toggle source
# File lib/pycall/libpython/finder.rb, line 141 def investigate_python_config(python) python_env = { 'PYTHONIOENCODING' => 'UTF-8' } debug_report("investigate_python_config(#{python.inspect})") IO.popen(python_env, [python, python_investigator_py], 'r') do |io| {}.tap do |config| io.each_line do |line| next unless line =~ /: / key, value = line.chomp.split(': ', 2) case value when 'True', 'true', 'False', 'false' value = (value == 'True' || value == 'true') end config[key.to_sym] = value if value != 'None' end end end rescue Errno::ENOENT raise PyCall::PythonInvestigationFailed end
make_libpaths(python_config)
click to toggle source
# File lib/pycall/libpython/finder.rb, line 165 def make_libpaths(python_config) libpaths = python_config.values_at(:LIBPL, :srcdir, :LIBDIR) if windows? libpaths << File.dirname(python_config[:executable]) else libpaths << File.expand_path('../../lib', python_config[:executable]) end if apple? libpaths << python_config[:PYTHONFRAMEWORKPREFIX] end exec_prefix = python_config[:exec_prefix] libpaths << exec_prefix libpaths << File.join(exec_prefix, 'lib') libpaths.compact! libpaths.uniq! debug_report "libpaths: #{libpaths.inspect}" return libpaths end
normalize_path(path, suffix, apple_p=apple?)
click to toggle source
# File lib/pycall/libpython/finder.rb, line 119 def normalize_path(path, suffix, apple_p=apple?) return nil if path.nil? case when path.nil?, Pathname.new(path).relative? nil when File.exist?(path) File.realpath(path) when File.exist?(path + suffix) File.realpath(path + suffix) when apple_p normalize_path(remove_suffix_apple(path), ".so", false) else nil end end
python_investigator_py()
click to toggle source
# File lib/pycall/libpython/finder.rb, line 161 def python_investigator_py File.expand_path('../../python/investigator.py', __FILE__) end
remove_suffix_apple(path)
click to toggle source
Strip off .so or .dylib
# File lib/pycall/libpython/finder.rb, line 137 def remove_suffix_apple(path) path.sub(/\.(?:dylib|so)\z/, '') end
Private Class Methods
apple?()
click to toggle source
# File lib/pycall/libpython/finder.rb, line 195 def apple? RUBY_PLATFORM.include?("darwin") end
debug?()
click to toggle source
# File lib/pycall/libpython/finder.rb, line 210 def debug? @debug ||= (ENV['PYCALL_DEBUG_FIND_LIBPYTHON'] == '1') end
debug_report(message)
click to toggle source
# File lib/pycall/libpython/finder.rb, line 205 def debug_report(message) return unless debug? $stderr.puts "DEBUG(find_libpython) #{message}" end
dlopen(libname)
click to toggle source
# File lib/pycall/libpython/finder.rb, line 199 def dlopen(libname) Fiddle.dlopen(libname).tap do |handle| debug_report("dlopen(#{libname.inspect}) = #{handle.inspect}") if handle end end
windows?()
click to toggle source
# File lib/pycall/libpython/finder.rb, line 191 def windows? Fiddle::WINDOWS end