diff --git a/PyInstaller/hooks/hook-distutils.py b/PyInstaller/hooks/hook-distutils.py index 61f779be2f5..3e65078d283 100644 --- a/PyInstaller/hooks/hook-distutils.py +++ b/PyInstaller/hooks/hook-distutils.py @@ -1,4 +1,4 @@ -#----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- # Copyright (c) 2005-2020, PyInstaller Development Team. # # Distributed under the terms of the GNU General Public License (version 2 @@ -7,7 +7,7 @@ # The full license is in the file COPYING.txt, distributed with this software. # # SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) -#----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- """ `distutils`-specific post-import hook. @@ -17,19 +17,59 @@ runtime for platform-specific metadata. """ -# TODO Verify that bundling Makefile and pyconfig.h is still required for Python 3. +from distutils import sysconfig +import sys +from os import path +from pathlib import Path -import os -import sysconfig +from PyInstaller.utils.hooks import logger -from PyInstaller.utils.hooks import relpath_to_config_or_make +if sys.version_info < (3, 6): + # XXX: Pythons >= 3.6 no longer use these files. Once we drop 3.5 support + # we can delete this. -_CONFIG_H = sysconfig.get_config_h_filename() -_MAKEFILE = sysconfig.get_makefile_filename() + datas = [] -# Data files in PyInstaller hook format. -datas = [(_CONFIG_H, relpath_to_config_or_make(_CONFIG_H))] + # Locate the ``Include`` folder containing the two files. + include_src = sysconfig.get_python_inc() + # Get a dist target location. This seems to handle venv and its many + # variants better than our own attempts involving ``sys.prefix``. See + # https://github.com/pyinstaller/pyinstaller/issues/4775. + include_dest = sysconfig.get_python_inc(prefix=".") -# The Makefile does not exist on all platforms, eg. on Windows -if os.path.exists(_MAKEFILE): - datas.append((_MAKEFILE, relpath_to_config_or_make(_MAKEFILE))) + makefile_src = path.join(include_src, "pyconfig.h") + if path.exists(makefile_src): + datas.append((makefile_src, include_dest)) + logger.debug("Add pyconfig.h from '{}' to '{}'." + .format(include_src, include_dest)) + else: + logger.debug("Skip non-existent pyconfig.h from '{}'." + .format(include_src)) + + # The above works well for pyconfig.h. But there is no equivalent function + # for makefile which has the ``prefix="."`` option. Work out which prefix + # the above used: + prefix = path.join( + *Path(include_src).parts[: -len(Path(include_dest).parts)] + ) + + makefile_src = sysconfig.get_makefile_filename() + if path.exists(makefile_src): + makefile_dest = path.dirname(path.relpath(makefile_src, prefix)) + datas.append((makefile_src, makefile_dest)) + logger.debug("Add Makefile from '{}' to '{}'." + .format(makefile_src, makefile_dest)) + else: + logger.debug("Skip non-existent Makefile from '{}'." + .format(makefile_src)) + + +else: + # In Python 3.6 and later ``distutils.sysconfig`` takes on the same + # behaviour as regular ``sysconfig`` of moving the config vars to an + # extension module (see hook-sysconfig.py). But it doesn't use a nice + # `get extension module name` function like ``sysconfig`` does. However the + # extension module is the same file that ``sysconfig`` uses so if we run + # the hook for ``sysconfig``, the extension module will be located and + # included. + hiddenimports = ["sysconfig"] diff --git a/news/5218.hooks.rst b/news/5218.hooks.rst new file mode 100644 index 00000000000..3475765e86c --- /dev/null +++ b/news/5218.hooks.rst @@ -0,0 +1 @@ +Update hook for ``distutils.sysconfig`` to be compatible with pyenv-virtualenv.