Wrapping C/C++ for Python

김명섭·2024년 8월 24일

5가지 Wrapping 방법

1. Python C 확장 모듈

장점: 최고 수준의 성능, 세밀한 제어 가능
단점: 구현이 복잡, Python C API에 대한 깊은 이해 필요
적합한 경우: 극도로 높은 성능이 필요한 경우, 저수준 시스템 작업

예시 : 원래 extern "C" 를 해줘야 되지만, 현대 C++ 컴파일러들은 Python.h 헤더를 포함할 때, 자동으로C 링키지를 적용.

// module.cpp
#include <Python.h>
#include <cmath>

static PyObject* fast_tanh(PyObject* self, PyObject* args) {
    double x;
    if (!PyArg_ParseTuple(args, "d", &x))
        return NULL;
    double result = tanh(x);
    return PyFloat_FromDouble(result);
}

static PyMethodDef ModuleMethods[] = {
    {"fast_tanh", fast_tanh, METH_VARARGS, "Calculate tanh(x)"},
    {NULL, NULL, 0, NULL}
};

static struct PyModuleDef moduledef = {
    PyModuleDef_HEAD_INIT,
    "fastmath",
    NULL,
    -1,
    ModuleMethods
};

PyMODINIT_FUNC PyInit_fastmath(void) {
    return PyModule_Create(&moduledef);
}



// setup.py
from setuptools import setup, Extension

module = Extension('fastmath', sources=['module.cpp'])

setup(name='FastMath',
      version='1.0',
      description='Fast math operations',
      ext_modules=[module])

# 컴파일: python setup.py build_ext --inplace

# use_fastmath.py
import fastmath

result = fastmath.fast_tanh(1.5)
print(f"tanh(1.5) = {result}")

2. Pybind11

장점: 현대적 C++ 기능 지원, 사용이 비교적 간단
단점: C++11 이상 필요, 순수 C 프로젝트에는 부적합
적합한 경우: 현대적 C++ 프로젝트, 복잡한 C++ 클래스/템플릿 바인딩

// fastmath.cpp
#include <pybind11/pybind11.h>
#include <cmath>

namespace py = pybind11;

double fast_tanh(double x) {
    return tanh(x);
}

PYBIND11_MODULE(fastmath, m) {
    m.doc() = "Fast math operations using pybind11";
    m.def("fast_tanh", &fast_tanh, "Calculate tanh(x)");
}

// setup.py
from setuptools import setup, Extension
from pybind11.setup_helpers import Pybind11Extension, build_ext

ext_modules = [
    Pybind11Extension("fastmath",
        ["fastmath.cpp"],
    ),
]

setup(
    name="fastmath",
    ext_modules=ext_modules,
    cmdclass={"build_ext": build_ext},
)

# 컴파일: python setup.py build_ext --inplace

# use_fastmath.py
import fastmath

result = fastmath.fast_tanh(1.5)
print(f"tanh(1.5) = {result}")

3. Cython

장점: Python 코드 최적화 가능, Python과 유사한 문법
단점: Cython 특유의 문법 학습 필요, 컴파일 단계 필요
적합한 경우: Python 코드 성능 개선, 수치 계산 집약적 작업

# fastmath.pyx
cdef extern from "math.h":
    double tanh(double x)

def fast_tanh(double x):
    return tanh(x)

# setup.py
from setuptools import setup
from Cython.Build import cythonize

setup(
    name='FastMath',
    ext_modules=cythonize("fastmath.pyx"),
    zip_safe=False,
)

# 컴파일: python setup.py build_ext --inplace

# use_fastmath.py
import fastmath

result = fastmath.fast_tanh(1.5)
print(f"tanh(1.5) = {result}")

4. SWIG(Simplified Wrapper and Interface Generator)

장점: 여러 프로그래밍 언어 지원, 대규모 코드베이스에 적합
단점: 생성된 코드가 복잡할 수 있음, 세밀한 제어가 어려울 수 있음
적합한 경우: 여러 언어로의 바인딩이 필요한 경우, 대규모 C/C++ 라이브러리 래핑

// math_functions.h
#ifndef MATH_FUNCTIONS_H
#define MATH_FUNCTIONS_H

double fast_tanh(double x);

#endif

// math_functions.cpp
#include "math_functions.h"
#include <cmath>

double fast_tanh(double x) {
    return tanh(x);
}

// math_functions.i
%module math_functions
%{
#include "math_functions.h"
%}

double fast_tanh(double x);

// setup.py
from distutils.core import setup, Extension

math_functions_module = Extension('_math_functions',
                                  sources=['math_functions_wrap.cxx', 'math_functions.cpp'],
                                  )

setup(name='math_functions',
      version='0.1',
      ext_modules=[math_functions_module],
      py_modules=['math_functions'],
      )

# 컴파일:
# swig -python math_functions.i
# python setup.py build_ext --inplace

# use_math_functions.py
import math_functions

result = math_functions.fast_tanh(1.5)
print(f"tanh(1.5) = {result}")

5. Ctypes

장점: 순수 Python으로 구현, 추가 컴파일 불필요 (Python 코드 측면에서)
단점: C++에 제한적 지원, 복잡한 데이터 구조 처리 어려움
적합한 경우: 간단한 C 라이브러리 사용, 빠른 프로토타이핑
주의: C++을 사용할 때는 반드시 extern "C"가 필요

// mathlib.cpp
#include <cmath>

extern "C" {
    double fast_tanh(double x) {
        return tanh(x);
    }
}

// 컴파일 (Linux): g++ -shared -fPIC mathlib.cpp -o libmathlib.so
// 컴파일 (Windows): g++ -shared mathlib.cpp -o mathlib.dll

# use_mathlib.py
import ctypes
import os

# 운영 체제에 따라 적절한 라이브러리 파일 선택
if os.name == 'posix':
    lib = ctypes.CDLL('./libmathlib.so')
elif os.name == 'nt':
    lib = ctypes.CDLL('./mathlib.dll')
else:
    raise OSError("Unsupported operating system")

lib.fast_tanh.argtypes = [ctypes.c_double]
lib.fast_tanh.restype = ctypes.c_double

result = lib.fast_tanh(1.5)
print(f"tanh(1.5) = {result}")

선택 기준

프로젝트의 특정 요구사항 (성능, 유지보수성, 개발 속도 등)
개발 팀의 기술 스택과 경험
기존 코드베이스의 특성
장기적인 확장성 및 유지보수 계획
C vs C++ 사용 여부
타겟 플랫폼 (운영 체제, 하드웨어 등)

선택 기준별 순위

성능 중요도

Python C 확장 모듈
Cython / pybind11 (비슷한 수준)
SWIG
ctypes

개발 용이성

ctypes
pybind11
Cython
SWIG
Python C 확장 모듈

학습 곡선 (가장 쉬운 것부터)

ctypes
pybind11
SWIG
Cython
Python C 확장 모듈

유지보수 용이성

pybind11
Cython
SWIG
ctypes
Python C 확장 모듈

C++ 지원

pybind11
SWIG
Cython
Python C 확장 모듈
ctypes (제한적 지원)

프로젝트 규모 적합성 (대규모 프로젝트)

pybind11
SWIG
Cython
Python C 확장 모듈
ctypes

다중 언어 지원

SWIG
나머지 방법들 (Python에만 특화됨)

profile
ML Engineer

0개의 댓글