Как можно импортировать c++ функцию из dll с помощью ctypes и можно ли?
Есть код на c++ ( lib1.cpp ), скомпилированный в dll файл ( lib1.dll ), также python код ( main.py ). Для компиляции dll файла использован g++ mingw 12.2.0. Использую Windows 10
Код компиляции:
g++ -shared -o lib1.dll lib1.cpp
main.py :
import ctypes
lib=ctypes.CDLL("lib1.dll",winmode=0)
lib.print("Hello")
lib1.cpp :
#include <iostream>
using namespace std;
extern "C" {
void print(string st);
}
void print(string st){
cout<<st;
}
Я видел в решении похожей задаче на английской версии сайта, там использовался extern. В моем случае он не помог. При попытке запустить функцию print , я получаю ошибку
AttributeError: function 'print' not found
Как можно подключить функцию и можно ли? Если нет, то почему в этом случае всё получилось?
PS: Немного исправил код lib1.cpp
Ответы (1 шт):
Да, можно. Решение найдено на основе этой статьи где есть пример с использованием класса. Для простоты я оставил только код присутсвующий в вопросе. В качестве запуска на питоне я проверил еще и метод из ответа — оба работают, второй разумеется проще. хотя если нужны перегрузки то возможно пригодится и первый, не проверял. Что касается extern то в данном случае, как я понял, он помогает сохранить имена функций такими как мы их прописали, вероятно чтобы ctypes мог с ним работать.
lib1.hpp
#include <iostream>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
void print(char *val);
#ifdef __cplusplus
}
#endif
lib1.cpp
#include "lib1.hpp"
void print(char *val) {
std::cout << val << std::endl;
}
main.py
# Вариант с Хабра
import ctypes
lib1 = ctypes.CDLL('./lib1.so')
lib1.print.restype = ctypes.c_void_p
lib1.print.argtypes = [ctypes.c_char_p]
lib1.print('Hello!'.encode('utf-8')) # Hello!
# Вариант из ответа enSO
from ctypes import cdll
lib1 = cdll.LoadLibrary('./lib1.so')
lib1.print('Hello!'.encode('utf-8')) # Hello!
Если не передавать с encode('utf-8') вывод стопорится на 1 символе.
Тестировал только на linux (.so аналог .dll) код компилировал так:
g++ -fPIC -shared -o lib1.so lib1.cpp
Флаг -fPIC позволяет генерировать машинный код не зависимо от адреса размещения программы в памяти, без него у меня при компиляции вылетала ошибка
symbol `_ZSt4cout@@GLIBCXX_3.4' can not be used when making a shared object;
recompile with -fPIC
Т.е. лучше все же эту опцию использовать если будет ругаться.`
P.S.:
В Windows 10, все таки удалось проверить, код отрабатывает, поменял только .so на .dll (в билде и скрипте) и добавил аргумент winmode=0 в ctypes.CDLL, т.е. так как у Вас.
lib=ctypes.CDLL("lib1.dll",winmode=0)