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 진행이 가능하다.
Append module path
- PYTHONPATH and embedding python
 - Stackoverflow - Is it possible to modify PYTHONPATH at runtime?
 - Stackoverflow - Embedding Python in C: Having problems importing local modules
 
#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포팅 라이브러리는 아래와 같다.
- Boost.Python
 - pybind11: https://pybind11.readthedocs.io/en/latest/
 - python2cpp: https://github.com/nicodjimenez/python2cpp
 - SWIG
 
See also
- Python
 - Cv::Mat:Python: cv::Mat와 OpenCV-Python에서 사용하는 NumPy Array와 호환 시키는 방법.
 - HPy - 파이썬을 위한 더 나은 C API
 
Favorite site
- 1. Extending Python with C or C++
 - [추천] ChangwooWiki - Embedded Python 1
 - [추천] EmbeddingPythonTutorial
 - [추천] Coding Patterns for Python Extensions
 - CodeProject: Embedding Python in C/C++: Part I
 - [추천] Reference Counting in Python 2
 - Embedding Python – Tutorial – Part 1 3
 - Joohyun's BLOG :: Boost Python 환경 구축 및 사용예제(Visual Studio 2013 Express 사용)
 - [추천] eunguru - C/C++와 연동 4
 
Tutorials
- Python embedding 1 - Overview 5
 - Python embedding 2 - Calling Python function from C/C++ Appilcation 6
 - Python embedding 3 - 캐싱 된 모듈 다시 로드 하기 7
 - Python embedding 4 - PyErr_Print() 를 파일로 남기기 8
 
Guide
Article
- [추천] 파이썬이 메모리를 관리하는 방법 10
 
Documentation Python 3.x
Documentation Python 2.x
- 5. Embedding Python in Another Application
 - Documentation » Python/C API Reference Manual » Abstract Objects Layer » Object Protocol
 - 1.2.1.1 Reference Count Details
 
References
-  
ChangwooWiki_-_Embedded_Python.pdf ↩
 -  
Reference_Counting_in_Python.pdf ↩
 -  
Embedding_Python_-Tutorial-Part_1-_realmike.pdf ↩
 -  
Eunguru.tistory.com_-_python_and_cpp.pdf ↩
 -  
Python_embedding_1.pdf ↩
 -  
Python_embedding_2.pdf ↩
 -  
Python_embedding_3.pdf ↩
 -  
Python_embedding_4.pdf ↩
 -  
Gpg_python_script.pdf ↩
 -  
How_Python_manages_memory_-_seonghyeon.dev.pdf ↩