boost::python

한 3주 쯤 전부터 Python/C++을 같이 쓰려고 삽질 중이었는데, 지난 주 초에 boost::python을 발견하고 이 둘을 쉽게 연결하기 시작 – 이어지는 내용은 UPnL 워크샵(2007/6/16)에서 발표했던 것의 요약입니다. 그 내용을 기반으로 해서몇일 정도 포스팅을 하려고 합니다.

사용하려는 플랫폼에 대해 초보적인 수준의 library사용 경험만 있으면(동적바인딩 라이브러리 빌드/링킹 관련) boost::python을 사용했을때 편한 점들은 일단,

  • Python C interface를 상세히 알지 못하는 상황에서도 C++ 인터페이스를 python module로 내보내기 쉽습니다.
  • Python embedding – C++ 쪽에서 python 코드를 실행시키는 것 – 을 쉽게 구현할 수 있습니다.
  • 양자를 통합해서 사용할 때도 편합니다. (예를 들어 C++이 전체 초기화를 하고, 일부분을 python 쪽에 노출 시키고, 메인 루프의 논리적인 부분은 python에서 노출된 C++ 함수를 호출함으로써 처리)

정도 입니다. 사실 3번째 경우가 필요한 상황이었는데, python 문서만 봐선 잘 할 수가 없던 부분이 쉽게 되서 매우 만족스럽습니다.

매우 긴 컴파일 시간 – <boost/python.hpp>의 컴파일 시간이 precompiled header를 써서 줄이지 않으면 안될 정도의 수준입니다 – 문제가 있고, boost library를 빌드할때 사용했었던 Python.h 버젼을 기준으로 실행 가능한 python 인터프리터가 결정되는 문제도 있습니다 – boost library를 python 2.4 헤더를 가지고 만들었었는데, 2.5 헤더와 2.5 라이브러리 파일로 빌드했더니 빌드는 되지만 실제로 import할때 해괴한-_-에러를 내면서 인터프리터가 강제 종료됩니다.

기본적인 예로 – 그리고 그런대로 실용적인 예로 – Win32 DirectX의 D3DXVECTOR3 를 export 하는 코드입니다.

BOOST_PYTHON_MODULE( d3d )
{
    class_<D3DXVECTOR3>( "v3", init<float, float, float>() )
        .def( self + self )
        .def( self - self )
        .def( self * float() )
        .def( self / float() )
        .def( float() * self )
        .def( - self )
        .def( + self )
        .def_readwrite("x", &D3DXVECTOR3::x)
        .def_readwrite("y", &D3DXVECTOR3::y)
        .def_readwrite("z", &D3DXVECTOR3::z)
    ;
}

class_ 라는 템플릿을 이용해서 클래스를 통채로 내보낼 수 있습니다 -그렇지만 실제로 노출할 것들은 일일이 서술 해줘야하긴 합니다. 가장 만족스러운 점은 예전에 lua로 작업할 때는 할 수 없었던 것 – operator overloading 내보내기 – 을 매우 깔끔하게 할 수 있다는 부분입니다. 위 코드에서 .def( self … ) 인 부분들은 전부 그런 역할을 합니다. 그리고 member variable을 노출시키는 부분도 상당히 단순하게 이루어집니다. 덤으로 맘에든 것은 C++에는 없는 property 비슷한 것을 사용할 수 있다는 점입니다.

여기까지 진행하면서 볼 수 있었던 에러들

  • Fatal Python error: Interpreter not initialized (version mismatch?) Debug 버젼의 파이썬 라이브러리를 사용하고, 일반(non-debug) Python 인터프리터를 사용하거나그 반대의 경우에 나오는 메시지라고 합니다. 하지만 제가본 것은 boost를 2.4에서 빌드하고 2.5 헤더/라이브러리를 썼기 때문. 해당 메시지는 module import 시점에서만 볼수 있는 것.
  • ImportError: dynamic module does not define init function (initHelloWorld) BOOST_PYTHON_MODULE로 내보낸 모듈의 이름과 .so 혹은 .pyd(실제로는 .dll의 이름 바꾸기지만)의 이름이 일치하지 않는 경우에 볼 수 있었음