출처
ctypes로 Python에서 C++ 클래스 호출하기
저는 파이썬에서 C++ 클래스를 호출하고 싶어서 최근에 스스로 방법을 찾았습니다. 저는 (Thrift를 사용하여 전에 했던 것처럼 - Python과 C++을 위한 Apache Thrift 사용하기를 보세요.) 분리된 프로세스를 호출하고 싶지 않았고 C++ 라이브러리를 직접 호출하고 싶었습니다.
저는 진행하기 전에 이를 파이썬으로 하기 위한 다양한 방법이 있다는 것을 말하고 싶습니다. 그리고 저는 작동한 것 중 하나를 선택하였습니다. 다른 기술도 사용 가능하며 어떤 기술이 '최상'인지에 대한 의견은 상당히 분분해 보입니다.
C++ 클래스로 시작하기 위해 평범하게 작성하였습니다.
#include <iostream>
// A simple class with a constuctor and some methods...
class Foo
{
public:
Foo(int);
void bar();
int foobar(int);
private:
int val;
};
Foo::Foo(int n)
{
val = n;
}
void Foo::bar()
{
std::cout << "Value is " << val << std::endl;
}
int Foo::foobar(int n)
{
return val + n;
}
다음 ctypes 시스템은 C++을 사용할 수 없기 때문에 C++ 코드 주변에 C wrapper를 놓을 것입니다. 이를 하기 위해 파일 제일 밑에 다음 부분에 코드를 추가합니다.
// ctypes는 C와만 대화할 수 있기 때문에 C++ 클래스를 위한 C 함수를 정의합니다.
extern "C"
{
Foo* Foo_new(int n) {return new Foo(n);}
void Foo_bar(Foo* foo) {foo->bar();}
int Foo_foobar(Foo* foo, int n) {return foo->foobar(n);}
}
호출하기 원하는 각 메소드를 클래스 기반이 아닌 이름으로 제공해야 함을 알아두세요.
우리는 우리 코드에서 lib.so 파일을 빌드해야 합니다.
다음을 쉘에서 입력하세요.
$ g++ -c -fPIC foo.cpp -o foo.o
$ g++ -shared -Wl,-soname,libfoo.so -o libfoo.so foo.o
또는 CMake를 사용할 수 있습니다.
다음은 foo.cpp를 빌드하기 위한 CMakeLists.txt 입니다.
cmake_minimum_required(VERSION 2.8.9)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}")
set(CMAKE_MACOSX_RPATH 1)
project (foo)
set (SOURCE foo.cpp)
add_library(foo MODULE ${SOURCE})
저는 Mac에서 빌드를 해서 MacOS를 위해 4번째 줄을 추가하였습니다. 리눅스에서도 잘 작동하겠지만 필요는 없습니다.
이제 C++로 컴파일 된 내용을 작성합니다. 우리는 클래스에 대한 Python wrapper를 빌드하려 합니다.
import ctypes
lib = ctypes.cdll.LoadLibrary('./libfoo.so')
class Foo(object):
def __init__(self, val):
lib.Foo_new.argtypes = [ctypes.c_int]
lib.Foo_new.restype = ctypes.c_void_p
lib.Foo_bar.argtypes = [ctypes.c_void_p]
lib.Foo_bar.restype = ctypes.c_void_p
lib.Foo_foobar.argtypes = [ctypes.c_void_p, ctypes.c_int]
lib.Foo_foobar.restype = ctypes.c_int
self.obj = lib.Foo_new(val)
def bar(self):
lib.Foo_bar(self.obj)
def foobar(self, val):
return lib.Foo_foobar(self.obj, val)
리턴 값의 타입과 argument 타입을 정의하는 요구사항을 적으세요. (하나도 리턴하지 않으면 예시로 void를 리턴합니다.) 이것이 없으면 segmentation fault(등)를 얻을 것입니다.
이제 모든 것을 다 하였고 모듈을 빌드해야 합니다. 파이썬에서 간단히 그것을 import할 수 있습니다.
예를 들어
from foo import Foo
# 우리는 5라는 값으로 Foo 객체를 생성할 것입니다...
f=Foo(5)
# f.bar()를 호출하는 것은 값을 포함한 메시지를 출력할 것입니다...
f.bar()
# 이제 f, Foo 객체에서 저장되어 있는 값에 값(7)을 더하기 위해 foobar를 사용합니다.
print (f.foobar(7))
# 또 한 번 같은 메소드를 호출합니다 - 이 번엔 일반적인 파이썬 정수를
# 보여줄 것입니다...
x = f.foobar(2)
print (type(x))
이 간단한 데모를 위한 전체 소스 코드는 여기에 있습니다.
https://github.com/Auctoris/ctypes_demo
이 간단한 데모를 위한 전체 소스 코드는 여기에 있습니다.
'Python' 카테고리의 다른 글
Python 스레드 풀 (0) | 2018.07.28 |
---|---|
python: MySQLdb. 의 큰 테이블에서 select * 없이 컬럼명을 얻는 방법 (0) | 2018.07.25 |
Python의 Requests 모듈을 사용하여 웹사이트에 "로그인"하는 방법 (0) | 2018.02.21 |
파이썬 list comprehension에서 if/else 구문 사용법? (0) | 2017.08.10 |
파이썬 - UTC 날짜시간 문자열을 local 날짜시간으로 변환하기 (0) | 2017.05.29 |