Acest tutorial arată cum să configurați un proiect pybind11 cu CMake pentru a include o bibliotecă C++ în Python.
Rezultatul final va fi:
- Un proiect
C++pe care îl puteți construi independent depybind11. - O bibliotecă
Pythongenerată din împachetarea coduluiC++. - Ambele folosind
CMake.
„Codul pentru proiectul complet îl găsiți aici.”

„Sursa imaginii.”
Cerințe
Evident, obțineți pybind11:
conda install -c conda-forge pybind11
Creați un proiect C++
Vom folosi directorul de lucru exterior (actual) pentru a construi python și un director interior numit cpp pentru a construi codul C++. Mai întâi faceți un director C++.
mkdir cpp cd cpp
În continuare, vom inițializa un proiect C++. Două moduri (din multe altele) sunt:
- Folosind
VS Code. Instalați extensiaCMake Tools. Apoi, deschideți paleta de comenzi și selectațiCMake: Quick start. Urmați instrucțiunile și introduceți un nume — am alesautomobile. Când vi se solicită bibliotecă sau executabil, alegețilibrary. Directorul dvs. ar trebui să arate acum astfel:
cpp/build/ cpp/motorcycle.cpp cpp/CMakeLists.txt
Vom separa fișierele sursă și antet - aceasta este întotdeauna o practică bună. În directorul cpp, creați două directoare noi:
cd cpp mkdir include mkdir src
și mutați fișierul sursă:
mv motorcycle.cpp src/
În directorul include, am dori să avem un singur antet de importat. În acest fel, mai târziu am putea pur și simplu #include <automobile>. O putem organiza astfel:
cd cpp/include mkdir automobile_bits touch automobile
În cele din urmă, să creăm un fișier antet în directorul cpp/include/automobile_bits:
cd cpp/include/automobile_bits touch motorcycle.hpp
Structura finală a directoarelor ar trebui să arate acum astfel:
cpp/build cpp/CMakeLists.txt cpp/include/automobile cpp/include/automobile_bits/motorcycle.hpp cpp/src/motorcycle.cpp
2. Alternativ, creați manual fișierele și directoarele, astfel încât structura finală să fie:
cpp/build cpp/CMakeLists.txt cpp/include/automobile cpp/include/automobile_bits/motorcycle.hpp cpp/src/motorcycle.cpp
Va trebui să edităm CMakeLists.txt curent astfel încât să poată găsi antetul și fișierele sursă. L-am editat pe al meu pentru a citi astfel:
Să dăm și fișierelor motorcycle.hpp și motorcycle.cpp un conținut rezonabil. Pentru antet:
si sursa:
Da! Stiu ca sunt prosti. Rețineți că am introdus un spațiu de nume vehicles - aceasta este întotdeauna o idee bună.
De asemenea, trebuie ca fișierul antet să găsească biblioteca reală. Editați fișierul include/automobile pentru a citi:
Acum putem construi deja biblioteca:
- Folosind linia de comandă:
cd cpp/build cmake .. make make install
2. Folosind IDE-ul tău preferat, de ex. XCode:
cd cpp/build cmake .. -GXcode
ar trebui să genereze automobile.xcodeproject în directorul build.
În orice caz, ar trebui să construiți și să instalați biblioteca.
Testarea bibliotecii C++
Înainte de a trece la împachetarea bibliotecii în Python, haideți să creăm un test pentru biblioteca C++ (nu un test real, doar undeva pentru a ne încurca!).
Creați un director nou în cpp:
cd cpp mkdir tests
Aici vom configura din nou un proiect CMake pentru testul nostru. Faceți ca structura directorului să arate după cum urmează:
cpp/tests/CMakeLists.txt cpp/tests/src/test.cpp
Editați fișierul test.cpp pentru a citi:
și editați fișierul CMakeLists.txt:
Faceți și rulați acel băiat rău folosind XCode ca înainte sau din linia de comandă:
mkdir build cd build cmake .. make cd ../bin ./test
Rețineți că binarul va fi în directorul bin. Ieșirea ar trebui să fie:
Made a motorcycle called: Yamaha Zoom Zoom on road: mullholland
Configurarea wrapper-ului Python
În cele din urmă, să trecem la împachetarea bibliotecii într-un Python. Mutăm într-un director! În directorul principal, să facem un nou director numit python. Va deține tot codul de lipici:
mkdir python
Avem nevoie și de un fișier CMakeLists.txt, cu conținut:
Ar trebui să fiți gata să vă construiți biblioteca Python! Încerca:
mkdir build cd build cmake .. -DPYTHON_LIBRARY_DIR=”/path/to/site-packages” -DPYTHON_EXECUTABLE=”/path/to/executable/python3" make make install
Ca de obicei, puteți genera cod folosind un generator pentru IDE-ul dvs. preferat, de ex. prin adăugarea -GXcode la comanda cmake. Drumurile mele au fost:
DPYTHON_LIBRARY_DIR=”/Users/USERNAME/opt/anaconda3/lib/python3.7/site-packages” DPYTHON_EXECUTABLE=”/Users/USERNAME/opt/anaconda3/bin/python3"
Rețineți că, dacă sunteți leneș ca mine, puteți încerca să adăugați pentru testare:
set(PYTHON_LIBRARY_DIR “/Users/USERNAME/opt/anaconda3/lib/python3.7/site-packages”) set(PYTHON_EXECUTABLE “/Users/USERNAME/opt/anaconda3/bin/python3”)
în CMakeLists.txt dvs. — evident că nu este un truc bun pentru producție!
Porniți python (asigurați-vă că este același cu cel specificat în PYTHON_EXECUTABLE de mai sus) și încercați:
>>> import automobile Traceback (most recent call last): File “<stdin>”, line 1, in <module> ImportError: dynamic module does not define module export function (PyInit_automobile)
Ai o eroare groasă, dar e în regulă! Nu am scris încă codul lipici, dar cel puțin CMake funcționează și Python vă poate găsi biblioteca.
Încheierea bibliotecii în Python
Acum, pentru logica reală a împachetării codului C++ în Python. Va avea loc în directorul python. Mai întâi creați un fișier care va defini „funcția de export de modul” despre care python se plângea în ultima parte:
touch python/automobile.cpp
Dă-i următorul conținut:
În continuare, vom defini metoda init_motorcycle care a fost declarată. Vom face acest lucru într-un fișier separat:
touch python/motorcycle.cpp
Editează-l pentru a citi:
Întotdeauna cred că codul în sine este cea mai bună explicație, dar câteva indicații:
”Motorcycle”definește numele clasei înPython— îl puteți schimba dacă doriți! Observați și aspectul spațiului de nume..def(py::init<std::string>(), py::arg(“name”))definește constructorul.py::arg(“name”)vă permite să utilizați argumente numite înPython..def(“get_name”, py::overload_cast<>( &vehicles::Motorcycle::get_name, py::const_))include metodaget_name. Observați cum este împachetat declarațiaconst..def(“ride”, py::overload_cast<std::string>( &vehicles::Motorcycle::ride, py::const_), py::arg(“road”));include metodaride. Argumentele metodei sunt declarate înpy::overload_cast<std::string>(separate prin virgule dacă sunt multiple) și pot fi denumite din nou folosindpy::arg(“road”). De asemenea, notați punctul și virgulă de la sfârșit - adesea uitat, dar acesta ar trebui să fie codulC++adecvat.
Acum vă puteți testa biblioteca. Rulați din nou make și make install pentru a reconstrui și a instala biblioteca.
Porniți python și încercați:
ar trebui să dea aceeași ieșire ca înainte:
Made a motorcycle called: Yamaha Zoom Zoom on road: mullholland
Ai putea face un alt script de testare cu acel conținut, situat într-un director tests/test.py.
Concluzie
Asta e pentru acest tutorial. „Codul complet îl găsiți aici.”
Partea plăcută a acestei configurații este că vă puteți construi proiectul C++ în liniște din directorul cpp, iar apoi, la sfârșit, în stratul exterior vă faceți griji că îl includeți în Python.
„Puteți citi despre mai multe funcții avansate pybind11 într-un alt tutorial pe care l-am scris aici.”
Multumesc pentru lectura!