Как можно импортировать c++ функцию из dll с помощью ctypes и можно ли?

Рейтинг: 1Ответов: 1Опубликовано: 06.04.2023

Есть код на 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

Ответы

▲ 2Принят

Да, можно. Решение найдено на основе этой статьи где есть пример с использованием класса. Для простоты я оставил только код присутсвующий в вопросе. В качестве запуска на питоне я проверил еще и метод из ответа — оба работают, второй разумеется проще. хотя если нужны перегрузки то возможно пригодится и первый, не проверял. Что касается 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)