Najprostsze rozwiązanie ma nic zrób z pybind11 jako takie. To, co zwykle robią autorzy, gdy chcą łączyć czyste rozszerzenia Python i C/Cython/inne natywne w tym samym pakiecie, jest następujące.
Tworzysz dwa moduły.
mymodule
to interfejs publiczny, czysta moduł Pythona
_mymodule
jest prywatnym implementacji, spełnione moduł
Następnie w mymodule
importować niezbędne symbole z _mymoudle
(i awaryjne do czystej wersji Pythona Jeśli to konieczne).
Oto przykład z yarl opakowania:
quoting.py
try:
from ._quoting import _quote, _unquote
quote = _quote
unquote = _unquote
except ImportError: # pragma: no cover
quote = _py_quote
unquote = _py_unquote
_quoting.pyx
Aktualizacji
Oto skrypt. Ze względu na powtarzalność robię to przeciwko oryginałowi cmake_example.
git clone --recursive https://github.com/pybind/cmake_example.git
# at the time of writing https://github.com/pybind/cmake_example/commit/8818f493
cd cmake_example
Teraz stwórz czyste moduły Pythona (wewnątrz cmake_example/cmake_example
).
cmake_example/__init__.py
"""Root module of your package"""
cmake_example/math.py
def mul(a, b):
"""Pure Python-only function"""
return a * b
def add(a, b):
"""Fallback function"""
return a + b
try:
from ._math import add
except ImportError:
pass
Teraz zmodyfikować istniejące pliki, aby włączyć moduł cmake_example
w cmake_example._math
.
src/main.cpp
(subtract
usunięte dla zwięzłość)
#include <pybind11/pybind11.h>
int add(int i, int j) {
return i + j;
}
namespace py = pybind11;
PYBIND11_MODULE(_math, m) {
m.doc() = R"pbdoc(
Pybind11 example plugin
-----------------------
.. currentmodule:: _math
.. autosummary::
:toctree: _generate
add
)pbdoc";
m.def("add", &add, R"pbdoc(
Add two numbers
Some other explanation about the add function.
)pbdoc");
#ifdef VERSION_INFO
m.attr("__version__") = VERSION_INFO;
#else
m.attr("__version__") = "dev";
#endif
}
CMakeLists.txt
cmake_minimum_required(VERSION 2.8.12)
project(cmake_example)
add_subdirectory(pybind11)
pybind11_add_module(_math src/main.cpp)
setup.py
# the above stays intact
from subprocess import CalledProcessError
kwargs = dict(
name='cmake_example',
version='0.0.1',
author='Dean Moldovan',
author_email='[email protected]',
description='A test project using pybind11 and CMake',
long_description='',
ext_modules=[CMakeExtension('cmake_example._math')],
cmdclass=dict(build_ext=CMakeBuild),
zip_safe=False,
packages=['cmake_example']
)
# likely there are more exceptions, take a look at yarl example
try:
setup(**kwargs)
except CalledProcessError:
print('Failed to build extension!')
del kwargs['ext_modules']
setup(**kwargs)
Teraz możemy go zbudować.
python setup.py bdist_wheel
W moim przypadku to produkuje dist/cmake_example-0.0.1-cp27-cp27mu-linux_x86_64.whl
(jeśli C++ kompilacja nie jest cmake_example-0.0.1-py2-none-any.whl
). Oto, co jej treść (unzip -l ...
):
Archive: cmake_example-0.0.1-cp27-cp27mu-linux_x86_64.whl
Length Date Time Name
--------- ---------- ----- ----
0 2017-12-05 21:42 cmake_example/__init__.py
81088 2017-12-05 21:43 cmake_example/_math.so
223 2017-12-05 21:46 cmake_example/math.py
10 2017-12-05 21:48 cmake_example-0.0.1.dist-info/DESCRIPTION.rst
343 2017-12-05 21:48 cmake_example-0.0.1.dist-info/metadata.json
14 2017-12-05 21:48 cmake_example-0.0.1.dist-info/top_level.txt
105 2017-12-05 21:48 cmake_example-0.0.1.dist-info/WHEEL
226 2017-12-05 21:48 cmake_example-0.0.1.dist-info/METADATA
766 2017-12-05 21:48 cmake_example-0.0.1.dist-info/RECORD
--------- -------
82775 9 files
dziękuję, jest to bardzo przydatna sugestia. Nie jestem wystarczająco biegły w pythonie i jego pakiecie narzędzi do pakowania, aby wdrożyć proponowane rozwiązanie na własną rękę, nawet w przypadku tego prostego przykładu umieszczam na githubie.czy byłbyś w stanie mi pomóc, kształtując go tak, aby miał "mult" w języku C++ i awarię w pytonie, jak zasugerowałeś? więc mogę go wykorzystać jako punkt wyjścia do budowy i dystrybucji mojego własnego pakietu? Dziękuję Ci! – seninp
@seninp Spójrz. – saaj
Bardzo podoba mi się sposób, w jaki to działa, zachowując separację między źródłami C++ i Python oraz możliwość testowania/używania tych niezależnie. Również buduje i testuje seamlesly na Travis i codecov jest w stanie wyciągnąć wskaźniki zasięgu. Przyjmowanie odpowiedzi - jeszcze raz dziękuję! – seninp