Skip to content

CPython

Hello world

#include <Python.h>

int main(int argc, char** argv)
{
  Py_SetProgramName(argv[0]);
  Py_Initialize();
  PyRun_SimpleString("print \'Hello, World!\'\n");
  Py_Finalize();
  return 0;
}

Windows의 경우 확장자를 *.dll가 아닌 *.pyd로 해야 한다.

Call Function

#include <Python.h>

int main(int argc, char** argv)
{
    int i;
    PyObject *pModule, *pFunc;
    PyObject *pArgs, *pValue;

    if (argc < 3) {
        fprintf(stderr, "Usage: call.out pythonfile function [args]\n");
        return 1;
    }

    Py_SetProgramName(argv[0]);
    Py_Initialize();

    /* modified part */
    PyRun_SimpleString(
            "import sys\n"
            "sys.path.append('.')\n");
    pModule = PyImport_ImportModule(argv[1]);

    pFunc = PyObject_GetAttrString(pModule, argv[2]);
    pArgs = PyTuple_New(argc - 3); 

    for(i = 0; i < argc - 3; ++i) {
        pValue = PyInt_FromLong(atoi(argv[i+3]));
        PyTuple_SetItem(pArgs, i, pValue);
    }

    pValue = PyObject_CallObject(pFunc, pArgs);
    printf("Result of call: %ld\n", PyInt_AsLong(pValue));
    Py_DECREF(pArgs);
    Py_DECREF(pValue);
    Py_DECREF(pFunc);
    Py_DECREF(pModule);

    Py_Finalize();
    return 0;
}

Create Module

// Pulls in the Python API
#include <Python.h>

static PyObject * spam_system(PyObject *self, PyObject *args) {

    /*
        PyObject *self: Only be used if building a class method, this would be NULL since it's not a method.
        PyObject *args: Pointer to a Python tuple object containing the arguments it'll be passed.

        Python expression to be run: spam.system(string)
    */

    const char *command;
    int sts;

    /*
        PyArg_ParseTuple: Returns true if all arguments have the right type (and raises appropriate exception otherwise)

        "s": Convert a Python string to a C pointer to a character string. 
        See: http://www.fnal.gov/docs/products/python/v1_5_2/ext/parseTuple.html

    */
    if (! PyArg_ParseTuple(args, "s", &command)) {
        return NULL;
    }

    // C command
    // See: http://www.thinkage.ca/english/gcos/expl/c/lib/system.html
    sts = system(command);

    /*
        Reverse of ParseTuple, converts it back to something Python
        "i" is an integer; system() returns an int

        See: http://www.fnal.gov/docs/products/python/v1_5_2/ext/buildValue.html
    */
    return Py_BuildValue("i", sts);
}

// Module's method table and initialization function
// See: http://docs.python.org/extending/extending.html#the-module-s-method-table-and-initialization-function
static PyMethodDef SpamMethods[] = {
    {"system", spam_system, METH_VARARGS, "Execute a shell command."},
    {NULL, NULL, 0, NULL}
};

void initspam(void) {
    // Module's initialization function
    // Will be called again if you use Python's reload()

    PyImport_AddModule("spam");
    Py_InitModule("spam", SpamMethods);
}

int main(int argc, char *argv[]) {
    Py_SetProgramName(argv[0]);
    Py_Initialize();
    initspam();
    return 0;
}

setup.py를 작성한다.

from distutils.core import setup, Extension
ext = Extension('spam', sources=['spammodule.c'])
setup(name='foo', version='1.0', description='Test description', ext_modules=[ext])

아래와 같이 BUILD & INSTALL 진행이 가능하다.

$ python setup.py build
$ python setup.py install

Append module path

#include "Python.h"
int main()
{
  Py_Initialize();
  PyRun_SimpleString("import sys");
  PyRun_SimpleString("sys.path.append(\"<some_path>\")");
  return 0;
}

위 방법은 추가되는 문자열이 Encoding에 영향을 받는다.

Python스크립트 없이 C함수로 적용하는 방법은 아래와 같다.

std::string NEW_PATH = std::string(Py_GetPath()) + PATH_SPLITTER + path;
PySys_SetPath(&NEW_PATH[0]);

이 방법은 정상적으로 적용되지 않는다.

PyObject * sys_module = PyImport_ImportModule("sys");
PyObject * python_path = PyObject_GetAttrString(sys_module, "path");

/* Unicode: */ PyList_Append(python_path, PyUnicode_FromString("."));
// OR:
/* C String: */ PyList_Append(python_path, PyString_FromString(path.c_str()));

Python interpreter code

/* Minimal main program -- everything is loaded from the library */

#include "Python.h"
#include <locale.h>

#ifdef __FreeBSD__
#include <fenv.h>
#endif

#ifdef MS_WINDOWS
int
wmain(int argc, wchar_t **argv)
{
    return Py_Main(argc, argv);
}
#else

int
main(int argc, char **argv)
{
    wchar_t **argv_copy;
    /* We need a second copy, as Python might modify the first one. */
    wchar_t **argv_copy2;
    int i, res;
    char *oldloc;

    /* Force malloc() allocator to bootstrap Python */
    (void)_PyMem_SetupAllocators("malloc");

    argv_copy = (wchar_t **)PyMem_RawMalloc(sizeof(wchar_t*) * (argc+1));
    argv_copy2 = (wchar_t **)PyMem_RawMalloc(sizeof(wchar_t*) * (argc+1));
    if (!argv_copy || !argv_copy2) {
        fprintf(stderr, "out of memory\n");
        return 1;
    }

    /* 754 requires that FP exceptions run in "no stop" mode by default,
     * and until C vendors implement C99's ways to control FP exceptions,
     * Python requires non-stop mode.  Alas, some platforms enable FP
     * exceptions by default.  Here we disable them.
     */
#ifdef __FreeBSD__
    fedisableexcept(FE_OVERFLOW);
#endif

    oldloc = _PyMem_RawStrdup(setlocale(LC_ALL, NULL));
    if (!oldloc) {
        fprintf(stderr, "out of memory\n");
        return 1;
    }

    setlocale(LC_ALL, "");
    for (i = 0; i < argc; i++) {
        argv_copy[i] = Py_DecodeLocale(argv[i], NULL);
        if (!argv_copy[i]) {
            PyMem_RawFree(oldloc);
            fprintf(stderr, "Fatal Python error: "
                            "unable to decode the command line argument #%i\n",
                            i + 1);
            return 1;
        }
        argv_copy2[i] = argv_copy[i];
    }
    argv_copy2[argc] = argv_copy[argc] = NULL;

    setlocale(LC_ALL, oldloc);
    PyMem_RawFree(oldloc);

    res = Py_Main(argc, argv_copy);

    /* Force again malloc() allocator to release memory blocks allocated
       before Py_Main() */
    (void)_PyMem_SetupAllocators("malloc");

    for (i = 0; i < argc; i++) {
        PyMem_RawFree(argv_copy2[i]);
    }
    PyMem_RawFree(argv_copy);
    PyMem_RawFree(argv_copy2);
    return res;
}
#endif

Multiprocessing Tip

Libraries

C/C++을 사용한 Python포팅 라이브러리는 아래와 같다.

See also

Favorite site

Tutorials

Guide

Article

Documentation Python 3.x

Documentation Python 2.x

References


  1. ChangwooWiki_-_Embedded_Python.pdf 

  2. Reference_Counting_in_Python.pdf 

  3. Embedding_Python_-Tutorial-Part_1-_realmike.pdf 

  4. Eunguru.tistory.com_-_python_and_cpp.pdf 

  5. Python_embedding_1.pdf 

  6. Python_embedding_2.pdf 

  7. Python_embedding_3.pdf 

  8. Python_embedding_4.pdf 

  9. Gpg_python_script.pdf 

  10. How_Python_manages_memory_-_seonghyeon.dev.pdf