study2012. 4. 23. 17:18

질문을 하나 받았다. Python/C API 관련 질문인데 이게 조금 복잡하다.

 

C/C++에서 파이썬을 사용하고 싶으면 Python/C API 사용해 파이썬을 프로그램에 포함시키면 된다. 아래 예제에서


#include "Python.h"


int

main(int argc, char *argv[])

{

   Py_Initialize();

 

   PyRun_SimpleString("from time import time,ctime\n"

                              "print('Today is', ctime(time()))\n");

   Py_Finalize();

}

 

현재 시간을 가져오는 프로그램을 파이썬의 time 모듈을 이용해서 구현한 것이다.

Python/C API 상위 레이어 함수인 PyRun_simpleString 사용해 쉽게 파이썬을 C/C++에서 실행 시킬 있다.

 

그렇다면 PyRun_SimpleString 번째 인수인 파이썬 구문에서 C/C++ 함수를 호출 있을 ? 물론 가능하다. 이를 위해서 파이썬 확장 모듈이라는 것이 있다.

 

파이썬에서 사용할 모듈 -여기서는 spam- 만들고 컴파일 하면 shared library 만들어 지고 이를 파이썬이 설치되어 있는 디렉터리에 옮겨 놓으면 된다.

 

그리고 아래와 같이 사용하면 된다.


PyRun_SimpleString("import spam\n"

                          "print('String Length is : ', spam.strlen('abc'))\n");

 

하지만 so 매번 옮겨 놓을 수도 없는 노릇이고, 원하는 것은 소스코드 안에서 파이썬과 C/C++ 서로 통신하듯이 쓰는 것이기 때문에   방법은 문제가 있다.

 

일단 C/C++ 함수를 파이썬에서 사용하게 하려면 함수들을 파이썬 확장 모듈로 만들어야 한다.

여기까지는 순조로웠는데, 만든 모듈을 파이썬에서 임포트 없었다.

문제는 PyRun_SimpleString안의 파이썬구문이 실행 , 우리가 만든 spam 모듈이 파이썬 built-in 네임스페이스에 포함 되지 않는 다는 것이다.

 

참고할 예제도 없어서, 주말 내내 Python Document 읽어보았다.

 

그래서 찾아낸 함수가 PyImport_ExtendInittab, PyImport_AppendInittab이다.

(http://docs.python.org/py3k/c-api/import.html?highlight=pyimport_#PyImport_ExtendInittab)

해당 모듈을 build-in 추가 해주는 고마운 함수이다. Importing Modules(http://docs.python.org/py3k/c-api/import.html) 보면 모듈을 C API에서 임포팅 하는 함수들이 나온다. PyImport_AppendInittab으로 예제를 만들고 테스트 해봤다.

 


#include "Python.h"

 

static PyObject *

spam_strlen(PyObject *self, PyObject *args)

{

    const char* str=NULL;

    int len;

 

    if (!PyArg_ParseTuple(args, "s", &str))

         return NULL;

 

    printf("argument = %s\n", str);

    len = strlen(str);

 

    return Py_BuildValue("i", len);

}

 

static PyMethodDef SpamMethods[] = {

{"strlen", spam_strlen, METH_VARARGS,

 "count a string length."},

 {NULL, NULL, 0, NULL}

};

 

static struct PyModuleDef spammodule = {

    PyModuleDef_HEAD_INIT,

    "spam",           

    "It is test module.",

    -1, SpamMethods

};

 

static PyObject* PyInit_spam(void)

{

    return PyModule_Create(&spammodule);

}

 

int

main(int argc, char *argv[])

{

 

   PyImport_AppendInittab("spam", &PyInit_spam);

 

   Py_Initialize();

 

   PyRun_SimpleString( "import spam\n"

       "print('String Length is : ', spam.strlen('abc'))\n"

   );

  

   Py_Finalize();

   return 0;

}

 


 

PyImport_AppendInittab에서 built-in 포함될 모듈의 이름과 만든 모듈 포인터를 넣어준다.

한가지 특이한 점이 PyInit_spam처럼 모듈을 바로 입력 받지 않고 함수 포인터를 받는 다는 것이다.

PyImport_AppendInittab는 Py_Initialize() 호출하기 전에 호출 되야 한다.

 

PyRun_SimpleString안의 파이썬 구문에서 spam 모듈이 정상적으로 임포트되고, 함수도 호출 되는 것을 있다.

  

 

Tip.

테스트는 리눅스에서 파이썬 3.1에서 진행했다. 파일을 컴파일 , 파이썬의 헤더 라이브러리 파일이 필요한데 아래처럼 간단하게 구할 있다.

 

cflags, ldflags 알아내는

$ /opt/bin/python3.2-config --cflags

$ /opt/bin/python3.2-config --ldflags

Posted by 평면우주