C++20 Modules 기초와 실전 활용
C++ 모듈은 40년 이상 사용된 #include 기반 헤더 시스템을 대체하는 새로운 코드 조직화 메커니즘입니다. 빌드 속도 향상, 매크로 격리, 명시적 인터페이스 정의 등 여러 장점을 제공합니다.
1. 헤더 파일의 문제점
섹션 제목: “1. 헤더 파일의 문제점”// 헤더 파일의 전통적 문제들#include <vector> // 전체 vector 구현 코드 복붙#include <string> // 다시 복붙// 컴파일 단위마다 반복, 빌드 시간 폭증
// 매크로 오염#define MAX_SIZE 100 // 전역으로 퍼짐모듈은 이를 해결합니다. 모듈 인터페이스는 한 번만 컴파일되고 바이너리 형태로 재사용됩니다.
2. 기본 문법
섹션 제목: “2. 기본 문법”2.1 모듈 인터페이스 단위 (.ixx 또는 .cppm)
섹션 제목: “2.1 모듈 인터페이스 단위 (.ixx 또는 .cppm)”export module math; // 모듈 선언
import <string>; // 표준 라이브러리 임포트 (모듈화된 경우)
// export: 외부에서 사용 가능export int add(int a, int b) { return a + b;}
export double pi = 3.14159265358979;
// export 없음: 모듈 내부에서만 사용static int helper(int x) { return x * 2;}2.2 모듈 사용
섹션 제목: “2.2 모듈 사용”import math; // 모듈 임포트#include <iostream> // 헤더와 혼용 가능
int main() { std::cout << add(3, 4) << "\n"; // 7 std::cout << pi << "\n"; // 3.14159... // helper(5); // 오류: export 되지 않음 return 0;}3. Export 상세
섹션 제목: “3. Export 상세”3.1 export 블록
섹션 제목: “3.1 export 블록”export module geometry;
export { struct Point { double x, y; }; struct Rect { Point tl, br; }; double area(const Rect& r);}
// 구현 (export 불필요)double area(const Rect& r) { return (r.br.x - r.tl.x) * (r.br.y - r.tl.y);}3.2 export import (재내보내기)
섹션 제목: “3.2 export import (재내보내기)”export module mylib;
export import math; // math 모듈의 export를 재내보냄export import geometry; // geometry도 재내보냄4. 모듈 파티션
섹션 제목: “4. 모듈 파티션”대형 모듈을 논리적 파티션으로 분할할 수 있습니다.
// engine-render.ixx (파티션)export module engine:render; // engine 모듈의 render 파티션
export void renderFrame();export void setResolution(int w, int h);
void renderFrame() { /* 구현 */ }void setResolution(int w, int h) { /* 구현 */ }export module engine:physics;
export void updatePhysics(float dt);
void updatePhysics(float dt) { /* 구현 */ }// engine.ixx (기본 모듈 인터페이스)export module engine;
export import :render; // 파티션 재내보내기export import :physics;import engine; // render, physics 모두 접근 가능
int main() { renderFrame(); updatePhysics(0.016f); return 0;}5. 구현 단위 (Module Implementation Unit)
섹션 제목: “5. 구현 단위 (Module Implementation Unit)”인터페이스와 구현을 분리할 수 있습니다.
// logger.ixx (인터페이스)export module logger;
export class Logger {public: void log(const char* msg); void warn(const char* msg); void error(const char* msg);};// logger.cpp (구현 단위)module logger; // export 없음 = 구현 단위
#include <cstdio>
void Logger::log(const char* msg) { std::printf("[LOG] %s\n", msg);}
void Logger::warn(const char* msg) { std::printf("[WARN] %s\n", msg);}
void Logger::error(const char* msg) { std::printf("[ERROR] %s\n", msg);}6. 헤더 단위 (Header Units)
섹션 제목: “6. 헤더 단위 (Header Units)”기존 헤더 파일을 모듈처럼 임포트할 수 있습니다.
// 헤더 단위로 임포트 (컴파일러 지원 필요)import <vector>;import <string>;import "my_legacy_header.h";이는 완전한 모듈은 아니지만 빌드 속도를 개선하는 중간 단계로 유용합니다.
7. 빌드 시스템 설정
섹션 제목: “7. 빌드 시스템 설정”CMake 3.28+
섹션 제목: “CMake 3.28+”cmake_minimum_required(VERSION 3.28)project(MyProject)
set(CMAKE_CXX_STANDARD 20)set(CMAKE_CXX_SCAN_FOR_MODULES ON)
add_executable(app main.cpp math.ixx geometry.ixx)MSVC (Visual Studio)
섹션 제목: “MSVC (Visual Studio)”cl /std:c++20 /experimental:module /interface math.ixxcl /std:c++20 /experimental:module main.cpp math.ixx.obj8. 점진적 마이그레이션 전략
섹션 제목: “8. 점진적 마이그레이션 전략”기존 코드베이스를 한 번에 모듈로 전환하는 것은 현실적이지 않습니다.
// 전략 1: 헤더 파일 래핑export module legacy;
// 기존 헤더를 global module fragment에 포함module; // global module fragment 시작#include "old_library.h" // 매크로, 전처리기 내용 포함 가능
export module legacy; // named module 시작
// old_library.h의 타입을 재내보내거나 래핑export using OldType = ::OldLibraryType;9. 헤더 vs 모듈 비교
섹션 제목: “9. 헤더 vs 모듈 비교”| 항목 | 헤더 파일 | 모듈 |
|---|---|---|
| 빌드 속도 | 파일마다 재파싱 | 한 번만 컴파일 |
| 매크로 격리 | 전역으로 누출 | 모듈 내부 격리 |
| 순환 의존성 | 문제 발생 | 명시적 오류 |
| include guard | 필요 | 불필요 |
| 도입 비용 | 없음 | 빌드 시스템 지원 필요 |
C++20 모듈은 C++ 빌드 시스템의 근본적인 개선을 가져옵니다. 컴파일 시간 단축, 명확한 인터페이스 정의, 매크로 오염 방지라는 세 가지 핵심 이점을 제공합니다. 2024년 기준으로 MSVC, GCC 15, Clang 16+ 모두 기본적인 모듈 지원을 제공하므로 새 프로젝트부터 점진적으로 도입해볼 것을 권장합니다.