2323_IS_DARWIN = sys .platform == "darwin"
2424
2525
26- def _search_directories (get_config ):
26+ def _search_directories (get_config , base_executable ):
2727 """Returns a list of library directories to search for shared libraries."""
2828 # There's several types of libraries with different names and a plethora
2929 # of settings, and many different config variables to check:
@@ -53,19 +53,23 @@ def _search_directories(get_config):
5353 if config_value and not config_value .endswith (multiarch ):
5454 lib_dirs .append (os .path .join (config_value , multiarch ))
5555
56- if _IS_WINDOWS :
57- # On Windows DLLs go in the same directory as the executable, while .lib
58- # files live in the lib/ or libs/ subdirectory.
59- lib_dirs .append (get_config ("BINDIR" ))
60- lib_dirs .append (os .path .join (os .path .dirname (sys .executable )))
61- lib_dirs .append (os .path .join (os .path .dirname (sys .executable ), "lib" ))
62- lib_dirs .append (os .path .join (os .path .dirname (sys .executable ), "libs" ))
63- elif not _IS_DARWIN :
64- # On most systems the executable is in a bin/ directory and the libraries
65- # are in a sibling lib/ directory.
66- lib_dirs .append (
67- os .path .join (os .path .dirname (os .path .dirname (sys .executable )), "lib" )
68- )
56+ if not _IS_DARWIN :
57+ for exec_dir in (
58+ os .path .dirname (base_executable ) if base_executable else None ,
59+ get_config ("BINDIR" ),
60+ ):
61+ if not exec_dir :
62+ continue
63+ if _IS_WINDOWS :
64+ # On Windows DLLs go in the same directory as the executable, while .lib
65+ # files live in the lib/ or libs/ subdirectory.
66+ lib_dirs .append (exec_dir )
67+ lib_dirs .append (os .path .join (exec_dir , "lib" ))
68+ lib_dirs .append (os .path .join (exec_dir , "libs" ))
69+ else :
70+ # On most systems the executable is in a bin/ directory and the libraries
71+ # are in a sibling lib/ directory.
72+ lib_dirs .append (os .path .join (os .path .dirname (exec_dir ), "lib" ))
6973
7074 # Dedup and remove empty values, keeping the order.
7175 lib_dirs = [v for v in lib_dirs if v ]
@@ -126,7 +130,7 @@ def _search_library_names(get_config):
126130 return {k : None for k in lib_names }.keys ()
127131
128132
129- def _get_python_library_info ():
133+ def _get_python_library_info (base_executable ):
130134 """Returns a dictionary with the static and dynamic python libraries."""
131135 config_vars = sysconfig .get_config_vars ()
132136
@@ -140,7 +144,7 @@ def _get_python_library_info():
140144 f"{ sys .version_info .major } .{ sys .version_info .minor } "
141145 )
142146
143- search_directories = _search_directories (config_vars .get )
147+ search_directories = _search_directories (config_vars .get , base_executable )
144148 search_libnames = _search_library_names (config_vars .get )
145149
146150 def _add_if_exists (target , path ):
@@ -187,13 +191,28 @@ def _add_if_exists(target, path):
187191 }
188192
189193
194+ def _get_base_executable ():
195+ """Returns the base executable path."""
196+ try :
197+ if sys ._base_executable : # pylint: disable=protected-access
198+ return sys ._base_executable # pylint: disable=protected-access
199+ except AttributeError :
200+ # Bug reports indicate sys._base_executable doesn't exist in some cases,
201+ # but it's not clear why.
202+ # See https://github.com/bazel-contrib/rules_python/issues/3172
203+ pass
204+ # The normal sys.executable is the next-best guess if sys._base_executable
205+ # is missing.
206+ return sys .executable
207+
208+
190209data = {
191210 "major" : sys .version_info .major ,
192211 "minor" : sys .version_info .minor ,
193212 "micro" : sys .version_info .micro ,
194213 "include" : sysconfig .get_path ("include" ),
195214 "implementation_name" : sys .implementation .name ,
196- "base_executable" : sys . _base_executable ,
215+ "base_executable" : _get_base_executable () ,
197216}
198- data .update (_get_python_library_info ())
217+ data .update (_get_python_library_info (_get_base_executable () ))
199218print (json .dumps (data ))
0 commit comments