[C++]

[C++ 20] Module

럭키🍀 2024. 11. 13. 21:11

C++ 20의 module의 도입으로 빌드 시간이 줄어들었다.
C++의 빌드 과정
1. 전처리 : #include, #define등
2. 컴파일 : obj파일 생성
3. 링크 : obj파일과 심볼, 등을 묶어서 실행파일을 만듦

-> 여기서 이런 기존 빌드 과정의 문제점
1. 너무 느린 빌드 속도(반복된 substitution)
같은 라이 파일도 클래스마다 들고 있으면 각각 오브젝트에 딸려들어가서 무거워진다.
(중복으로 인클루드 되는 문제)
2. 매크로 (#define)의 사용을 지양하자..?
예) #define NUM 1 이렇게 한 파일에서 정의하고 다른곳에서 #define NUM 2 하면 다른데서
두 파일 다 인클루드하고 있을 때 NUM을 뭐로 쓸지 모름
3. 심볼의 중복 정의
보통 헤더에 함수를 선언하고 cpp에서 정의하지만
Test.h에 함수의 선언과 정의를 같이하고
메인함수가 있는 곳에 Test.h를 추가한다음에 빌드하려하면 '여러번 정의된 기호가 있습니다.' 오류가 난다.
그런데 메인함수고 있는 파일에서 Test.h를 빼면 이 문제가 발생하지 않는다.
이 문제는 이 문제는 Test.h에 선언된 함수가 Test.obj파일에 포함되어 있는데 그다음에 별도로 메인함수가 있는 cpp파일을 별도로 obj파일에 
만들려니 두 개의 object파일에 동일한 이름으로 함수가 두 번 생기게 되어서 링크에러가 발생한다.
 
=> 이런 복잡한 문제를 모듈을 이용하면 한번에 다 처리 가능하다.

Module의 장점.
1. 딱 한번만 import된다.
2. import 순서에 영향을 받지 않는다. 
#define NUM 1 을 한 파일과 #define NUM 2 를 한 파일을 include 하는 순서에 따라 NUM이 다른 문제가 있엇다.
3. 심볼 중복 정의문제 해결
4. 모듈의 이름짓기가 가능해짐
5. (h/cpp)인터페이스와 구현부 분리해 관리할 필요가 없어짐.

솔루션탐색기에서 프로젝트 우클릭으로 새항목을 추가하는데 
C++ 모듈 인터페이스 단위(.ixx)를 선택한다.
(참고로 윈도우즈에서는 ixx지만 리눅스나 다른 환경에선 확장자가 다를 수 있다.)


 

모듈을 사용하는 여러가지 방법.
1) 함수앞에다가 export를 쓰고 .ixx 파일 상단에 이 파일을 뭐라고 할지
export module [파일 이름] 
이런식으로 쓴 다음에 갖다 쓸 곳에서 
import [파일 이름]
이렇게 쓰고 파일에서 export한 함수 가져다가 쓰기
예)

//Math.ixx
export module math;
export int Add(int a, int b)
{
 return a+b;
}

// [프로젝트이름].cpp
#include <iostream>
import math;
int main()
{
cout<<Add(1,2);
}



2).ixx파일 내에서 export해주고싶은 것들만 묶어서 하기.

// Math_Time.ixx
export module math;

void Internal()
{
}

export
{
 void TestExport()
 {
 }
}

// [프로젝트이름].cpp
#include <iostream>
import math;
int main()
{
  TestExport();
  // Internal(); // 에러
}

 

 

3) namespace를 지정해서 쓰기 <- 권장

// Math.ixx
export module math;

export namespace TestNamespace
{
 void TestExport2()
 {
 }
}

// [프로젝트이름].cpp
import math;

int main()
{
 TestNamespace::TestExport2();
 return 0;
}

 

사실 모듈이름과 네임스페이스의 이름도 갖게 맞추는게 권장된다.

 

 

모듈 사용시 참고사항

1.

export를 붙이지 않은 함수, 네임스페이스 등은 모듈과 같은 페이지 안에 있어도 내보내지지 않아 모듈을 import해도 사용할수 없다.

 

2.

모듈 안에서 외부 라이브러리를 사용할 경우 ixx 파일 내에 다음과 같이 작성하면 된다.

// Math.ixx

module; // global module fragment
// 각종 외부 헤더 추가
#include <vector>
#include <iostream>
// ...


// module의 시작
export module math;

// module에도 module을 추가할 수 있다.
import math2;

export int Add(int a, int b)
{
// ...

외부 라이브러리를 사용하거나 module을 추가해서 module내에서 사용할때 위같은 순서를 지키는게 일반적이다.

 

3. 

모듈의 기능이 방대해져서 같은 목적을 갖고 있는데도 파일의 분리가 필요할 때도 가능하다.

Math.ixx외에도 Math의 기능을 수행하는 다른 ixx파일도 만든다고 가정하면 이름을 Math_partial1.ixx파일을 만들었다 가정했을 때 

3-1.

// Math_Partial.ixx
export module math.partial;

export void MathPartialFunc()
{

}

// [프로젝트이름].cpp
import math.partial;

int main()
{
  MathPartialFunc();
  return 0;
}

그런데 이렇게 하면 결국 모든 module을 import해야하는건 마찬가지이므로

 

3-2.

'[C++]' 카테고리의 다른 글

CHAR/ TCHAR/ WCHAR  (0) 2022.04.21
Modern C++ #2 스마트 포인터(smart pointer)  (0) 2021.09.19
STL #1 Vector  (0) 2021.08.24
포인터 1 - 포인터, 참조 기초  (0) 2021.08.24