1111# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212# See the License for the specific language governing permissions and
1313# limitations under the License.
14-
1514"""Returns information about the local Python runtime as JSON."""
1615
1716import json
@@ -38,7 +37,9 @@ def _search_directories(get_config, base_executable):
3837 # On MacOS, the LDLIBRARY may be a relative path under /Library/Frameworks,
3938 # such as "Python.framework/Versions/3.12/Python", not a file under the
4039 # LIBDIR/LIBPL directory, so include PYTHONFRAMEWORKPREFIX.
41- lib_dirs = [get_config (x ) for x in ("PYTHONFRAMEWORKPREFIX" , "LIBPL" , "LIBDIR" )]
40+ lib_dirs = [
41+ get_config (x ) for x in ("PYTHONFRAMEWORKPREFIX" , "LIBPL" , "LIBDIR" )
42+ ]
4243
4344 # On Debian, with multiarch enabled, prior to Python 3.10, `LIBDIR` didn't
4445 # tell the location of the libs, just the base directory. The `MULTIARCH`
@@ -55,8 +56,8 @@ def _search_directories(get_config, base_executable):
5556
5657 if not _IS_DARWIN :
5758 for exec_dir in (
58- os .path .dirname (base_executable ) if base_executable else None ,
59- get_config ("BINDIR" ),
59+ os .path .dirname (base_executable ) if base_executable else None ,
60+ get_config ("BINDIR" ),
6061 ):
6162 if not exec_dir :
6263 continue
@@ -67,16 +68,28 @@ def _search_directories(get_config, base_executable):
6768 lib_dirs .append (os .path .join (exec_dir , "lib" ))
6869 lib_dirs .append (os .path .join (exec_dir , "libs" ))
6970 else :
70- # On most systems the executable is in a bin/ directory and the libraries
71- # are in a sibling lib/ directory.
71+ # On most non-windows systems the executable is in a bin/ directory and
72+ # the libraries are in a sibling lib/ directory.
7273 lib_dirs .append (os .path .join (os .path .dirname (exec_dir ), "lib" ))
7374
7475 # Dedup and remove empty values, keeping the order.
7576 lib_dirs = [v for v in lib_dirs if v ]
7677 return {k : None for k in lib_dirs }.keys ()
7778
7879
79- def _search_library_names (get_config ):
80+ def _get_shlib_suffix (get_config ) -> str :
81+ """Returns the suffix for shared libraries."""
82+ if _IS_DARWIN :
83+ return ".dylib"
84+ if _IS_WINDOWS :
85+ return ".dll"
86+ suffix = get_config ("SHLIB_SUFFIX" )
87+ if not suffix :
88+ suffix = ".so"
89+ return suffix
90+
91+
92+ def _search_library_names (get_config , shlib_suffix ):
8093 """Returns a list of library files to search for shared libraries."""
8194 # Quoting configure.ac in the cpython code base:
8295 # "INSTSONAME is the name of the shared library that will be use to install
@@ -90,8 +103,7 @@ def _search_library_names(get_config):
90103 #
91104 # A typical LIBRARY is 'libpythonX.Y.a' on Linux.
92105 lib_names = [
93- get_config (x )
94- for x in (
106+ get_config (x ) for x in (
95107 "LDLIBRARY" ,
96108 "INSTSONAME" ,
97109 "PY3LIBRARY" ,
@@ -104,26 +116,24 @@ def _search_library_names(get_config):
104116 # The suffix and version are set here to the default values for the OS,
105117 # since they are used below to construct "default" library names.
106118 if _IS_DARWIN :
107- suffix = ".dylib"
108119 prefix = "lib"
109120 elif _IS_WINDOWS :
110- suffix = ".dll"
111121 prefix = ""
112122 else :
113- suffix = get_config ("SHLIB_SUFFIX" )
114123 prefix = "lib"
115- if not suffix :
116- suffix = ".so"
117124
118125 version = get_config ("VERSION" )
119126
120127 # Ensure that the pythonXY.dll files are included in the search.
121- lib_names .append (f"{ prefix } python{ version } { suffix } " )
128+ lib_names .append (f"{ prefix } python{ version } { shlib_suffix } " )
122129
123130 # If there are ABIFLAGS, also add them to the python version lib search.
124131 abiflags = get_config ("ABIFLAGS" ) or get_config ("abiflags" ) or ""
125132 if abiflags :
126- lib_names .append (f"{ prefix } python{ version } { abiflags } { suffix } " )
133+ lib_names .append (f"{ prefix } python{ version } { abiflags } { shlib_suffix } " )
134+
135+ # Add the abi-version includes to the search list.
136+ lib_names .append (f"{ prefix } python{ sys .version_info .major } { shlib_suffix } " )
127137
128138 # Dedup and remove empty values, keeping the order.
129139 lib_names = [v for v in lib_names if v ]
@@ -138,30 +148,31 @@ def _get_python_library_info(base_executable):
138148 # construct library paths such as python3.12, so ensure it exists.
139149 if not config_vars .get ("VERSION" ):
140150 if sys .platform == "win32" :
141- config_vars ["VERSION" ] = f"{ sys .version_info .major } { sys .version_info .minor } "
151+ config_vars ["VERSION" ] = (
152+ f"{ sys .version_info .major } { sys .version_info .minor } " )
142153 else :
143154 config_vars ["VERSION" ] = (
144- f"{ sys .version_info .major } .{ sys .version_info .minor } "
145- )
155+ f"{ sys .version_info .major } .{ sys .version_info .minor } " )
146156
157+ shlib_suffix = _get_shlib_suffix (config_vars .get )
147158 search_directories = _search_directories (config_vars .get , base_executable )
148- search_libnames = _search_library_names (config_vars .get )
149-
150- def _add_if_exists (target , path ):
151- if os .path .exists (path ) or os .path .isdir (path ):
152- target [path ] = None
159+ search_libnames = _search_library_names (config_vars .get , shlib_suffix )
153160
154161 interface_libraries = {}
155162 dynamic_libraries = {}
156163 static_libraries = {}
164+
157165 for root_dir in search_directories :
158166 for libname in search_libnames :
167+ # Check whether the library exists.
159168 composed_path = os .path .join (root_dir , libname )
160- if libname .endswith (".a" ):
161- _add_if_exists (static_libraries , composed_path )
162- continue
169+ if os .path .exists (composed_path ) or os .path .isdir (composed_path ):
170+ if libname .endswith (".a" ):
171+ static_libraries [composed_path ] = None
172+ else :
173+ dynamic_libraries [composed_path ] = None
163174
164- _add_if_exists ( dynamic_libraries , composed_path )
175+ interface_path = None
165176 if libname .endswith (".dll" ):
166177 # On windows a .lib file may be an "import library" or a static library.
167178 # The file could be inspected to determine which it is; typically python
@@ -172,14 +183,20 @@ def _add_if_exists(target, path):
172183 #
173184 # See: https://docs.python.org/3/extending/windows.html
174185 # https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-creation
175- _add_if_exists (
176- interface_libraries , os .path .join (root_dir , libname [:- 3 ] + "lib" )
177- )
186+ interface_path = os .path .join (root_dir , libname [:- 3 ] + "lib" )
178187 elif libname .endswith (".so" ):
179188 # It's possible, though unlikely, that interface stubs (.ifso) exist.
180- _add_if_exists (
181- interface_libraries , os .path .join (root_dir , libname [:- 2 ] + "ifso" )
182- )
189+ interface_path = os .path .join (root_dir , libname [:- 2 ] + "ifso" )
190+
191+ # Check whether an interface library exists.
192+ if interface_path and os .path .exists (interface_path ):
193+ interface_libraries [interface_path ] = None
194+
195+ # Non-windows typically has abiflags.
196+ if hasattr (sys , "abiflags" ):
197+ abiflags = sys .abiflags
198+ else :
199+ abiflags = ""
183200
184201 # When no libraries are found it's likely that the python interpreter is not
185202 # configured to use shared or static libraries (minilinux). If this seems
@@ -188,6 +205,8 @@ def _add_if_exists(target, path):
188205 "dynamic_libraries" : list (dynamic_libraries .keys ()),
189206 "static_libraries" : list (static_libraries .keys ()),
190207 "interface_libraries" : list (interface_libraries .keys ()),
208+ "shlib_suffix" : "" if _IS_WINDOWS else shlib_suffix ,
209+ "abi_flags" : abiflags ,
191210 }
192211
193212
0 commit comments