[모던 CMake] Python 바인딩 프로젝트 구성과 설정

이번 글에서는 Python 바인딩 프로젝트를 CMake로 구성하고 설정하는 방법을 알아보겠습니다. C++로 작성된 라이브러리를 Python에서 사용할 수 있도록 바인딩하면 두 언어의 장점을 모두 활용할 수 있습니다. 이를 위해 다양한 라이브러리가 존재하며, 대표적으로 Boost.Python, pybind11, nanobind 등이 있습니다. 이 글에서는 특히 pybind11nanobind를 중심으로 설명하겠습니다.

Python 바인딩이란?

Python 바인딩은 C++로 구현된 코드를 Python에서 직접 호출할 수 있도록 연결해주는 기술입니다. 이를 통해 성능이 중요한 부분은 C++로 작성하고, 사용의 편의성은 Python으로 제공할 수 있습니다. 과학 계산, 게임 개발, 머신 러닝 등 다양한 분야에서 활용되고 있습니다.

주요 바인딩 라이브러리 소개

Boost.Python

  • Boost.Python은 Boost 라이브러리의 일부로, C++ 코드를 Python에 바인딩하기 위한 강력한 도구입니다.
  • 장점:
    • 다양한 기능과 유연성 제공
    • Boost의 다른 라이브러리와 통합 용이
  • 단점:
    • 상대적으로 복잡한 문법
    • 컴파일 시간이 길고, 종속성이 많음

pybind11

  • pybind11은 Boost.Python의 경량 대안으로, 현대적인 C++11/14 문법을 활용하여 간결한 바인딩 코드를 작성할 수 있습니다.
  • 장점:
    • 간단하고 직관적인 문법
    • 컴파일 시간이 짧고, 종속성이 적음
  • 단점:
    • 일부 고급 기능은 Boost.Python에 비해 제한적

nanobind

  • nanobind는 pybind11의 아이디어를 기반으로 더욱 경량화한 라이브러리로, 효율성과 메모리 사용량에 초점을 맞추고 있습니다.
  • 장점:
    • 매우 작은 바이너리 크기
    • 빠른 컴파일 시간
  • 단점:
    • 상대적으로 새로운 프로젝트로, 문서와 커뮤니티 지원이 제한적일 수 있음

pybind11을 사용한 프로젝트 구성

프로젝트 디렉토리 구조

my_project/
├── CMakeLists.txt
├── src/
│   ├── CMakeLists.txt
│   └── mymodule.cpp
└── include/
    └── mymodule.h

최상위 CMakeLists.txt

cmake_minimum_required(VERSION 3.15)
project(MyPybindProject)

add_subdirectory(src)

src/CMakeLists.txt

# pybind11 패키지 찾기
find_package(pybind11 REQUIRED)

# 모듈 생성
pybind11_add_module(mymodule mymodule.cpp)

# 필요한 경우 include 디렉토리 추가
target_include_directories(mymodule PRIVATE ${CMAKE_SOURCE_DIR}/include)

mymodule.cpp 예제

#include <pybind11/pybind11.h>

int add(int i, int j) {
    return i + j;
}

PYBIND11_MODULE(mymodule, m) {
    m.doc() = "pybind11 example module";

    m.def("add", &add, "A function which adds two numbers");
}

빌드 및 설치

mkdir build
cd build
cmake ..
make

빌드 후 생성된 mymodule 모듈을 Python에서 사용할 수 있습니다.

Python에서 사용 예시

import mymodule

result = mymodule.add(1, 2)
print(result)  # 출력: 3

nanobind를 사용한 프로젝트 구성

프로젝트 디렉토리 구조

my_project/
├── CMakeLists.txt
├── src/
│   ├── CMakeLists.txt
│   └── mymodule.cpp
└── include/
    └── mymodule.h

최상위 CMakeLists.txt

cmake_minimum_required(VERSION 3.15)
project(MyNanobindProject)

add_subdirectory(src)

nanobind 가져오기

nanobind는 FetchContent를 통해 가져올 수 있습니다.

include(FetchContent)

FetchContent_Declare(
  nanobind
  GIT_REPOSITORY https://github.com/wjakob/nanobind.git
  GIT_TAG v1.2.0
)

FetchContent_MakeAvailable(nanobind)

src/CMakeLists.txt

# nanobind 디렉토리 설정
set(nanobind_DIR ${nanobind_SOURCE_DIR})

# 모듈 생성
add_library(mymodule MODULE mymodule.cpp)

# nanobind 및 Python 라이브러리 링크
target_link_libraries(mymodule PRIVATE nanobind::nanobind)

# 확장자 설정 (플랫폼에 따라 다를 수 있음)
set_target_properties(mymodule PROPERTIES PREFIX "" SUFFIX ".so")

mymodule.cpp 예제

#include <nanobind/nanobind.h>

namespace nb = nanobind;

int add(int i, int j) {
    return i + j;
}

NB_MODULE(mymodule, m) {
    m.doc() = "nanobind example module";

    m.def("add", &add, "A function which adds two numbers");
}

빌드 및 설치

mkdir build
cd build
cmake ..
make

빌드 후 생성된 mymodule 모듈을 Python에서 사용할 수 있습니다.

Python에서 사용 예시

import mymodule

result = mymodule.add(1, 2)
print(result)  # 출력: 3

pybind11과 nanobind 비교

특징 pybind11 nanobind

문법 직관적이고 간결함 pybind11과 유사한 문법
컴파일 시간 빠름 매우 빠름
바이너리 크기 작음 더 작음
기능 지원 다양한 기능과 광범위한 지원 핵심 기능에 초점
문서 및 커뮤니티 풍부한 문서와 활발한 커뮤니티 상대적으로 제한적
종속성 최소화 최소화
  • pybind11은 사용하기 쉽고 문서와 예제가 풍부하여 시작하기에 적합합니다.
  • nanobind는 성능과 바이너리 크기에 민감한 프로젝트에 유리하지만, 상대적으로 새로운 프로젝트입니다.

프로젝트 구성 시 고려사항

  • Python 버전 호환성: 사용하는 Python 버전에 맞는 라이브러리를 선택하고, CMake 설정에서 Python 해더와 라이브러리를 정확하게 참조해야 합니다.
  • 컴파일러 지원: pybind11과 nanobind 모두 C++11 이상을 요구하므로, 컴파일러가 해당 표준을 지원하는지 확인해야 합니다.
  • 배포 전략: 빌드된 모듈을 어떻게 배포할지 계획해야 합니다. 예를 들어, setuptools와 scikit-build를 사용하여 Python 패키지로 배포할 수 있습니다.

CMake 설정 추가사항

C++ 표준 설정

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

빌드 타입 설정

if(NOT CMAKE_BUILD_TYPE)
  set(CMAKE_BUILD_TYPE Release)
endif()

플랫폼별 설정

플랫폼에 따라 모듈 확장자가 다를 수 있으므로, 이를 설정해야 합니다.

if(WIN32)
  set(EXTENSION ".pyd")
else()
  set(EXTENSION ".so")
endif()

set_target_properties(mymodule PROPERTIES PREFIX "" SUFFIX ${EXTENSION})

결론

이번 글에서는 Python 바인딩 프로젝트를 CMake로 구성하고 설정하는 방법을 알아보았습니다. pybind11nanobind를 사용하여 C++ 코드를 Python에서 사용할 수 있도록 바인딩하는 방법을 살펴보았으며, 각 라이브러리의 특징과 사용 방법을 비교했습니다.

반응형