Скомпилируйте модуль python pybind11, который работает в большинстве версий ОС Windows

#c #python-3.x #visual-studio #pybind11

#c #python-3.x #visual-studio #pybind11

Вопрос:

У меня есть модуль C , который я успешно предоставил python с помощью Pybind11.

Проблема в том, что я компилирую его под Windows 10 с помощью VS2019, и я хотел бы, чтобы модуль работал с Windows 7.

К сожалению, при установке модуля в том же чистом дистрибутиве python на компьютерах с Windows 7 я получаю ImportError: DLL load failed сообщение об ошибке.

Когда я повторяю процедуру в Windows 10, все идет так, как ожидалось. Поэтому я полагаю, что это связано с каким-то параметром VS, чтобы сделать dll ретро-совместимой или что-то в этом роде.

Мой setup.py файл такой:

 import os
import re
import pathlib
import numpy
import sys
from sysconfig import get_paths
from setuptools import setup, Extension
from setuptools.command.build_ext import build_ext as build_ext_orig


class CMakeExtension(Extension):

    def __init__(self, name):
        # don't invoke the original build_ext for this special extension
        super().__init__(name, sources=[])


class build_ext(build_ext_orig):

    def run(self):

        # Add numpy headers to include_dirs
        # self.include_dirs.append(numpy.get_include())

        for ext in self.extensions:
            # ext.include_dirs.insert(0, numpy.get_include())
            self.build_cmake(ext)

        super().run()

    def build_cmake(self, ext):

        # add the numpy include folder of associated to the numpy installed in the python executing this script
        ext.include_dirs.insert(0, numpy.get_include())

        cwd = pathlib.Path().absolute()
        # these dirs will be created in build_py, so if you don't have
        # any python sources to bundle, the dirs will be missing
        build_temp = pathlib.Path(self.build_temp)
        build_temp.mkdir(parents=True, exist_ok=True)
        # extdir = pathlib.Path(self.get_ext_fullpath(ext.name))
        extdir = pathlib.Path(pathlib.PurePath(self.get_ext_fullpath(ext.name)).with_suffix(''))
        extdir.mkdir(parents=True, exist_ok=True)

        # example of cmake args
        config = 'Debug' if self.debug else 'Release'
        path_info = get_paths()
        cmake_args = [
            '-DCMAKE_LIBRARY_OUTPUT_DIRECTORY='   str(extdir.parent.absolute()),  # LIBRARY_OUTPUT_DIRECTORY
            '-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE='   str(extdir.parent.absolute()),  # LIBRARY_OUTPUT_DIRECTORY
            '-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG='   str(extdir.parent.absolute()),  # LIBRARY_OUTPUT_DIRECTORY
            '-DWITH_PYTHON_MODULE=ON',
            '-DCMAKE_BUILD_TYPE='   config,
            # python executable path of the python that executes this script
            '-DPYTHON_EXECUTABLE='   sys.executable,
            # path to the python include folder of the python that executes this script
            '-DPYTHON_LIBRARY='   path_info['include'],
            # properly pass the numpy include (works under windows too)
            '-DPython_NumPy_FOUND=True',
            '-DPython_NumPy_INCLUDE_DIRS='   numpy.get_include()
        ]

        # example of build args
        build_args = [
            '--config', config,
            '--target', 'NewtonNative'
        ]

        # We can handle some platform-specific settings at our discretion
        if os.name == 'nt':
            cmake_args  = [
                # These options are likely to be needed under Windows
                '-DCMAKE_WINDOWS_EXPORT_ALL_SYMBOLS=TRUE',
                '-DCMAKE_RUNTIME_OUTPUT_DIRECTORY_{}={}'.format(config.upper(), extdir),
                # python executable path of the python that executes this script
                # '-DPYTHON_EXECUTABLE='   sys.executable,
                # path to the python include folder of the python that executes this script
                # '-DPYTHON_LIBRARY='   path_info['include'],
            ]

        os.chdir(str(build_temp))
        self.spawn(['cmake', str(cwd)]   cmake_args)
        if not self.dry_run:
            self.spawn(['cmake', '--build', '.']   build_args)
        # Troubleshooting: if fail on line above then delete all possible
        # temporary CMake files including "CMakeCache.txt" in top level dir.
        os.chdir(str(cwd))


def read_version(fname):
    """
    Read the version from the CMake file
    :param fname: file name
    :return: version string
    """
    version = "0.1.0"  # set a default version
    with open(fname) as file:
        for l in file:
            if 'NewtonNative' in l and 'VERSION' in l:
                version = re.search('"(.*)"', l).group(1)
                return version
    return version


__version__ = read_version(os.path.join('src', 'CMakeLists.txt'))

setup(name='NewtonNative',
      version=__version__,
      author='',
      author_email='',
      url='',
      description='',
      long_description='',
      ext_modules=[CMakeExtension('NewtonNative')],
      cmdclass={'build_ext': build_ext},
      install_requires=['pybind11>=2.4'],
      setup_requires=['pybind11>=2.4'],
      include_dirs=[numpy.get_include()],
      zip_safe=False)
  

Как я могу скомпилировать для нескольких версий Windows?

Я думаю, это должно быть возможно, поскольку numpy и другим расширениям удается иметь одну версию для всех ОС Windows и зависеть только от версии python.