Python 모듈을 C에서 import 하기
: 이 내용은 Python으로 개발된 모듈들을 C에서 자유자재로 이용하기 위해서 사용해야할 API 들과 그 전반에 대한 개발 가이드이다.
파일의 구성
: 이 Sample App은 크게 3개의 함수들로 구성하였다.
첫 번째로는, string을 인자로 받아 string을 반환하는 make_string
함수.
두 번째로는, int를 인자로 받아 int를 반환하는 make_int
함수.
마지막으로는, list 타입을 반환하는 make_list
함수이다.
파일의 구조는 다음과 같이 구성하였다.
jay@ ~/Desktop/tutorial/embedded-python $ tree .
.
├── bin
├── scripts
│ ├── __init__.py
│ └── my_module.py
└── src
└── main.cpp
my_module.py
파일은 다음의 함수들로 구성된다.
def make_string(param):
return "my_string: " + param
def make_int(param):
return (1 + param)
def make_list():
return ["1", "2", "3"]
main.cpp
파일은 다음의 함수들로 구성된다.
#include <Python.h>
void initialize(char* module_name, PyObject **pModule)
{
Py_Initialize();
PyObject *pName = PyUnicode_DecodeFSDefault(module_name);
*pModule = PyImport_Import(pName);
Py_DECREF(pName);
}
void finalize(PyObject *pModule)
{
Py_DECREF(pModule);
Py_FinalizeEx();
}
void make_string(PyObject *pModule, char *arg)
{
PyObject *pFunc, *pArgs, *pValue;
pFunc = PyObject_GetAttrString(pModule, "make_string");
pArgs = PyTuple_New(1);
PyTuple_SetItem(pArgs, 0, PyUnicode_FromString(arg));
pValue = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
printf("Result of call: %s \n", PyUnicode_AsUTF8(pValue));
Py_DECREF(pValue);
Py_DECREF(pFunc);
}
void make_int(PyObject *pModule, int arg)
{
PyObject *pFunc, *pArgs, *pValue;
pFunc = PyObject_GetAttrString(pModule, "make_int");
pArgs = PyTuple_New(1);
PyTuple_SetItem(pArgs, 0, PyLong_FromLong(arg));
pValue = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
printf("Result of call: %d \n", PyLong_AsLong(pValue));
Py_DECREF(pValue);
Py_DECREF(pFunc);
}
void make_list(PyObject *pModule)
{
PyObject *pFunc, *pArgs, *pValue;
pFunc = PyObject_GetAttrString(pModule, "make_list");
pValue = PyObject_CallObject(pFunc, NULL);
printf("Result of call: \n");
for (int i = 0; i < PyList_Size(pValue); ++i)
{
printf("\t%dst item: %s \n", i, PyUnicode_AsUTF8(PyList_GetItem(pValue, i)));
}
Py_DECREF(pValue);
Py_DECREF(pFunc);
}
int main(int argc, char *argv[])
{
PyObject *pName, *pModule, *pFunc;
PyObject *pArgs, *pValue;
int i;
initialize(argv[1], &pModule);
make_string(pModule, "Hello World!");
make_int(pModule, 99);
make_list(pModule);
finalize(pModule);
return 0;
}
여기서 __init__.py
파일은 아무런 내용을 기입하지 않아도 상관없으므로, 실행을 위해서 단순히 파일만 만들어 놓자.
빌드 및 실행
: 빌드는 다음과 같은 명령어로 빌드할 수 있다.
jay@ ~/Desktop/tutorial/embedded-python $ gcc -o ./bin/main -I/usr/local/include/python3.7m ./src/main.cpp -L/usr/local/lib -lpython3.7m -lpthread -ldl -lutil -lm -Xlinker -export-dynamic
빌드 후 산출물을 가지고 실행하면 아래의 결과를 얻을 수 있을 것이다.
jay@ ~/Desktop/tutorial/embedded-python $ PYTHONPATH=. ./bin/main scripts.my_module
Result of call: my_string: Hello World!
Result of call: 100
Result of call:
0st item: 1
1st item: 2
2st item: 3
실행 중 발생되는 오류
- No module named pyfunction
ImportError: No module named pyfunction
$ PYTHONPATH=. ./main blah blah
을 통해 모듈의 위치를 찾는 경로에 현재 위치를 추가해 준다.
- reference undefined to "Py_Initialize", undefined referecne to 'log'
reference undefined to "Py_Initialize"
reference undefined to "PyRun_SimpleStringFlags"
reference undefined to "Py_Finalize"
collect2: error: ld returned 1 exit status
/Python-3.7.0/Objects/longobject.c:2287: undefined reference to `log'
/Python-3.7.0/Objects/floatobject.c:788: undefined reference to `pow'
/Python-3.7.0/Objects/floatobject.c:753: undefined reference to `floor'
/Python-3.7.0/Objects/floatobject.c:764: undefined reference to `fmod'
collect2: error: ld returned 1 exit status
-
$ python3-config --ldflags
수행 후 나타나는 결과를 gcc 옵션에 넣어준다.
-
위의 해결방법으로 되지 않는다면, $ pkg-config --cflags --libs python3
수행 후 나타나는 결과를 gcc 옵션에 넣어준다. 본인은 위 방법으로 해결되었음.
- Python.h: No such file or directory
fatal error: Python.h: No such file or directory
compilation terminated.
$ sudo apt install libpython3-dev
를 통해 Python 개발 관련 헤더파일을 설치해 준다.
- No module named 'BlahBlah'
ModuleNotFoundError: No module named 'BlahBlah'
Python2 에서 Python3로 변경시 유의해야 할 점
아래의 참고자료 중 Python2 to Python3 Porting Guide
를 보면 자세한 설명과 그 이유를 알 수 있으니 해당 문서를 참고하길 바랍니다.
: 추후 업데이트 예정
참고자료
[Ofiicial] Embedding Python Application
Python/C API Reference Manual
Python/C API Unicode Objects and Codecs
Python/C API List Objects
Python2 to Python3 Porting Guide
NLTK install guide
stackoverflow - No module name
stackoverflow - Python.h: No such file or directory