setup: detect Python DLL filename from loaded DLL

Attempting to build Mercurial from source using MinGW from
msys2 on Windows produces a hg.exe that attempts to load e.g.
python27.dll. MinGW prefixes its library name with "lib" and
adds a period between the major and minor versions. e.g.
"libpython2.7.dll."

Before this patch, hg.exe files in a MinGW environment would
either fail to find a Python DLL or would attempt to load a
non-MinGW DLL, which would summarily explode. Either way,
hg.exe wouldn't work.

This patch improves the code that determines the Python DLL
filename to actually use the loaded Python DLL instead of
inferring it. Basically we take the handle of the loaded DLL
from sys.dllhandle and call a Windows API to try to resolve
that handle to a filename.
This commit is contained in:
Gregory Szorc 2016-04-28 08:52:13 -07:00
parent b30a08bac0
commit ec5e1b8364

View File

@ -57,6 +57,7 @@ else:
ispypy = "PyPy" in sys.version
import ctypes
import os, stat, subprocess, time
import re
import shutil
@ -369,8 +370,34 @@ class buildhgexe(build_ext):
if isinstance(self.compiler, HackedMingw32CCompiler):
self.compiler.compiler_so = self.compiler.compiler # no -mdll
self.compiler.dll_libraries = [] # no -lmsrvc90
hv = sys.hexversion
pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xff)
# Different Python installs can have different Python library
# names. e.g. the official CPython distribution uses pythonXY.dll
# and MinGW uses libpythonX.Y.dll.
_kernel32 = ctypes.windll.kernel32
_kernel32.GetModuleFileNameA.argtypes = [ctypes.c_void_p,
ctypes.c_void_p,
ctypes.c_ulong]
_kernel32.GetModuleFileNameA.restype = ctypes.c_ulong
size = 1000
buf = ctypes.create_string_buffer(size + 1)
filelen = _kernel32.GetModuleFileNameA(sys.dllhandle, ctypes.byref(buf),
size)
if filelen > 0 and filelen != size:
dllbasename = os.path.basename(buf.value)
if not dllbasename.lower().endswith('.dll'):
raise SystemExit('Python DLL does not end with .dll: %s' %
dllbasename)
pythonlib = dllbasename[:-4]
else:
log.warn('could not determine Python DLL filename; '
'assuming pythonXY')
hv = sys.hexversion
pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xff)
log.info('using %s as Python library name' % pythonlib)
with open('mercurial/hgpythonlib.h', 'wb') as f:
f.write('/* this file is autogenerated by setup.py */\n')
f.write('#define HGPYTHONLIB "%s"\n' % pythonlib)