pybind11 + CMake + pyproject.toml로 파이썬 확장 모듈 세팅하기

C++로 작성한 고성능 코드나 라이브러리를 파이썬에서 손쉽게 호출하려면 확장 모듈(extension module)을 만들어 파이썬에 로드할 수 있어야 합니다. pybind11은 이러한 바인딩을 매우 간단하게 해주는 라이브러리이며, CMake를 이용하면 C++ 빌드 과정을 관리하고, pyproject.toml을 통해 현대적 파이썬 패키징 표준에 맞춰 배포까지 할 수 있습니다.

이 글에서는 다음과 같은 목표를 가집니다.

  • 간단한 C++ 함수(C++11 이상) 정의
  • pybind11로 파이썬 바인딩 코드 작성
  • CMakeLists.txt로 빌드 시스템 설정
  • pyproject.toml 이용해 빌드 백엔드와 메타데이터 정의 → pip install . 명령으로 파이썬 패키지 설치 가능하게 하기

사전 준비

  • Python 3.7 이상 권장
  • C++ 컴파일러(GCC, Clang, MSVC) 준비
  • CMake 설치 (3.12 이상 권장)
  • pybind11 설치 (pip로 의존성 관리 가능)
  • 파이썬 가상환경(Optional) 생성
python -m venv env
source env/bin/activate
pip install pybind11 build

여기서 pip install pybind11 build로 pybind11과 python -m build 패키지(표준 빌드도구) 설치.

디렉토리 구조 예시

my_cpp_extension/
  ├─ src/
  │    ├─ main.cpp
  │    └─ CMakeLists.txt
  ├─ pyproject.toml
  ├─ README.md
  └─ LICENSE
  • src/ 디렉토리에 C++ 소스 및 CMakeLists.txt 배치
  • 상위 디렉토리에 pyproject.toml, README, LICENSE 등 프로젝트 메타파일 배치

C++ 코드 및 pybind11 바인딩 예제

src/main.cpp:

#include <pybind11/pybind11.h>
#include <pybind11/complex.h>
#include <pybind11/stl.h>

namespace py = pybind11;

int add(int a, int b) {
    return a + b;
}

PYBIND11_MODULE(my_module, m) {
    m.doc() = "My C++ extension module using pybind11";
    m.def("add", &add, "A function that adds two integers");
}

설명:

  • PYBIND11_MODULE(my_module, m) 매크로로 my_module라는 모듈명 지정
  • m.def("add", &add)로 파이썬 add() 함수 등록
  • 이로써 파이썬에서 import my_module; my_module.add(3,4) 사용 가능

CMakeLists.txt 작성

src/CMakeLists.txt:

cmake_minimum_required(VERSION 3.12)
project(my_module CXX)

# pybind11 경로 설정
# pip install pybind11 로 설치 시, pybind11는 Python site-packages 내에 위치
# find_package(pybind11) 사용시 CMAKE_PREFIX_PATH를 pybind11 설치 경로로 설정 가능
# 여기서는 예제상 pybind11을 CMAKE_PREFIX_PATH 또는 환경변수 통해 찾는다고 가정
# 실제로는 "find_package(pybind11 CONFIG REQUIRED)" 명령 사용을 위해
# site-packages/pybind11/share/cmake/pybind11 경로를 CMAKE_PREFIX_PATH에 추가 필요.

find_package(pybind11 CONFIG REQUIRED) 
# pybind11::module pybind11::embed 등 타겟 제공

add_library(my_module MODULE main.cpp)
target_link_libraries(my_module PRIVATE pybind11::module)

# OS별 모듈 확장자 처리
# 파이썬 확장 모듈은 일반적으로 .so(Unix), .pyd(Windows)
# pybind11::module 타겟이 자동 처리하므로 추가 설정 불필요할 수도 있음.
set_target_properties(my_module PROPERTIES 
  PREFIX ""
  SUFFIX "${PYTHON_EXTENSION_SUFFIX}" # pybind11이 이 변수를 정의
)

# 빌드 결과를 상위 디렉토리로 배치해서 pyproject.toml 빌드와 통합
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/..)

중요 포인트:

  • find_package(pybind11 CONFIG REQUIRED)로 pybind11 CMake 설정을 가져옴
  • add_library(my_module MODULE main.cpp)로 공유 모듈 생성
  • my_module를 pybind11::module에 링크
  • PREFIX ""SUFFIX 설정으로 파이썬 확장 모듈 명칭 맞춤

빌드 시 my_module.so (Unix) 또는 my_module.pyd(Windows) 생성.

pyproject.toml 작성

상위 디렉토리 pyproject.toml:

[build-system]
requires = ["setuptools>=42", "wheel", "pybind11"]
build-backend = "setuptools.build_meta"

[project]
name = "my_module"
version = "0.1.0"
description = "A sample pybind11 + CMake + pyproject.toml project"
readme = "README.md"
license = "MIT"
authors = [{name="Alice", email="alice@example.com"}]
classifiers = [
  "Programming Language :: Python :: 3",
  "License :: OSI Approved :: MIT License"
]

dependencies = [
  # 여기에 추가 의존성 필요시 기재
]

[tool.setuptools]
# setuptools 빌드 백엔드 사용 시, 확장 모듈 빌드 관련 설정 필요할 수도 있음
# 하지만 여기서는 CMake 별도 호출 과정 필요
# pybind11 문서 참고: https://pybind11.readthedocs.io/

[tool.cmake-build-extension]
module = "my_module"
source-dir = "src"
# cmake-build-extension 패키지 사용 시,
# pyproject.toml내 설정으로 cmake 빌드 자동화 가능

여기서, setuptools.build_meta로 빌드 백엔드를 지정했지만, 단순히 setuptools alone으로 CMake 빌드를 자동화하기 어렵습니다. cmake-build-extension 등 추가 패키지를 이용하면 pyproject.toml를 통해 CMake 빌드 과정을 파이썬 빌드 파이프라인에 통합할 수 있습니다.

cmake-build-extension(https://github.com/diegoferigo/cmake-build-extension)와 같은 툴을 활용하면 pyproject.toml 내 [tool.cmake-build-extension] 섹션을 정의해 CMake 명령, 빌드 타입, CMake 옵션 등을 설정하고, pip install . 시 자동으로 CMake 빌드를 수행할 수 있습니다.

예를 들어:

[tool.cmake-build-extension]
module = "my_module"
source-dir = "src"
cmake-args = ["-DCMAKE_BUILD_TYPE=Release"]

이렇게 하면 pip install . 명령을 실행할 때 CMake를 호출해 빌드 후 확장 모듈을 site-packages에 배치합니다.

빌드 및 설치 테스트

pip install cmake-build-extension
pip install .

설치 완료 후 파이썬에서 테스트:

import my_module
print(my_module.add(3,4))  # 7 출력

성공적으로 C++ 함수를 파이썬에서 호출할 수 있게 되었습니다.

결론

  • pybind11 + CMake + pyproject.toml 조합으로 C++ 확장 모듈을 현대적이고 일관된 방식으로 빌드/배포 가능
  • pybind11로 파이썬 바인딩, CMake로 C++ 빌드 관리, pyproject.toml로 파이썬 빌드/설치 표준화
  • cmake-build-extension 등 추가 도구 활용 시 pip install .로 CMake 빌드 자동화 가능
  • 이 패턴으로 고성능 C++ 코드를 파이썬에서 손쉽게 이용하는 패키지 만들기 용이

이렇게 하면 C++과 파이썬을 융합한 프로젝트를 모던 파이썬 패키징 생태계와 seamlessly 결합하여 연구, 개발, 배포 파이프라인을 간소화할 수 있습니다.

반응형