@@ -47,91 +47,65 @@ pysys(python::AbstractString, var::AbstractString) = pyvar(python, "sys", var)
47
47
48
48
const dlprefix = Compat. Sys. iswindows () ? " " : " lib"
49
49
50
- # return libpython name, libpython pointer
51
- function find_libpython (python:: AbstractString )
52
- # it is ridiculous that it is this hard to find the name of libpython
53
- v = pyconfigvar (python," VERSION" ," " )
54
- libs = [ dlprefix* " python" * v, dlprefix* " python" ]
55
- lib = pyconfigvar (python, " LIBRARY" )
56
- lib != " None" && pushfirst! (libs, splitext (lib)[1 ])
57
- lib = pyconfigvar (python, " LDLIBRARY" )
58
- lib != " None" && pushfirst! (pushfirst! (libs, basename (lib)), lib)
59
- libs = unique (libs)
60
-
61
- # it is ridiculous that it is this hard to find the path of libpython
62
- libpaths = [pyconfigvar (python, " LIBDIR" ),
63
- (Compat. Sys. iswindows () ? dirname (pysys (python, " executable" )) : joinpath (dirname (dirname (pysys (python, " executable" ))), " lib" ))]
64
- if Compat. Sys. isapple ()
65
- push! (libpaths, pyconfigvar (python, " PYTHONFRAMEWORKPREFIX" ))
66
- end
50
+ # print out extra info to help with remote debugging
51
+ const PYCALL_DEBUG_BUILD = " yes" == get (ENV , " PYCALL_DEBUG_BUILD" , " no" )
67
52
68
- # `prefix` and `exec_prefix` are the path prefixes where python should look for python only and compiled libraries, respectively.
69
- # These are also changed when run in a virtualenv.
70
- exec_prefix = pysys (python, " exec_prefix" )
71
-
72
- push! (libpaths, exec_prefix)
73
- push! (libpaths, joinpath (exec_prefix, " lib" ))
53
+ function exec_find_libpython (python:: AbstractString , options)
54
+ cmd = ` $python $(joinpath (@__DIR__ , " find_libpython.py" )) $options `
55
+ if PYCALL_DEBUG_BUILD
56
+ cmd = ` $cmd --verbose`
57
+ end
58
+ return readlines (pythonenv (cmd))
59
+ end
74
60
75
- error_strings = String[]
61
+ function show_dlopen_error (e)
62
+ if PYCALL_DEBUG_BUILD
63
+ println (stderr , " dlopen($libpath_lib ) ==> " , e)
64
+ # Using STDERR since find_libpython.py prints debugging
65
+ # messages to STDERR too.
66
+ end
67
+ end
76
68
77
- # TODO : other paths? python-config output? pyconfigvar("LDFLAGS")?
69
+ # return libpython name, libpython pointer
70
+ function find_libpython (python:: AbstractString )
71
+ dlopen_flags = Libdl. RTLD_LAZY| Libdl. RTLD_DEEPBIND| Libdl. RTLD_GLOBAL
78
72
79
- # find libpython (we hope):
80
- for lib in libs
81
- for libpath in libpaths
82
- libpath_lib = joinpath (libpath, lib)
83
- if isfile (libpath_lib* " ." * Libdl. dlext)
84
- try
85
- return (Libdl. dlopen (libpath_lib,
86
- Libdl. RTLD_LAZY| Libdl. RTLD_DEEPBIND| Libdl. RTLD_GLOBAL),
87
- libpath_lib)
88
- catch e
89
- push! (error_strings, string (" dlopen($libpath_lib ) ==> " , e))
90
- end
91
- end
73
+ libpaths = exec_find_libpython (python, ` --list-all` )
74
+ for lib in libpaths
75
+ try
76
+ return (Libdl. dlopen (lib, dlopen_flags), lib)
77
+ catch e
78
+ show_dlopen_error (e)
92
79
end
93
80
end
94
81
82
+ # Try all candidate libpython names and let Libdl find the path.
95
83
# We do this *last* because the libpython in the system
96
84
# library path might be the wrong one if multiple python
97
85
# versions are installed (we prefer the one in LIBDIR):
86
+ libs = exec_find_libpython (python, ` --candidate-names` )
98
87
for lib in libs
99
88
lib = splitext (lib)[1 ]
100
89
try
101
- return (Libdl. dlopen (lib, Libdl. RTLD_LAZY| Libdl. RTLD_DEEPBIND| Libdl. RTLD_GLOBAL),
102
- lib)
90
+ libpython = Libdl. dlopen (lib, dlopen_flags)
91
+ # Store the fullpath to libpython in deps.jl. This makes
92
+ # it easier for users to investigate Python setup
93
+ # PyCall.jl trying to use. It also helps PyJulia to
94
+ # compare libpython.
95
+ return (libpython, Libdl. dlpath (libpython))
103
96
catch e
104
- push! (error_strings, string (" dlopen($lib ) ==> " , e))
105
- end
106
- end
107
-
108
- if " yes" == get (ENV , " PYCALL_DEBUG_BUILD" , " no" ) # print out extra info to help with remote debugging
109
- println (stderr , " ------------------------------------- exceptions -----------------------------------------" )
110
- for s in error_strings
111
- print (s, " \n\n " )
112
- end
113
- println (stderr , " ---------------------------------- get_config_vars ---------------------------------------" )
114
- print (stderr , read (` python -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_vars())"` , String))
115
- println (stderr , " --------------------------------- directory contents -------------------------------------" )
116
- for libpath in libpaths
117
- if isdir (libpath)
118
- print (libpath, " :\n " )
119
- for file in readdir (libpath)
120
- if occursin (" pyth" , file)
121
- println (" " , file)
122
- end
123
- end
124
- end
97
+ show_dlopen_error (e)
125
98
end
126
- println (stderr , " ------------------------------------------------------------------------------------------" )
127
99
end
128
100
129
101
error ("""
130
102
Couldn't find libpython; check your PYTHON environment variable.
131
103
132
- The python executable we tried was $python (= version $v );
133
- the library names we tried were $libs
134
- and the library paths we tried were $libpaths """ )
104
+ The python executable we tried was $python (= version $v ).
105
+ Re-building with
106
+ ENV["PYCALL_DEBUG_BUILD"] = "yes"
107
+ may provide extra information for why it failed.
108
+ """ )
135
109
end
136
110
137
111
# ########################################################################
0 commit comments