본문 바로가기

dev_AI_framework

"CUDA" + "C++" + "pybind11" 모듈의 빌드 방법 및 과정, 체크리스트 확인

0) 큰그림: 파일 → 컴파일 → 링크 → .pyd → wheel → 설치

  1. 소스: *.cpp, *.cu (+ 헤더들)
  2. 컴파일
    • C++ 소스(.cpp) → MSVC(cl.exe) 가 .obj 생성
    • CUDA 소스(.cu) → NVCC가 호스트컴파일러(MSVC)를 호출해서 .obj 생성
    • .cu가 여러 개면 Device Linking(Relocatable Device Code) 단계가 들어감
  3. 링크: 모든 .obj + 외부 라이브러리(cudart, cublas 등) → 하나의 DLL 생성
    • 파이썬 확장 모듈이면 윈도우 확장자 = .pyd (사실상 DLL)
  4. 패키징: .pyd를 wheel 안에 넣어 .whl 생성
  5. 설치/import: pip install .whl → site-packages에 복사 → import 모듈명 동작

포인트: 모듈명(=import 이름)은 C++의 PYBIND11_MODULE(<이름>, m) 으로 결정. wheel의 패키지명(name=)과는 별개!

 

1) 각 파일의 “역할”

pyproject.toml (Python 빌드의 “메타+드라이버”)

  • “내 프로젝트는 CMake + scikit-build-core로 빌드할 거야”를 pip에게 알려줌.
  • python -m build나 pip install . 할 때 빌드 백엔드로 CMake를 실행해 wheel을 만들어 줌.
[build-system]
requires = ["scikit-build-core>=0.9", "pybind11>=2.12"]
build-backend = "scikit_build_core.build"

[project]
name = "graph-executor-v2"      # pip에서 보이는 배포명 (하이픈 가능)
version = "0.0.1"
requires-python = ">=3.12"

 

CMakeLists.txt (C++/CUDA 빌드 “설정서”)

  • 무슨 소스를 어떤 옵션으로 컴파일/링크할지 기술.
  • NVCC/CL 세부 옵션, 아키텍처, 링크 라이브러리, 출력물 이름 등을 정의.
  • install(TARGETS ...)로 wheel에 담을 결과물을 지정.

주요 포인트:

  • project(... LANGUAGES CXX CUDA) : CUDA 사용 선언
  • pybind11_add_module(<모듈명> MODULE srcs...) : pybind11 파이썬 모듈 타깃 생성
  • CMAKE_CUDA_ARCHITECTURES : GPU 아키텍처 지정(예: 86 = Ampere)
  • CUDA_SEPARABLE_COMPILATION ON : 여러 .cu의 device linking 자동 처리
  • target_link_libraries(... CUDA::cudart CUDA::cublas ...) : CUDA 런타임/라이브러리 연결
  • install(TARGETS ...) : wheel에 포함 지시
cmake_minimum_required(VERSION 3.26)
project(graph_executor_v2 LANGUAGES CXX CUDA)

find_package(Python 3.12 COMPONENTS Interpreter Development.Module REQUIRED)
find_package(pybind11 CONFIG REQUIRED)
find_package(CUDAToolkit REQUIRED)

# GPU 아키텍처(여러개면 세미콜론 구분: 75;86;89;90)
set(CMAKE_CUDA_ARCHITECTURES 86)

set(SRC
  src/bindings_min_api.cpp      # PYBIND11_MODULE(graph_executor_v2, m) 있어야 함
  src/launch_table.cpp
  src/my_kernels.cu
)

# 파이썬 모듈 타깃 생성 (.pyd 결과)
pybind11_add_module(graph_executor_v2 MODULE ${SRC})

# C++/CUDA 표준 및 분리컴파일
target_compile_features(graph_executor_v2 PRIVATE cxx_std_17)
set_target_properties(graph_executor_v2 PROPERTIES
  CUDA_STANDARD 17
  CUDA_SEPARABLE_COMPILATION ON
  POSITION_INDEPENDENT_CODE ON
  OUTPUT_NAME "graph_executor_v2"         # 최종 모듈 이름 고정
)

# 컴파일 옵션 (MSVC/Windows)
if (MSVC)
  target_compile_options(graph_executor_v2 PRIVATE
    $<$<COMPILE_LANGUAGE:CXX>:/bigobj;/W3;/EHsc;/O2;/MD>
  )
endif()

# CUDA 전용으로 호스트컴파일러 옵션 넘길 때는 -Xcompiler 사용
target_compile_options(graph_executor_v2 PRIVATE
  $<$<COMPILE_LANGUAGE:CUDA>:-Xcompiler=/EHsc;-Xcompiler=/O2;-Xcompiler=/MD>
)

# 링크할 CUDA 라이브러리
# cudart는 정적으로 링크하고 싶다면 아래 주석 해제:
# set_target_properties(graph_executor_v2 PROPERTIES CUDA_RUNTIME_LIBRARY Static)
target_link_libraries(graph_executor_v2 PRIVATE
  CUDA::cudart
  CUDA::cublas
  # CUDA::cublasLt  # 필요 시
)

target_include_directories(graph_executor_v2 PRIVATE
  ${CUDAToolkit_INCLUDE_DIRS}
  include
)

# wheel에 담으려면 install이 매우 중요!
install(TARGETS graph_executor_v2
        LIBRARY DESTINATION .
        RUNTIME DESTINATION .
        ARCHIVE DESTINATION .)

 

2) 빌드/설치 “실행 흐름”

A. 개발/빌드 전제

  • Windows: Python 3.12, Visual Studio Build Tools 2022 (C++ 툴셋), CUDA Toolkit 12.x
  • 환경변수: CUDA_PATH 설정되어 있고, PATH에 %CUDA_PATH%\bin 포함 권장
# 프로젝트 폴더: dev/backend/graph_executor_v2
python -m pip install -U pip scikit-build-core pybind11

# 과거 캐시가 섞여 있으면 정리
Remove-Item -Recurse -Force _skbuild, build, dist  -ErrorAction SilentlyContinue

# wheel/sdist 생성
python -m build

# 설치(개발 반복 용이라면 -e . 도 가능)
python -m pip install --force-reinstall dist\graph_executor_v2-0.0.1-cp312-cp312-win_amd64.whl

 

3) NVCC/링킹에 대한 핵심 개념 (윈도우 기준 요약)

  • NVCC는 메타 드라이버: .cu를 컴파일할 때 내부적으로 MSVC를 호출.
  • Device Linking: .cu가 여러 개고 서로 __device__ 심볼을 참조하면 분리 컴파일 + 장치 링킹이 필요.
    • CMake에선 CUDA_SEPARABLE_COMPILATION ON이면 자동 처리.
  • 런타임 DLL: 보통 cudart64_12.dll, cublas64_12.dll 등이 실행 시 PATH에 있어야 import 성공.
    • Python 3.8+에선 os.add_dll_directory(os.path.join(os.environ["CUDA_PATH"], "bin")) 권장.
    • cudart를 정적 링크하면 그 DLL의존 하나 줄일 수 있지만, cuBLAS는 여전히 DLL 필요.
  • /MD vs /MT: 파이썬/pybind11은 기본적으로 /MD 런타임을 가정(권장).
  • 모듈명 일치:
    • PYBIND11_MODULE(graph_executor_v2, m)
    • pybind11_add_module(graph_executor_v2 ...)
    • 최종 .pyd가 graph_executor_v2.cp312-win_amd64.pyd 로 나와야 import graph_executor_v2가 됨.
    • wheel의 name="graph-executor-v2"는 pip 패키지명일 뿐, import 이름과 무관.

 

4) 체크리스트 (실무용)

  • VS Build Tools 2022 + CUDA Toolkit 설치/버전 확인
  • pyproject.toml에 scikit-build-core, pybind11 지정
  • CMakeLists.txt에
    • pybind11_add_module(graph_executor_v2 ...)
    • set(CMAKE_CUDA_ARCHITECTURES 86) (GPU 맞게)
    • CUDA_SEPARABLE_COMPILATION ON
    • target_link_libraries(... CUDA::cudart CUDA::cublas)
    • install(TARGETS graph_executor_v2 DESTINATION .)
  • PYBIND11_MODULE(graph_executor_v2, m) 이름 일치
  • python -m build 로 wheel 생성
  • pip install dist\...whl
  • import graph_executor_v2; print(__file__)로 경로 확인
  • 실행 스크립트에서 ensure_cuda_dlls() 1회 호출