(Решено) Импорт скомпилированного модуля Pybind11 / C ++ не работает - PullRequest
1 голос
/ 21 июня 2019

Я довольно плохо знаком с python setuptools и dist.Кажется, я не могу получить модуль оболочки c ++ для импорта, чтобы я мог использовать функции.

Скомпилированный файл .so появляется в файле instal-files.txt после установки pip, но импорт оболочки делаетне.

setup.py

import subprocess
import os
from pathlib import Path

from setuptools import setup, Extension, find_packages
from setuptools.command.build_ext import build_ext


class CMakeExtension(Extension):
    def __init__(self, name):
        Extension.__init__(self, name, sources=[])


class CMakeBuild(build_ext):
    def run(self):
        for ext in self.extensions:
            self.build_cmake(ext)
        super().run()

    def build_cmake(self, ext):
        try:
            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)
            )

        cwd = 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 = Path(self.build_temp)
        build_temp.mkdir(parents=True, exist_ok=True)
        extdir = Path(self.get_ext_fullpath(ext.name))
        extdir.mkdir(parents=True, exist_ok=True)

        pyenv_root = os.environ.get("PYENV_ROOT")

        cmake_args = [
            f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={extdir}",
            "-DCMAKE_BUILD_TYPE=Release",
            "-DTRANSIT_INCLUDE_TESTS:BOOL=OFF",
        ]

        if pyenv_root is not None:
            cmake_args += [f"-DPYTHON_EXECUTABLE={pyenv_root}/shims/python"]

        build_args = ["--config", "Release", "--", "-j2"]

        env = os.environ.copy()

        self.announce("Running CMake prepare", level=3)
        subprocess.check_call(["cmake", cwd] + cmake_args, cwd=build_temp, env=env)

        self.announce("Building extensions")
        cmake_cmd = ["cmake", "--build", "."] + build_args
        subprocess.check_call(cmake_cmd, cwd=build_temp)


setup(
    name="bgtfs_py_lib",
    version="3.2.2",
    long_description="",
    zip_safe=False,
    install_requires=[
        "redis==2.10.6",
        "cffi==1.11.5",
        "numpy==1.15.3",
        "patricia-trie==10",
        "PuLP==1.6.8",
        "py-lz4framed==0.13.0",
        "pycparser==2.19",
        "pyparsing==2.2.2",
        "pypng==0.0.18",
        "pyproj==1.9.5.1",
        "python-graph-core==1.8.2",
        "pytz==2018.6",
        "redis==2.10.6",
        "requests==2.21.0",
        "six==1.11.0",
        "tabulate==0.8.2",
        "unicodecsv==0.14.1",
        "Unidecode==1.0.22",
    ],
    ext_modules=[CMakeExtension("bgtfs_py_lib.bgtfs_py_lib_wrapper")],
    cmdclass=dict(build_ext=CMakeBuild),
    packages=find_packages(exclude=["tests"]),
    package_data={"": "*.so"},
)

CMakeLists.txt

cmake_minimum_required(VERSION 3.8)

project(bgtfs_py_lib_wrapper)
include(submodules/transitLib/bgtfs/bgtfsLib/TransitUtils/transit_shared.cmake)

# bgtfsPyLib
set(PYBIND11_CPP_STANDARD -std=c++14)
set(PYBIND11_PYTHON_VERSION 3.6)

add_subdirectory(submodules/transitLib transitLib)
add_subdirectory(pybind11)

include_directories(
    cpp
    submodules/transitLib/bgtfs/bgtfsLib/
    submodules/transitLib/bgtfs/bgtfsLib/bgtfsLib
)

pybind11_add_module(bgtfs_py_lib_wrapper MODULE NO_EXTRAS
    cpp/pybindCasts.cpp
    cpp/bgtfsPyLibWrapper.cpp
    cpp/BgtfsFeedHandler.cpp
)

target_link_libraries(bgtfs_py_lib_wrapper PRIVATE transitLib)
set_target_properties(bgtfs_py_lib_wrapper PROPERTIES
    LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/bgtfs_py_lib
    LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_LIST_DIR}/bgtfs_py_lib
    LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_LIST_DIR}/bgtfs_py_lib
)
target_compile_definitions(bgtfs_py_lib_wrapper PRIVATE TRANSIT_SERVER)
target_compile_definitions(transitLib PRIVATE TRANSIT_SERVER)
target_compile_definitions(bgtfsLib PRIVATE ENABLE_BACKWARD_FILE_COMPATIBILITY YES)
set_default_target_properties(bgtfs_py_lib_wrapper)

Я пытаюсь использовать virtualenvчтобы выделить модули, необходимые для запуска в моем проекте.

Вот структура файла:

.
|-- CMakeLists.txt
|-- README.md
|-- bgtfs_py_lib
|   |-- __init__.py
|   |-- bgtfs_handler
|-- cpp
|   |-- BgtfsFeedHandler.cpp
|   |-- BgtfsFeedHandler.h
|   |-- bgtfsPyLibWrapper.cpp
|   `-- pybindCasts.cpp
|-- deploy.sh
|-- make.sh
|-- pybind11
|-- setup.py
|-- submodules
|-- test.sh
`-- tests
    |-- __init__.py
    |-- __pycache__
    |-- fixtures
    |-- test.py
    `-- test_functions.py

Файл init .py в bgtfs_py_lib выглядит следующим образом,Функции обёртки раскрываются.

import bgtfs_py_lib_wrapper as _bgtfs_py_lib
from bgtfs_py_lib.bgtfs_handler.bgtfs_handler import BgtfsHandler

В другом проекте это pip-установка с использованием git + ssh и egg.

git + ssh: //git@github.com/path/to/project.git@build/production/setup#egg=bgtfs_py_lib

Когда я ctrl + space в pyCharm модуль-обертка найден и классы присутствуют.
Модуль находится в каталоге Binary Skeletons, но пока

import bgtfs_py_lib_wrapper as _bgtfs_py_lib просто не работает, и выдается следующее исключение: ModuleNotFoundError: No module named 'bgtfs_py_lib_wrapper'

Может кто-нибудь помочь мне разобраться, как правильно собирать модули C ++ / Pybind11 и использовать их в установленном pip-пакете с virtualenv?

1 Ответ

1 голос
/ 02 июля 2019

Я наконец-то решил это

Оказывается, что файл CMakeLists.txt нужно было изменить, потому что между cmake_args и build_args были несоответствия. Таким образом, файл CMakeList.txt теперь выглядит следующим образом:

CMakeLists.txt

cmake_minimum_required(VERSION 3.8)

project(bgtfs_py_lib_wrapper)
include(submodules/transitLib/bgtfs/bgtfsLib/TransitUtils/transit_shared.cmake)

# bgtfsPyLib
set(PYBIND11_CPP_STANDARD -std=c++14)
set(PYBIND11_PYTHON_VERSION 3.6)

add_subdirectory(submodules/transitLib transitLib)
add_subdirectory(pybind11)

include_directories(
    cpp
    submodules/transitLib/bgtfs/bgtfsLib/
    submodules/transitLib/bgtfs/bgtfsLib/bgtfsLib
)

pybind11_add_module(bgtfs_py_lib_wrapper MODULE NO_EXTRAS
    cpp/pybindCasts.cpp
    cpp/bgtfsPyLibWrapper.cpp
    cpp/BgtfsFeedHandler.cpp
)

target_link_libraries(bgtfs_py_lib_wrapper PRIVATE transitLib)
target_compile_definitions(bgtfs_py_lib_wrapper PRIVATE TRANSIT_SERVER)
target_compile_definitions(transitLib PRIVATE TRANSIT_SERVER)
target_compile_definitions(bgtfsLib PRIVATE ENABLE_BACKWARD_FILE_COMPATIBILITY YES)
set_default_target_properties(bgtfs_py_lib_wrapper)

и файл setup.py теперь:

setup.py

import subprocess
import os
from pathlib import Path

from setuptools import setup, Extension, find_packages
from setuptools.command.build_ext import build_ext


class CMakeExtension(Extension):
    def __init__(self, name):
        Extension.__init__(self, name, sources=[])


class CMakeBuild(build_ext):
    def run(self):
        for ext in self.extensions:
            self.build_cmake(ext)
        super().run()

    def build_cmake(self, ext):
        try:
            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)
            )

        cwd = 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
        if not os.path.exists(self.build_temp):
            os.makedirs(self.build_temp)
        extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name)))

        pyenv_root = os.environ.get("PYENV_ROOT")

        cmake_args = [
            f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={extdir}",
            "-DCMAKE_BUILD_TYPE=Release",
            "-DTRANSIT_INCLUDE_TESTS:BOOL=OFF",
        ]

        if pyenv_root is not None:
            cmake_args += [f"-DPYTHON_EXECUTABLE={pyenv_root}/shims/python"]

        build_args = ["--config", "Release", "--", "-j2"]

        env = os.environ.copy()

        self.announce("Running CMake prepare", level=3)
        subprocess.check_call(["cmake", cwd] + cmake_args, cwd=self.build_temp, env=env)

        self.announce("Building extensions")
        cmake_cmd = ["cmake", "--build", "."] + build_args
        subprocess.check_call(cmake_cmd, cwd=self.build_temp)


setup(
    name="bgtfs_py_lib",
    version="3.2.2",
    author="Transit App",
    author_email="juan@transitapp.com",
    description="A python wrapper for the transitLib",
    long_description="",
    zip_safe=False,
    license="Transit",
    install_requires=[
        "bgtfs_py_lib",
        "redis==2.10.6",
        "cffi==1.11.5",
        "numpy==1.15.3",
        "patricia-trie==10",
        "PuLP==1.6.8",
        "py-lz4framed==0.13.0",
        "pycparser==2.19",
        "pyparsing==2.2.2",
        "pypng==0.0.18",
        "pyproj==1.9.5.1",
        "python-graph-core==1.8.2",
        "pytz==2018.6",
        "redis==2.10.6",
        "requests==2.21.0",
        "six==1.11.0",
        "tabulate==0.8.2",
        "unicodecsv==0.14.1",
        "Unidecode==1.0.22",
    ],
    ext_modules=[CMakeExtension("bgtfs_py_lib_wrapper")],
    cmdclass=dict(build_ext=CMakeBuild),
    packages=find_packages(exclude=["tests", "*.plist"]),
    package_data={"": "*.so"},
)

Файл расширения не должен был выводиться в каталог bgtfs_py_lib, а скорее в виртуальную среду, а сам проект требовался

Привет Сергей за помощь в разгадке

...