Vorwort Vor Kurzem habe ich begonnen, Robot Framework zum Testen dynamischer C++-Bibliotheken zu verwenden. Robot Framework läuft unter Windows und dynamische C++-Bibliotheken laufen auf einem Remote-Linux-Host. Die Testmethode besteht darin, das Roboter-Framework das Python-Skript auf dem Remote-Computer über die SSHLIbrary-Bibliothek ausführen zu lassen, und das Python-Skript ruft die dynamische C++-Bibliothek auf. Jetzt müssen wir das Problem lösen, wie wir Python die dynamische C++-Bibliothek aufrufen lassen. Zwei Möglichkeiten zum Aufrufen der dynamischen C++-Bibliothek in Python Nach einer Online-Suche und durch Rücksprache mit Kollegen bin ich auf zwei Methoden gestoßen: Die erste besteht darin, die dynamische C++-Bibliothek in eine C-Schnittstelle zu kapseln und Python die C-Sprachschnittstelle aufrufen zu lassen. Da Python nur C-Schnittstellen aufrufen kann und C++-Schnittstellen nicht direkt aufrufen kann, ist eine Kapselungsschicht erforderlich. Kapselungsmethode: Verwenden Sie die externe Deklarationsmethode „C“, um eine Schicht der C-Sprachschnittstelle über der C++-Schnittstelle zu kapseln. Nachdem wir diese Methode ausprobiert haben, haben wir festgestellt, dass reine C-Aufrufe möglich sind, Python-Aufrufe jedoch nicht. Die Gründe werden im Folgenden ausführlich erläutert. Die zweite Methode besteht darin, mithilfe der C++-Boost-Bibliothek eine Schnittstelle zu generieren, die Python aufrufen kann. Diese Methode wurde getestet und ist machbar, aber der Vorgang ist sehr umständlich. Im Folgenden werden die aufgetretenen Probleme und ihre Lösungen im Detail erläutert. Die Natur des externen „C“ verstehen Bevor wir die erste Methode beschreiben, stellen wir kurz die Funktion der externen „C“-Methode vor. Konkrete Erklärungen finden Sie in diesem Blog, der sehr ausführlich ist und sich zum Lesen empfiehlt. Beispielsweise gibt es in der Sprache C eine Funktion } Wenn Sie den gcc-Compiler verwenden, lautet der von der Kompilierung generierte Name „add“, wenn Sie jedoch den g++-Compiler verwenden, kann der von der Kompilierung generierte Name etwa wie „ABaddCD“ lauten und den Funktionsnamen, die Anzahl der Eingabeparameter, den Typ und den Rückgabewert enthalten. Wenn C++ also auch eine überladene Fügt eine Gleitkommazahl hinzu, die mit a und b übereinstimmt. Der durch die Kompilierung generierte Name könnte etwa EFaddGH sein, der auch Informationen wie Funktionsname, Eingabeparameter, Rückgabewert usw. enthält, sodass C++ überladen werden kann. Stellen Sie sich vor, Sie verwenden den gcc-Compiler. Dann heißen sie alle „add“, und Sie können nicht erkennen, um welche Funktion es sich handelt, und können sie daher nicht überladen. Die Rolle von extern „C“ besteht dann darin, dem g++-Compiler mitzuteilen, dass int add(int a, int b) in add statt in ABaddCD kompiliert werden soll, da add von der Sprache C erkannt wird, ABaddCD jedoch von der Sprache C nicht erkannt wird und die Sprache C Add als „undefiniertes Symbol“ betrachten würde. Daraus können wir auch erkennen, dass externes „C“ nur für C++-Code verwendet werden kann. Darüber hinaus müssen Sie für überladene C++-Funktionen zwei verschiedene Funktionen schreiben, um sie separat aufzurufen und sicherzustellen, dass die Namen nicht wiederholt werden. Python verwendet externes „C“, um die dynamische C++-Bibliothek aufzurufen Nachdem wir die Natur des externen „C“ kennen, werden wir es gemäß dieser Methode kapseln. Ich habe direkt den Quellcode der dynamischen C++-Bibliothek übernommen, eine Schicht C-Schnittstelle über den Quellcode gekapselt und dann die dynamische Bibliothek generiert. Angenommen, die Add-Funktion ist als addc gekapselt, die dynamische C++-Bibliothek heißt A und die nach der Kapselung einer Schicht der C-Schnittstelle generierte dynamische Bibliothek heißt B. Wenn Sie einen Testcode mit dem Namen test.c schreiben, reinen C-Code verwenden, um die dynamische Bibliothek B zu überprüfen, und die Funktion addc aufrufen, ist das Ergebnis machbar und erfolgreich. Wenn Sie jedoch Python zum Überprüfen der dynamischen Bibliothek B verwenden und die Funktion addc aufrufen, wird der folgende Fehler gemeldet:
Das heißt, die Add-Funktion wird weiterhin nicht erkannt. verwenden nm B.so | grep hinzufügen In der Lage sein zu bekommen
Infolgedessen kann das erste addc definitiv von Python erkannt werden, aber das zweite ABaddCD ist der durch die G++-Kompilierung generierte Name und kann von Python nicht aufgerufen werden. Ich gebe nur ein Beispiel aus meiner eigenen Erfahrung. Der Quellcode meiner eigenen dynamischen C++-Bibliothek ist möglicherweise relativ komplex und kann von Python nicht erfolgreich aufgerufen werden. Es gibt online viele Beispiele, die erfolgreich aufgerufen werden können. Die Leser können also selbst experimentieren. Wenn sie erfolgreich benennen können, ist das das Beste. Denn die Art und Weise, wie boost.python verwendet wird, die ich als nächstes vorstelle, ist ziemlich umständlich. Python verwendet boost.python, um die dynamische C++-Bibliothek aufzurufen Lösen Sie andere Drittanbieterbibliotheken, von denen dynamische C++-Bibliotheken abhängen Da meine dynamische Bibliothek von anderen Bibliotheksdateien von Drittanbietern wie OpenSSL, UUID, Libevent und Pthread abhängt, muss Python diese dynamischen Bibliotheken laden, unabhängig davon, mit welcher Methode die dynamische C++-Bibliothek aufgerufen wird. Der spezifische Python-Code lautet wie folgt: von ctypes importiere * ctypes.CDLL("libssl.so", Modus=ctypes.RTLD_GLOBAL) ctypes.CDLL("libcrypto.so", Modus=ctypes.RTLD_GLOBAL) ctypes.CDLL("libuuid.so", Modus=ctypes.RTLD_GLOBAL) ctypes.CDLL("/usr/lib64/libevent.so", Modus=ctypes.RTLD_GLOBAL) #ctypes.CDLL("/usr/lib64/libpthread.so.0", Modus=ctypes.RTLD_GLOBAL) Einige können standardmäßig geladen werden, wie z. B. libpthread.so, das wir nicht laden müssen. Andere müssen manuell geladen werden, wie z. B. libssl.so und libuuid.so, die sich alle im Verzeichnis /usr/lib64/ befinden und nicht zum Pfad hinzugefügt werden müssen. Die libevent-Bibliothek befindet sich jedoch auch im Verzeichnis /usr/lib64 und auch im Verzeichnis /usr/lib/, daher muss der Pfad hinzugefügt werden. Wenn die Kompilierung fehlschlägt, überprüfen Sie mit whereis libevent.so, in welchem Verzeichnis es sich befindet, und fügen Sie dann den absoluten Pfad hinzu. Manchmal funktioniert das Hinzufügen des absoluten Pfads immer noch nicht. Beispielsweise meldet libpthread.so nach dem Hinzufügen des absoluten Pfads immer noch einen Fehler.
Dies bedeutet, dass die Versionsnummer falsch ist. Suchen Sie die Versionsnummer des libpthread.so-Links und fügen Sie die Versionsnummer .0 hinzu. Dann wird kein Fehler gemeldet. C++-Codekonfigurations-Boost-Umgebung Auf der CentOS6.6-Maschine, auf der sich die dynamische C++-Bibliothek befindet, verweise ich auf: Ubuntu Python ruft die C/C++-Methode zur Konfiguration und zum Test-Boost der dynamischen Linkbibliothek auf. Referenz: Verwenden von Boost.Python zum Implementieren einer gemischten Python-C/C++-Programmierung zum Implementieren einer Python-definierten C++-Funktionsüberladung. Beim Konfigurieren der Umgebung habe ich folgende Befehle verwendet: yum install boost*, yum install python-devel. Ich habe boost unter Bezugnahme auf diese beiden Artikel implementiert und im Grunde haben alle funktioniert. Die Probleme, auf die ich gestoßen bin, wurden auch in diesen beiden Artikeln erwähnt. Ich bin auch auf andere Probleme gestoßen und habe Lösungen auf Stack Overflow gefunden. Die Ergebnisse werde ich direkt unten posten: Erstellen Sie eine neue Datei test.cpp, in der wir die für Python verfügbaren Funktionen definieren müssen. Fügen Sie im Code test.cpp den folgenden Code ein: // Boost-Headerdatei muss eingebunden werden #include <boost/python.hpp> #include <boost/python/module.hpp> #include <boost/python/def.hpp> //Implementierung überladener Funktionen. In meinem C++-Code haben die LOGIN-Funktion, die Synchronize_Request-Funktion und die Notify-Funktion jeweils drei überladene Funktionen. Im Folgenden verwende ich nur eine LOGIN-Funktion, eine Synchronize_Request-Funktion und zwei Notify-Funktionen. Beispielsweise sind fun3 und fun4 im Folgenden zwei verschiedene Notify-Funktionen. //Nur überladene Funktionen müssen fun1, fun2, fun3, fun4 so definieren. Wenn es keine überladene Funktion gibt, können Sie den Namen direkt schreiben int (*fun1)(const int server_type, const int request_no, std::string& login_result) = &LOGIN; int (*fun2)(const int server_type, const int request_no,std::string& recv_answer) = &Anfrage synchronisieren; int (*fun3)(const int server_type, unsigned int timeout_ms, unsigned int sesscare ) = &Benachrichtigen; int (*fun4)(void) = &Benachrichtigen; // Beispiel für Funktionsüberladung hinzufügen int (*fun5)(int a,int b) = &add; BOOST_PYTHON_MODULE( libB ) // Python-Modul, der Name von libB sollte mit dem Namen von .so { übereinstimmen. Namespace boost::python verwenden; //Die Initialisierungsfunktion ist nicht überladen, daher können Sie sie direkt verwenden, ohne fun1 wie oben zu definieren. def("Initialisieren",Initialisieren); //Die Funktion „Uninitialize“ ist nicht überladen, verwenden Sie sie einfach direkt. def("Uninitialize",Uninitialize); def("ANMELDEN",spaß1); def("Anfrage synchronisieren",fun2); def("Benachrichtigen",fun3); def("Benachrichtigung2",Spaß4); def("Hinzufügen",fun5); // Python kann die in der obigen Definition definierte Funktion aufrufen} Die vom Makefile verwendeten Befehle sind: %.o : %.cpp g++ -g -lssl -fPIC -levent -lcrypto -luuid -lpthread -lrt -lboost\_filesystem -lboost\_system -lboost_python -lpython -I/usr/include/python2.7 -o $@ -c $< Der Befehl zum Generieren von B.so lautet: g++ -shared -Wl,-soname,libB.so -o libB.so *.o -lpython -lboost_python Die dynamische Bibliothek muss im Python-Skript eingeführt werden libB importieren drucke libB.add(10,20) Durch Schreiben und Kompilieren gemäß den obigen Befehlen können Sie die Fallstricke vermeiden, auf die ich gestoßen bin. Achten Sie auf die Position von -lpython und setzen Sie es nicht an den Anfang. Wenn die überladene Definition nicht implementiert ist und def("LOGIN",LOGIN); direkt verwendet wird, wird der folgende Fehler gemeldet: Fehler: Keine passende Funktion für den Aufruf von 'def(const char [15], <unaufgelöster überladener Funktionstyp>)' def("LOGIN",LOGIN); Zusammengefasst ist dies das Ergebnis meiner Recherchen des ganzen Tages. Wenn es Fehler oder Auslassungen gibt, weisen Sie mich bitte darauf hin. Vielen Dank. Ergänzung: Wenn ich boost.python verwende, um die dynamische C++-Bibliothek aufzurufen, kann ich keine Referenztypen verarbeiten. Beispielsweise wird string& recv_answer verwendet, um das Rückgabeergebnis zu erhalten, und wird als string{lvalue} erkannt, aber mein Python übergibt es im String-Typ und kann nicht übereinstimmen. Daher habe ich die Zeichenfolgentypreferenz von string& recv_answer manuell in das Format char * recv_answer_c geändert, das heißt, ich habe sie in den C-Sprachstil geändert und dann den Parameter recv_answer_c auf die folgende Weise übergeben, um das Ergebnis zu erhalten. #Verwenden Sie Bytes, um Speicherplatz für Variablen vorab zu reservieren und so sicherzustellen, dass keine Segmentierungsfehler auftreten. temp = Bytearray(1000) recv_answer_c = Bytes(temp) Zusammenfassen: Das Obige ist der vollständige Inhalt dieses Artikels. Ich hoffe, dass der Inhalt dieses Artikels einen gewissen Lernwert für Ihr Studium oder Ihre Arbeit hat. Wenn Sie Fragen haben, können Sie eine Nachricht hinterlassen. Vielen Dank für Ihre Unterstützung von 123WORDPRESS.COM. Das könnte Sie auch interessieren:
|
<<: Beispiel zum Erstellen eines lokalen Benutzers in MySQL und Erteilen von Datenbankberechtigungen
>>: Konstruktions- und Nutzungsprozess des Vue3.0-Projekts
Inhaltsverzeichnis Vue3 + TypeScript lernen 1. Um...
In diesem Artikel wird der spezifische Code für J...
Inhaltsverzeichnis 1. Speichermodell und Laufzeit...
Inhaltsverzeichnis Private Klassenfelder in JavaS...
Das Internet ist bereits voll von Artikeln dieser...
Anweisungen zur MySQL-Installation MySQL ist ein ...
Inhaltsverzeichnis [Siehe ein Beispiel]: [Der urs...
Heute werde ich diese Anfängerfragen beantworten: ...
Zusammenfassung: HBase verfügt über zahlreiche Be...
Docker-Installation 1. Anforderungen: Linux-Kerne...
Inhaltsverzeichnis Manipulationssicheres Javascri...
Heute fiel mir plötzlich ein, die Produktionsprinz...
Geschäftsszenarioanforderungen und Implementierun...
In diesem Artikelbeispiel wird der spezifische Co...
Zwei Möglichkeiten zum Navigieren auf der Seite D...