правильный setup.py для смешивания Python и C ++ - PullRequest
0 голосов
/ 11 октября 2018

Я пытаюсь смешать оба языка и следую хорошему примеру, представленному pybind здесь .Я действительно проверил этот пост , чтобы улучшить его, чтобы я мог вернуться к функциям 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 к модулю, поэтому он все еще ломается.Как правильно делать то, что я пытаюсь сделать?

1 Ответ

0 голосов
/ 11 октября 2018

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

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

from setuptools import setup, find_packages
setup(
    name="HelloWorld",
    version="0.1",
    packages=find_packages(),
)
...