правильный setup.py для смешивания Python и C++

Я пытаюсь смешать оба языка и следую хорошему примеру, предоставленному pybind здесь. Я действительно проверил это post, чтобы улучшить его, чтобы я мог вернуться к функциям Python, когда скомпилированная функция не существует. У меня сейчас проблема в том, что мой configure.py не собирает правильный пакет. Позвольте мне развить: структура моего кода примерно такая:

$ tree .
.
├── AUTHORS.md
├── CMakeLists.txt
├── LICENSE
├── MANIFEST.in
├── Makefile
├── README.md
├── conda.recipe
│   ├── bld.bat
│   └── ...
├── docs
│   ├── Makefile
│   └── ...
├── cmake_example
│   ├── __init__.py
│   ├── __main__.py
│   ├── geometry
│   │   ├── __init__.py
│   │   ├── triangle.py
│   │   └── ...
│   ├── quadrature
│   │   ├── __init__.py
│   │   ├── legendre
│   │   └── ...
│   └── utils
│       ├── __init__.py
│       ├── classes.py
│       └── ...
├── pybind11
│   ├── CMakeLists.txt
│   └── ...
├── setup.py
├── src
│   └── main.cpp
└── tests
    └── test.py

Где я поставил многоточие, чтобы упростить структуру каталогов, но вы можете видеть, что есть несколько модулей. Теперь мой файл setup.py выглядит так

import os
import re
import sys
import platform
import subprocess
import glob

from setuptools import setup, Extension, find_packages
from setuptools.command.build_ext import build_ext
from distutils.version import LooseVersion

class CMakeExtension(Extension):
    def __init__(self, name, sourcedir=''):
        Extension.__init__(self, name, sources=[])
        self.sourcedir = os.path.abspath(sourcedir)    

class CMakeBuild(build_ext):
    def run(self):
        try:
            out = subprocess.check_output(['cmake', '--version'])
        except OSError:
            raise RuntimeError("CMake must be installed to build the following extensions: " +
                               ", ".join(e.name for e in self.extensions))

        if platform.system() == "Windows":
            cmake_version = LooseVersion(re.search(r'version\s*([\d.]+)', out.decode()).group(1))
            if cmake_version < '3.1.0':
                raise RuntimeError("CMake >= 3.1.0 is required on Windows")

        for ext in self.extensions:
            self.build_extension(ext)

    def build_extension(self, ext):
        extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name)))
        cmake_args = ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + extdir,
                      '-DPYTHON_EXECUTABLE=' + sys.executable]

        cfg = 'Debug' if self.debug else 'Release'
        build_args = ['--config', cfg]

        if platform.system() == "Windows":
            cmake_args += ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{}={}'.format(cfg.upper(), extdir)]
            if sys.maxsize > 2**32:
                cmake_args += ['-A', 'x64']
            build_args += ['--', '/m']
        else:
            cmake_args += ['-DCMAKE_BUILD_TYPE=' + cfg]
            build_args += ['--', '-j2']

        env = os.environ.copy()
        env['CXXFLAGS'] = '{} -DVERSION_INFO=\\"{}\\"'.format(env.get('CXXFLAGS', ''),
                                                              self.distribution.get_version())
        if not os.path.exists(self.build_temp):
            os.makedirs(self.build_temp)
        subprocess.check_call(['cmake', ext.sourcedir] + cmake_args, cwd=self.build_temp, env=env)
        subprocess.check_call(['cmake', '--build', '.'] + build_args, cwd=self.build_temp)


kwargs = dict(
    name="cmake_example",
    ext_modules=[CMakeExtension('cmake_example._mymath')],
    cmdclass=dict(build_ext=CMakeBuild),
    zip_safe=False,
    packages='cmake_example',
)

# likely there are more exceptions
try:
    setup(**kwargs)
except subprocess.CalledProcessError:
    print("ERROR: Cannot compile C accelerator module, use pure python version")
    del kwargs['ext_modules']
    setup(**kwargs)

который я взял из этот пост. Когда я пытаюсь собрать колесо с помощью python setup.py bdist_wheel, а затем установить с помощью pip install ., я не могу использовать свой код, потому что он жалуется, что пакеты не найдены:

>>> import cmake_example
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/aaragon/Local/cmake_example/cmake_example/__init__.py", line 11, in <module>
    from .geometry import Triangle
ModuleNotFoundError: No module named 'cmake_example.geometry'

Если я вручную добавлю в setup.py список с packages=['cmake_example', cmake_example.geometry], то это сработает, но я не думаю, что это правильный способ сделать это, потому что было бы очень сложно идти в ногу с добавлением новых модулей. Я где-то видел, что могу заменить эту строку и использовать findpackages в setuptools, но эта функция не добавляет cmake_example перед модулем, поэтому она все равно ломается. Каков правильный способ сделать то, что я пытаюсь сделать?


person aaragon    schedule 11.10.2018    source источник


Ответы (1)


Если я вручную добавлю в setup.py список с packages=['cmake_example', cmake_example.geometry], то это сработает, но я не думаю, что это правильный способ сделать это, потому что было бы очень сложно идти в ногу с добавление новых модулей.

Либо вы делаете это вручную, либо когда становится трудно следить за добавлением новых модулей, есть setuptools.find_packages. Используйте как:

from setuptools import setup, find_packages
setup(
    name="HelloWorld",
    version="0.1",
    packages=find_packages(),
)
person saaj    schedule 11.10.2018