Die einfachste Lösung hat nichts zu tun mit pybind11 als solche. Was Autoren normalerweise tun, wenn sie reine Python und C/Cython/andere native Erweiterungen im selben Paket kombinieren wollen, ist folgendes.
Sie erstellen zwei Module.
mymodule
ist eine öffentliche Schnittstelle, eine reine Python-Modul
_mymodule
eine private Implementierung ist ein erfüllter Modul
Dann in mymodule
Sie notwendige Symbole aus _mymoudle
(und Rückgriff auf reine Python-Version importieren Falls benötigt).
Hier Beispiel aus yarl Paket:
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
aktualisieren
Hier folgt das Skript. Aus Gründen der Reproduzierbarkeit tue ich es gegen Original 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
Jetzt reine Python-Module erstellen (innen 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
Lassen Sie uns jetzt vorhandene Dateien modifizieren cmake_example
Modul in cmake_example._math
einzuschalten.
src/main.cpp
(subtract
der Kürze entfernt)
#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)
Jetzt können wir es bauen.
python setup.py bdist_wheel
In meinem Fall erzeugt es dist/cmake_example-0.0.1-cp27-cp27mu-linux_x86_64.whl
(wenn C++ Kompilation es ist cmake_example-0.0.1-py2-none-any.whl
ausfällt). Hier ist, was es Inhalt (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
danke, das ist ein sehr nützlicher Vorschlag. ich bin in python und seinem packaging toolkit nicht kompetent genug, die vorgeschlagene lösung alleine zu implementieren, selbst für dieses einfache beispiel, das ich auf den github gesetzt habe.Könntest du mir helfen, indem du es formulierst, um das "Mult" in C++ und ein Fallback in Python zu haben, wie du es vorgeschlagen hast? also kann ich es als Ausgangspunkt für den Aufbau und die Verteilung meines eigenen Pakets verwenden? Danke! – seninp
@seninp Werfen Sie einen Blick darauf. – saaj
Ich mag die Funktionsweise von C++ - und Python-Quellen und die Möglichkeit, diese unabhängig voneinander zu testen und zu verwenden. Außerdem erstellt und testet es nahtlos auf Travis und Codecov kann die Coverage-Metriken abrufen. Die Antwort annehmen - Danke nochmal! – seninp