Wywoływanie C / C ++ z Python?


521

Jaki byłby najszybszy sposób na zbudowanie powiązania Pythona z biblioteką C lub C ++?

(Używam Windows, jeśli to ma znaczenie).

Odpowiedzi:


170

Powinieneś spojrzeć na Boost.Python . Oto krótkie wprowadzenie z ich strony internetowej:

Biblioteka Boost Python jest strukturą dla interfejsów Python i C ++. Pozwala szybko i bezproblemowo udostępniać funkcje i obiekty klas C ++ w Pythonie i odwrotnie, bez użycia specjalnych narzędzi - tylko kompilatora C ++. Został zaprojektowany do nieinwazyjnego pakowania interfejsów C ++, dzięki czemu nie trzeba wcale zmieniać kodu C ++, aby go zawinąć, dzięki czemu Boost.Python jest idealny do udostępniania bibliotek innych firm w Pythonie. Zastosowanie przez bibliotekę zaawansowanych technik metaprogramowania upraszcza składnię dla użytkowników, dzięki czemu zawijanie kodu przypomina wygląd deklaratywnego języka definicji interfejsu (IDL).


Boost.Python jest jedną z bardziej przyjaznych dla użytkownika bibliotek w Boost, dla prostego interfejsu API wywoływania funkcji jest dość prosty i zapewnia szablon, który musisz napisać sam. Jest to nieco bardziej skomplikowane, jeśli chcesz udostępnić obiektowy interfejs API.
— jwfearn

15
Boost.Python to najgorsza rzecz, jaką można sobie wyobrazić. W przypadku każdej nowej maszyny i każdej aktualizacji wiąże się to z problemami z łączeniem.
— młynarz

14
Prawie 11 lat później czas na kontemplację jakości tej odpowiedzi?
— J Evans

4
Czy to wciąż najlepsze podejście do interfejsu python i c ++?
— tushaR

8
Może możesz wypróbować pybind11, który jest lekki w porównaniu do boosta .
— jdhao,

659

Moduł ctypes jest częścią standardowej biblioteki, a zatem jest bardziej stabilny i szeroko dostępny niż swig , co zawsze sprawiało mi problemy .

W przypadku ctypes musisz spełnić każdą zależność czasową kompilacji od Pythona, a twoje wiązanie będzie działać na każdym pythonie, który ma ctypy, a nie tylko na tym, z którym został skompilowany.

Załóżmy, że masz prostą przykładową klasę C ++, z którą chcesz rozmawiać w pliku o nazwie foo.cpp:

#include <iostream>

class Foo{
    public:
        void bar(){
            std::cout << "Hello" << std::endl;
        }
};

Ponieważ ctypy mogą rozmawiać tylko z funkcjami języka C, musisz podać te, które deklarują je jako zewnętrzne „C”

extern "C" {
    Foo* Foo_new(){ return new Foo(); }
    void Foo_bar(Foo* foo){ foo->bar(); }
}

Następnie musisz skompilować to do biblioteki współdzielonej

g++ -c -fPIC foo.cpp -o foo.o
g++ -shared -Wl,-soname,libfoo.so -o libfoo.so  foo.o

I na koniec musisz napisać swoje opakowanie Pythona (np. W fooWrapper.py)

from ctypes import cdll
lib = cdll.LoadLibrary('./libfoo.so')

class Foo(object):
    def __init__(self):
        self.obj = lib.Foo_new()

    def bar(self):
        lib.Foo_bar(self.obj)

Gdy już to zrobisz, możesz to tak nazwać

f = Foo()
f.bar() #and you will see "Hello" on the screen

14
To jest prawie to, co boost.python robi dla Ciebie w jednym wywołaniu funkcji.
— Martin Beckett,

203
ctypes znajduje się w standardowej bibliotece Pythona, swig i boost nie. Swig i boost polegają na modułach rozszerzeń i dlatego są powiązane z mniejszymi wersjami Pythona, które nie są niezależnymi obiektami współdzielonymi. budowanie owijki swig lub boost może być uciążliwe, ctypy nie wymagają żadnych wymagań.
— Florian Bösch,

25
boost opiera się na magii szablonu voodoo i całkowicie niestandardowym systemie kompilacji, ctypes polega na prostocie. ctypes jest dynamiczny, boost jest statyczny. ctypy mogą obsługiwać różne wersje bibliotek. Boost nie może.
— Florian Bösch,

32
W systemie Windows musiałem podać __declspec (dllexport) w moich podpisach funkcji, aby Python mógł je zobaczyć. Z powyższego przykładu odpowiadałoby to: extern "C" { __declspec(dllexport) Foo* Foo_new(){ return new Foo(); } __declspec(dllexport) void Foo_bar(Foo* foo){ foo->bar(); } }
— Alan Macdonald

13
Nie zapomnij usunąć wskaźnika później, np. Udostępniając Foo_deletefunkcję i wywołując ją albo z destruktora Pythona, albo zawijając obiekt w zasobie .
— Adversus

58

Najszybszym sposobem na to jest użycie SWIG .

Przykład z samouczka SWIG :

/* File : example.c */
int fact(int n) {
    if (n <= 1) return 1;
    else return n*fact(n-1);
}

Plik interfejsu:

/* example.i */
%module example
%{
/* Put header files here or function declarations like below */
extern int fact(int n);
%}

extern int fact(int n);

Budowanie modułu Python na Uniksie:

swig -python example.i
gcc -fPIC -c example.c example_wrap.c -I/usr/local/include/python2.7
gcc -shared example.o example_wrap.o -o _example.so

Stosowanie:

>>> import example
>>> example.fact(5)
120

Zauważ, że musisz mieć python-dev. Również w niektórych systemach pliki nagłówkowe Pythona będą w /usr/include/python2.7 w zależności od sposobu zainstalowania.

Z samouczka:

SWIG to dość kompletny kompilator C ++ z obsługą prawie wszystkich funkcji językowych. Obejmuje to przetwarzanie wstępne, wskaźniki, klasy, dziedziczenie, a nawet szablony C ++. SWIG może być również używany do pakowania struktur i klas w klasy proxy w języku docelowym - odsłaniając podstawową funkcjonalność w bardzo naturalny sposób.


50

Swoją podróż rozpocząłem w powiązaniu Pythona <-> C ++ z tej strony, mając na celu połączenie typów danych wysokiego poziomu (wielowymiarowe wektory STL z listami Pythona) :-)

Po wypróbowaniu rozwiązań opartych na obu typach i boost.python (i nie będąc inżynierem oprogramowania) Znalazłem je złożone typy danych, gdy wymagany jest wysoki poziom wiązania, natomiast znalazłem haust znacznie prostsze dla takich przypadków.

W tym przykładzie użyto zatem SWIG i został on przetestowany w systemie Linux (ale SWIG jest dostępny i jest również powszechnie używany w systemie Windows).

Celem jest udostępnienie Pythonowi funkcji C ++, która przyjmuje macierz w postaci wektora 2D STL i zwraca średnią każdego wiersza (jako wektor 1D STL).

Kod w C ++ („code.cpp”) jest następujący:

#include <vector>
#include "code.h"

using namespace std;

vector<double> average (vector< vector<double> > i_matrix) {

  // Compute average of each row..
  vector <double> averages;
  for (int r = 0; r < i_matrix.size(); r++){
    double rsum = 0.0;
    double ncols= i_matrix[r].size();
    for (int c = 0; c< i_matrix[r].size(); c++){
      rsum += i_matrix[r][c];
    }
    averages.push_back(rsum/ncols);
  }
  return averages;
}

Odpowiednik nagłówka („code.h”) to:

#ifndef _code
#define _code

#include <vector>

std::vector<double> average (std::vector< std::vector<double> > i_matrix);

#endif

Najpierw kompilujemy kod C ++, aby utworzyć plik obiektowy:

g++ -c -fPIC code.cpp

Następnie definiujemy plik definicji interfejsu SWIG („code.i”) dla naszych funkcji C ++.

%module code
%{
#include "code.h"
%}
%include "std_vector.i"
namespace std {

  /* On a side note, the names VecDouble and VecVecdouble can be changed, but the order of first the inner vector matters! */
  %template(VecDouble) vector<double>;
  %template(VecVecdouble) vector< vector<double> >;
}

%include "code.h"

Za pomocą SWIG generujemy kod źródłowy interfejsu C ++ z pliku definicji interfejsu SWIG.

swig -c++ -python code.i

W końcu kompilujemy wygenerowany plik źródłowy interfejsu C ++ i łączymy wszystko razem, aby wygenerować bibliotekę współdzieloną, którą można bezpośrednio importować przez Python (ważne jest „_”):

g++ -c -fPIC code_wrap.cxx  -I/usr/include/python2.7 -I/usr/lib/python2.7
g++ -shared -Wl,-soname,_code.so -o _code.so code.o code_wrap.o

Możemy teraz używać tej funkcji w skryptach Python:

#!/usr/bin/env python

import code
a= [[3,5,7],[8,10,12]]
print a
b = code.average(a)
print "Assignment done"
print a
print b

Rzeczywista implementacja przypadku, w której w kodzie C ++ wektory stl są przekazywane jako odwołania non const, a zatem są dostępne przez python jako parametry wyjściowe: lobianco.org/antonello/personal:portfolio:portopt
— Antonello

33

Jest też pybind11, która jest jak lekka wersja Boost.Python i kompatybilna ze wszystkimi nowoczesnymi kompilatorami C ++:

https://pybind11.readthedocs.io/en/latest/


1
Dzisiaj !! 2020 To powinna być najlepsza odpowiedź! Jest to biblioteka zawierająca tylko nagłówki szablonów. Wiele dużych odpowiednich projektów zaleca go, np. Pytorch Pytorch.org/tutorials/advanced/cpp_extension.html Działa również w pełni w VS Communitysystemie Windows
— eusoubrasileiro

30

Sprawdź pyrex lub Cython . Są to języki podobne do Pythona do współpracy między C / C ++ i Python.


1
+1 dla Cython! Nie próbowałem cffi, więc nie mogę powiedzieć, co jest lepsze, ale miałem bardzo dobre doświadczenia z Cython - nadal piszesz kod Python, ale możesz w nim używać C. Trochę trudno było mi skonfigurować proces kompilacji z Cython, co później wyjaśniłem w blogu: martinsosic.com/development/2016/02/08/…
— Martinsos

Możesz poprawić odpowiedź, aby nie była już odpowiedzią tylko na link.
— Adelin

Używam Cython od około tygodnia i bardzo mi się podoba: 1) Widziałem używane typy i jest Brzydki i bardzo podatny na błędy z licznymi pułapkami 2) Pozwala ci wziąć trochę kodu Pythona i przyspieszyć go od samego statycznego wpisywania rzeczy 3) Łatwo jest napisać otoki Pythona dla metod i obiektów C / C ++ 4) Nadal jest dobrze obsługiwany. Mogłoby to przynieść więcej wskazówek dotyczących instalacji w venv i kompilacji krzyżowej, co zajęło trochę czasu. Tutaj jest bardzo dobry 4-godzinny samouczek wideo: youtube.com/watch?v=gMvkiQ-gOW8
— Den-Jason

22

Dla współczesnego C ++ użyj cppyy: http://cppyy.readthedocs.io/en/latest/

Opiera się na Cling, interpretatorze C ++ dla Clang / LLVM. Wiązania są w czasie wykonywania i nie jest wymagany żaden dodatkowy język pośredni. Dzięki Clang obsługuje C ++ 17.

Zainstaluj go za pomocą pip:

    $ pip install cppyy

W przypadku małych projektów wystarczy załadować odpowiednią bibliotekę i nagłówki, które Cię interesują. Np. Weź kod z przykładu ctypes to ten wątek, ale podzielony na sekcje nagłówka i kodu:

    $ cat foo.h
    class Foo {
    public:
        void bar();
    };

    $ cat foo.cpp
    #include "foo.h"
    #include <iostream>

    void Foo::bar() { std::cout << "Hello" << std::endl; }

Skompiluj to:

    $ g++ -c -fPIC foo.cpp -o foo.o
    $ g++ -shared -Wl,-soname,libfoo.so -o libfoo.so  foo.o

i użyj go:

    $ python
    >>> import cppyy
    >>> cppyy.include("foo.h")
    >>> cppyy.load_library("foo")
    >>> from cppyy.gbl import Foo
    >>> f = Foo()
    >>> f.bar()
    Hello
    >>>

Duże projekty są obsługiwane przez automatyczne ładowanie przygotowanych informacji o odbiciu i fragmentów cmake do ich utworzenia, aby użytkownicy zainstalowanych pakietów mogli po prostu uruchomić:

    $ python
    >>> import cppyy
    >>> f = cppyy.gbl.Foo()
    >>> f.bar()
    Hello
    >>>

Dzięki LLVM możliwe są zaawansowane funkcje, takie jak automatyczne tworzenie szablonów. Aby kontynuować przykład:

    >>> v = cppyy.gbl.std.vector[cppyy.gbl.Foo]()
    >>> v.push_back(f)
    >>> len(v)
    1
    >>> v[0].bar()
    Hello
    >>>

Uwaga: Jestem autorem cppyy.


3
W rzeczywistości tak nie jest: Cython jest językiem programowania podobnym do Pythona do pisania modułów rozszerzeń C dla Pythona (kod Cython zostaje przetłumaczony na C wraz z niezbędną płytką kotłową C-API). Zapewnia podstawową obsługę C ++. Programowanie w cppyy obejmuje tylko Python i C ++, bez rozszerzeń językowych. Jest w pełni działający i nie generuje kodu offline (leniwe generowanie skaluje się znacznie lepiej). Jest ukierunkowany na nowoczesne C ++ (w tym automatyczne instancje szablonów, ruchy, listy inicjalizujące, lambda itp. Itp.), A PyPy jest obsługiwany natywnie (tj. Nie przez wolną warstwę emulacji C-API).
— Wim Lavrijsen

2
Ten papier PyHPC'16 zawiera szereg numerów wzorcowych. Od tego czasu nastąpiła jednak wyraźna poprawa po stronie CPython.
— Wim Lavrijsen

Lubię to podejście, ponieważ nie trzeba zrobić dodatkową pracę integracji z swig, ctypeslub boost.python. Zamiast pisać kod, aby Python działał z Twoim kodem c ++ ... Python wykonuje ciężką pracę, aby znaleźć c ++. Zakładając, że to faktycznie działa.
— Trevor Boyd Smith

cppyy jest bardzo interesujący! W dokumentach widzę, że redystrybucja i pakowanie wstępne są obsługiwane. Czy to dobrze działa z narzędziami, które również pakują kod Pythona (np. PyInstaller)? I czy jest to związane z projektem ROOT, czy może wykorzystać jego pracę?
— JimB

Dzięki! PyInstaller nie jest mi znany, ale „słowniki”, które pakują do przodu deklaracje, ścieżki i nagłówki, to kody C ++ kompilowane do współdzielonych bibliotek. Ponieważ cppyy jest używany do wiązania kodu C ++, zakładam, że obsługa trochę więcej kodu C ++ powinna być w porządku. I ten kod nie jest zależny od Python C-API (jest tylko moduł libcppyy), co upraszcza rzeczy. samo cppyy można zainstalować z Conda-Forge lub pypi (pip), więc na pewno każde z tych środowisk będzie działać. Tak, cppyy zaczął jako widelec od PyROOT, ale od tego czasu tak się poprawił, że zespół ROOT wypuszcza PyROOT na cppyy.
— Wim Lavrijsen


15

Nigdy go nie używałem, ale słyszałem dobre rzeczy o typach . Jeśli próbujesz używać go z C ++, pamiętaj, aby uniknąć przekłamywania nazw przez extern "C". Dzięki za komentarz, Florian Bösch.


13

Myślę, że cffi dla Pythona może być opcją.

Celem jest wywołanie kodu C z Pythona. Powinieneś być w stanie to zrobić bez uczenia się trzeciego języka: każda alternatywa wymaga nauki własnego języka (Cython, SWIG) lub API (ctyp). Próbowaliśmy więc założyć, że znasz Python i C i zminimalizować dodatkowe bity API, których musisz się nauczyć.

http://cffi.readthedocs.org/en/release-0.7/


2
Myślę, że to może wywoływać tylko c (nie c ++), wciąż +1 (bardzo lubię cffi).
— Andy Hayden,

8

Pytanie brzmi: jak wywołać funkcję C z Pythona, jeśli dobrze zrozumiałem. Zatem najlepszym wyborem są typy Ctyp (BTW przenośne we wszystkich wariantach Pythona).

>>> from ctypes import *
>>> libc = cdll.msvcrt
>>> print libc.time(None)
1438069008
>>> printf = libc.printf
>>> printf("Hello, %s\n", "World!")
Hello, World!
14
>>> printf("%d bottles of beer\n", 42)
42 bottles of beer
19

Szczegółowy przewodnik możesz znaleźć w moim blogu .


Warto zauważyć, że chociaż ctypy są przenośne, twój kod wymaga biblioteki C specyficznej dla systemu Windows.
— Palec


6

Cython jest zdecydowanie właściwą drogą, chyba że spodziewasz się pisać opakowania Java, w takim przypadku SWIG może być lepszym rozwiązaniem.

Polecam korzystanie z runcythonnarzędzia wiersza poleceń, dzięki czemu proces korzystania z Cython jest niezwykle łatwy. Jeśli potrzebujesz przekazać dane strukturalne do C ++, spójrz na bibliotekę protobuf Google, jest to bardzo wygodne.

Oto minimalne przykłady, które stworzyłem przy użyciu obu narzędzi:

https://github.com/nicodjimenez/python2cpp

Mam nadzieję, że może to być przydatny punkt wyjścia.


5

Najpierw powinieneś zdecydować, jaki jest twój konkretny cel. Oficjalna dokumentacja Pythona dotycząca rozszerzania i osadzania interpretera Pythona została wspomniana powyżej, mogę dodać dobry przegląd rozszerzeń binarnych . Przypadki użycia można podzielić na 3 kategorie:

  • moduły akceleratora : aby działały szybciej niż równoważny czysty kod Pythona działa w CPython.
  • moduły opakowujące : w celu udostępnienia istniejących interfejsów C kodowi Python.
  • dostęp do systemu na niskim poziomie : aby uzyskać dostęp do funkcji niższego poziomu środowiska wykonawczego CPython, systemu operacyjnego lub sprzętu.

Aby dać szerszą perspektywę innym zainteresowanym, a ponieważ twoje początkowe pytanie jest nieco niejasne („do biblioteki C lub C ++”), myślę, że ta informacja może być dla ciebie interesująca. Na powyższym linku możesz przeczytać o wadach korzystania z rozszerzeń binarnych i ich alternatyw.

Oprócz innych sugerowanych odpowiedzi, jeśli chcesz moduł akceleratora, możesz wypróbować Numba . Działa „generując zoptymalizowany kod maszynowy przy użyciu infrastruktury kompilatora LLVM w czasie importu, w czasie wykonywania lub statycznie (przy użyciu dołączonego narzędzia pycc)”.


3

Uwielbiam cppyy, bardzo ułatwia rozszerzenie Pythona za pomocą kodu C ++, dramatycznie zwiększając wydajność w razie potrzeby.

Jest potężny i szczerze mówiąc bardzo prosty w użyciu,

tutaj jest przykład, w jaki sposób można utworzyć tablicę numpy i przekazać ją do funkcji członka klasy w C ++.

cppyy_test.py

import cppyy
import numpy as np
cppyy.include('Buffer.h')


s = cppyy.gbl.Buffer()
numpy_array = np.empty(32000, np.float64)
s.get_numpy_array(numpy_array.data, numpy_array.size)
print(numpy_array[:20])

Bufor. H

struct Buffer {
  void get_numpy_array(double *ad, int size) {
    for( long i=0; i < size; i++)
        ad[i]=i;
  }
};

Możesz także bardzo łatwo stworzyć moduł Pythona (z CMake), dzięki czemu unikniesz ponownej kompilacji kodu C ++ przez cały czas.


2

pybind11 minimalny możliwy do uruchomienia przykład

pybind11 był wcześniej wspomniany na https://stackoverflow.com/a/38542539/895245, ale chciałbym podać tutaj konkretny przykład użycia i trochę dalszej dyskusji na temat implementacji.

W sumie gorąco polecam pybind11, ponieważ jest naprawdę łatwy w użyciu: wystarczy dołączyć nagłówek, a następnie pybind11 używa magii szablonów, aby sprawdzić klasę C ++, którą chcesz udostępnić Pythonowi i robi to w przejrzysty sposób.

Minusem tej magii szablonu jest to, że spowalnia kompilację, natychmiast dodając kilka sekund do dowolnego pliku korzystającego z pybind11, patrz na przykład dochodzenie przeprowadzone w tej sprawie . PyTorch zgadza się .

Oto minimalny przykład, który można uruchomić, aby poczuć, jak niesamowity jest pybind11:

class_test.cpp

#include <string>

#include <pybind11/pybind11.h>

struct ClassTest {
    ClassTest(const std::string &name) : name(name) { }
    void setName(const std::string &name_) { name = name_; }
    const std::string &getName() const { return name; }
    std::string name;
};

namespace py = pybind11;

PYBIND11_PLUGIN(class_test) {
    py::module m("my_module", "pybind11 example plugin");
    py::class_<ClassTest>(m, "ClassTest")
        .def(py::init<const std::string &>())
        .def("setName", &ClassTest::setName)
        .def("getName", &ClassTest::getName)
        .def_readwrite("name", &ClassTest::name);
    return m.ptr();
}

class_test_main.py

#!/usr/bin/env python3

import class_test

my_class_test = class_test.ClassTest("abc");
print(my_class_test.getName())
my_class_test.setName("012")
print(my_class_test.getName())
assert(my_class_test.getName() == my_class_test.name)

Skompiluj i uruchom:

#!/usr/bin/env bash
set -eux
g++ `python3-config --cflags` -shared -std=c++11 -fPIC class_test.cpp \
  -o class_test`python3-config --extension-suffix` `python3-config --libs`
./class_test_main.py

Ten przykład pokazuje, jak pybind11 pozwala bez wysiłku wystawiać ClassTestklasę C ++ na Pythona! Kompilacja tworzy plik o nazwie, class_test.cpython-36m-x86_64-linux-gnu.soktóry class_test_main.pyautomatycznie wybiera się jako punkt definicji plikuclass_test natywnie zdefiniowanego modułu.

Być może uświadomienie sobie, jak to jest niesamowite, zatapia się tylko wtedy, gdy próbujesz zrobić to samo ręcznie z natywnym API Pythona, zobacz na przykład ten przykład wykonania, który zawiera około 10 razy więcej kodu: https://github.com /cirosantilli/python-cheat/blob/4f676f62e87810582ad53b2fb426b74eae52aad5/py_from_c/pure.c W tym przykładzie możesz zobaczyć, jak kod C musi boleśnie i wyraźnie definiować klasę Python krok po kroku ze wszystkimi zawartymi w niej informacjami (członkowie, metody, dalej metadane ...). Zobacz też:

pybind11 twierdzi, że jest podobny do Boost.Pythontego, o którym wspomniano na https://stackoverflow.com/a/145436/895245, ale bardziej minimalny, ponieważ jest wolny od nadęty bycia w projekcie Boost:

pybind11 to lekka biblioteka zawierająca tylko nagłówki, która eksponuje typy C ++ w Pythonie i odwrotnie, głównie w celu tworzenia powiązań Pythona z istniejącym kodem C ++. Jego cele i składnia są podobne do doskonałej biblioteki Boost.Python autorstwa Davida Abrahamsa: aby zminimalizować kod płyty wzorcowej w tradycyjnych modułach rozszerzeń poprzez wywnioskowanie informacji o typie przy użyciu introspekcji w czasie kompilacji.

Główny problem z Boost.Python - i powód stworzenia takiego podobnego projektu - to Boost. Boost to niezwykle duży i złożony zestaw bibliotek narzędziowych, który działa z prawie każdym istniejącym kompilatorem C ++. Ta kompatybilność ma swój koszt: tajemnicze sztuczki związane z szablonami i obejścia są niezbędne do obsługi najstarszych i najbardziej szkodliwych próbek kompilatora. Teraz, gdy kompilatory kompatybilne z C ++ 11 są powszechnie dostępne, ta ciężka maszyna stała się zbyt dużą i niepotrzebną zależnością.

Pomyśl o tej bibliotece jako o małej, samodzielnej wersji Boost.Python ze wszystkim, co zostało usunięte, co nie ma znaczenia dla generowania powiązań. Bez komentarzy podstawowe pliki nagłówkowe wymagają tylko ~ 4 wierszy kodu i zależą od Pythona (2.7 lub 3.x lub PyPy2.7> = 5.7) i standardowej biblioteki C ++. Ta kompaktowa implementacja była możliwa dzięki niektórym nowym funkcjom języka C ++ 11 (w szczególności: krotki, funkcje lambda i szablony variadic). Od momentu powstania biblioteka ta rozszerzyła się na wiele sposobów poza Boost.Python, prowadząc do znacznie prostszego wiązania kodu w wielu typowych sytuacjach.

pybind11 jest także jedyną nie-rodzimą alternatywą wyróżnioną przez aktualną dokumentację wiązania Microsoft Python C pod adresem : https://docs.microsoft.com/en-us/visualstudio/python/working-with-c-cpp-python-in- visual-studio? view = vs-2019 ( archiwum ).

Testowane na Ubuntu 18.04, pybind11 2.0.1, Python 3.6.8, GCC 7.4.0.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.