Notice
Recent Posts
Recent Comments
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Tags
more
Archives
Today
Total
관리 메뉴

웹프로그래밍

Pytthon embeddeding : 파이썬을 c언어에 내장하기 작업일지 2 - 인터렉티브 본문

프로그래밍일반

Pytthon embeddeding : 파이썬을 c언어에 내장하기 작업일지 2 - 인터렉티브

공부모드 2016. 7. 13. 05:09

'Pytthon embeddeding : 파이썬을 c언어에 내장하기 작업일지 1 - 모듈사용' 에 이어 이번에는 C,C++에서 직접 파이썬 모듈을 로드하여 전달인자와 함께 호출하고 리턴값을 받아오는 과정을 진행합니다.

이번에도 마찬가지로 제가 겪는 시행 착오와 이를 풀어가는 과정을 기록하겠습니다.
컴파일 옵션궁금하다면 이전 게시물을 참고하면 됩니다.

다음의 사이트에 소스 및 자세한 설명이 있으며 여기에서는 해당 사이트만 참고해서는 제대로 동작하지 않는 부분을 해결하는 과정만을 다룹니다.
http://docs.python.org/extending/embedding.html

1. C에서 파이선모듈을 전달인자와 함께 호출하여 리턴값을 받는 과정에 대해 열심히 공부한다음, 코드들을 각각 main.c multiple.py 로 저장하고 다음 명령으로 컴파일하면 무사히 컴파일 된다.
$ g++ main.cpp -I/usr/include/python2.6 -pthread -lm -ldl -lutil /usr/lib/libpython2.6.so

2. 하지만 다음의 전달인자들로 프로그램을 실행하면 원하는 결과를 얻을 수 없다.

$ ./a.out multiply multiply 3 2
ImportError: No module named multiply
Failed to load "multiply"

이전과 마찬가지로 파이썬 스크립트를 실행파일과 같은 디렉터리에 두었지만 모듈을 로드하지 못하였다.

3. 그래서 이전과 마찬가지로 main.cpp 에 다음 코드를 추가한다.

    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path");
    PyRun_SimpleString("sys.path.append('/root/work/Twitter/Python/embedding_test3')");

파란 부분은 작업 디렉터리의 위치 즉 로드할 모듈의 위치이다.

4. 컴파일해서 실행하면 원하는 결과를 얻을 수 있다.

 # ./a.out multiply multiply 3 2
Will compute 3 times 2
Result of call: 6

모듈의 위치를 추가하는 부분에 대해 언급이 없는 이유는 잘 모르겠다. 무언가 보다 근본적인 해결 방법이 있을 것 같은데...


소스분석

 ...생략
Py_Initialize();
pName = PyString_FromString(argv[1]);   //로드할 모듈의 이름을을 받아와서
/* Error checking of pName left out */
pModule = PyImport_Import(pName);       // 모듈을 로드
Py_DECREF(pName);                           // 참조횟수를 감소시킴

파이썬은 c언어처럼 malloc(), free(), 등으로 메모리를 관리하지 않고 레퍼런스카운터를 통해 메모리를 관리함. 카운터가 0이 되면 메모리가 해제됨. 자세한 사항은 다음을 참고
http://docs.python.org/extending/extending.html#refcounts
 // 프로그램을 다음과 같은 인자로 실행했다고 할 때 $ ./a.out multiply multiply 3 2   
if (pModule != NULL) {
        pFunc = PyObject_GetAttrString(pModule, argv[2]);    // 모듈에서 호출하려고 하는 함수의 레퍼런스를 pFunc 에 받아온다.
        /* pFunc is a new reference */

        if (pFunc && PyCallable_Check(pFunc)) {                 // 해당 함수가 호출 가능한지 검사한다.
            pArgs = PyTuple_New(argc - 3);                           // pArgs 에 5-3 갯수의 튜플을 생성한다
            for (i = 0; i < argc - 3; ++i) {
                pValue = PyInt_FromLong(atoi(argv[i + 3]));       // 3 과 2 를 차례로 pValue에 저장하여
                if (!pValue) {                                                  // 매계변수를 제대로 입력하지 않았다면 에러처리를 한다
                    Py_DECREF(pArgs);
                    Py_DECREF(pModule);
                    fprintf(stderr, "Cannot convert argument\n");
                    return 1;
                }
                /* pValue reference stolen here: */
                PyTuple_SetItem(pArgs, i, pValue);                   // 이상이 없다면 pArgs 의 튜플에 3 과 2 를 저장한다.
            }
            pValue = PyObject_CallObject(pFunc, pArgs);        // multi 함수에 전달인자를 주어 호출하고 리턴값을 pValue에 받아온다 
            Py_DECREF(pArgs);
            if (pValue != NULL) {
                printf("Result of call: %ld\n", PyInt_AsLong(pValue)); // 리턴값을 출력한다. PyInt_AsLong 은 파이썬자료형을 long형으로 리턴한다
                Py_DECREF(pValue);
            }
            else {
                Py_DECREF(pFunc);
                Py_DECREF(pModule);
                PyErr_Print();
                fprintf(stderr,"Call failed\n");
                return 1;
            }
        }
        else {
            if (PyErr_Occurred())
                PyErr_Print();
            fprintf(stderr, "Cannot find function \"%s\"\n", argv[2]);
        }
        Py_XDECREF(pFunc);
        Py_DECREF(pModule);
    }
    else {
        PyErr_Print();
        fprintf(stderr, "Failed to load \"%s\"\n", argv[1]);
        return 1;
    }
생략...



__



Comments