C++의 modules
와 static polymorphism
에 관심이 생겼다. 이 글에서는 그 중 modules
를 살펴본 후 import std;
를 사용하기 위한 과정과 거기서 얻은 인사이트를 다룬다.
정적 다형성은 다음 포스트에서..
전처리 과정에서 파일의 내용을 그대로 복사하기 때문에 여러 가지 문제가 발생한다.
문제를 해결하기 위해 include guard나 PCH(Precompiled Header) 같이 별도의 처리가 필요
modules의 장점은:
1. 한 번만 로드: 중복 포함 방지
2. 매크로 충돌 방지: 동일한 매크로가 있는 두 헤더를 포함할 때, 순서에 따라 값이 달라지는 문제 해결
3. 순서 독립적: 모듈은 포함 순서에 영향 받지 않음
4. 불필요한 의존성 제거: 직접 참조하는 모듈만 알면 됨
그리고 헤더와 소스를 나눌 필요가 없다. 파일을 복사하는 방식은 컴파일 시간을 단축하기 위해서 분리가 필요했지만, 컴파일러는 export
로 명시한 모듈의 인터페이스와 구현을 구분한다. 따라서 코드를 분리하여 복잡하게 만들필요가 없다.
파일 분리가 필요 없어진 상황에서 어떻게 가독성을 높일지 고민 할만한 것 같다.
module
,import
, export
키워드를 통해서 모듈을 사용할 수 있다.
// Vector.cpp
export module Vector;
export class Vector {
public:
explicit Vector(int s);
double &operator[](int i) const;
private:
double *elem;
int elemSize;
};
// 구현 부분 ...
// main.cpp
import Vector;
int main() {
import std;
는 표준 라이브러리의 모듈 인터페이스를 가져온다. 하지만 clang c++23 환경에서는 제대로 지원을 하지 않았다.
#include <iostrema>
한 후 export를 하려고 했다.export std::cout
개별로 export 하는 것만 동작해서 실패clang에서는 불가능한 것인가 생각하던 찰나 cmake를 사용하는 방법을 찾았다.Clion how to enable std module support?
CmakeList.txt
를 다음 글을 보고 수정했다.
cmake_minimum_required(VERSION 3.30)
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD
# This specific value changes as experimental support evolves. See
# `Help/dev/experimental.rst` in the CMake source corresponding to
# your CMake build for the exact value to use.
"0e5b6991-d74f-4b3d-a41c-cf096e0b2508")
project(untitled LANGUAGES CXX)
set(CMAKE_CXX_MODULE_STD 1)
set(CMAKE_CXX_STANDARD 23)
add_executable(untitled src/main.cpp
)
target_sources(untitled
PUBLIC
FILE_SET modules TYPE CXX_MODULES FILES
src/Vector.cppm
src/Transport/Server.cppm
src/StdAll.cppm
)
이런 오류가 생겼다.
Experimental
import std
support not enabled when detecting toolchain; it must be set beforeCXX
is enabled (usually aproject()
call)
CLion 설정에 CMake option을 직접 넣어줬다.
-DCMAKE_EXPERIMENTAL_CXX_IMPORT_STD=0e5b6991-d74f-4b3d-a41c-cf096e0b2508
또 오류...
libc++.modules.json
resource does not exist
https://github.com/NixOS/nixpkgs/issues/370217
같은 고민을 하는 사람이 좀 있었다. CLion 내장 CMake 사용 중이라서 homebrew로 CMake 설치 및 연동하고 아래 파일 수정했다.
/opt/homebrew/share/cmake/Modules/Compiler/Clang-CXX-CXXImportStd.cmake
Go to the line 13 and change -print-file-name=libc++.modules.json
to -print-file-name=../../c++/libc++.modules.json
빌드가 됐다. 그런데 문제가 또 남았다.
CLion에서 std모듈을 resolve를 못했다.
'import std': CLion can't resolve module 'std' in case of clang
CMakeList.txt 수정하여 해결
add_library(unused_std_target STATIC)
target_sources(unused_std_target
PRIVATE
FILE_SET CXX_MODULES
BASE_DIRS <path-to-llvm>/share/libc++/v1
FILES <path-to-llvm>/share/libc++/v1/std.cppm <path-to-llvm>/share/libc++/v1/std.compat.cppm)
--
modules 사용 부터 import std;
까지 여러번 막히며 예상보다 많은 시간을 들였다. 중간에 #include
로 되돌아갈까 고민도 했다. 하지만 모던한 C++을 경험하고 싶고 개발 환경도 결국 문법과 같은 언어의 일부라는 깨달음으로 끝까지 시도하기로 했다.
회사에서 처음 환경 세팅을 했을 때도 비슷한 어려움을 겪었지만, 몇 번 반복하다 보니 어느 정도 익숙해졌고 이후에는 귀찮음을 덜기 위해 Docker Compose로 손쉽게 구축할 수 있었다. 돌아보면, 이 모든 과정은 언어와 환경뿐 아니라 서비스에 까지 도움이 되는 중요한 준비 단계였다고 생각한다. 왜냐하면 실제 서비스를 위한 코드가 실행되는 환경의 이해는 이슈 발생 시에 빠른 대처로 이어질 수 있고 정확한 대응 방안을 마련할 수 있기 때문이다.
결과적으로 CMake, LLVM, 컴파일러 등 자세히 몰랐던 C++의 생태계를 마주하게 되었고 모듈을 사용해서 개발을 할 수 있는 토대가 마련 되었다. 비록 C++생태계에 대해 단편적인 지식들을 얻었을 뿐이지만 언젠가 주력으로 사용한다면 무엇을 알아야할지는 알 수 있을 것이다.
학부시절 C++은 그냥 Visual Studio만 실행하면 됐었는데 참...
별개로 cyclic dependency를 제대로 처리 못해서 일단 기존 방식으로 해야할 것 같다.