컴파일과 실행 과정
C++ 프로그램의 생명 주기
C++ 프로그램이 소스 코드에서 실행 가능한 프로그램이 되기까지의 과정을 생명 주기라고 합니다.
이 과정은 다음과 같은 단계로 구성됩니다.
1. 소스 코드 작성
2. 전처리 (Preprocessing)
3. 컴파일 (Compilation)
4. 어셈블 (Assembly)
5. 링킹 (Linking)
6. 로딩 (Loading)
7. 실행 (Execution)
각 단계를 자세히 살펴보겠습니다.
전처리 과정
전처리기는 컴파일 전에 소스 코드를 수정하는 역할을 합니다. 주요 작업은 다음과 같습니다.
1. 주석 제거
2. #include
지시문 처리 : 헤더 파일의 내용을 소스 코드에 삽입
3. 매크로 확장 : #define
으로 정의된 매크로를 실제 값으로 대체
4. 조건부 컴파일 : #ifdef
, #ifndef
, #endif
등의 지시문 처리
컴파일 과정
컴파일러는 전처리된 소스 코드를 어셈블리 코드로 변환합니다. 이 과정에서 다음과 같은 작업이 수행됩니다.
- 문법 검사 : 코드의 문법적 오류를 찾아냅니다.
- 의미 분석 : 변수 타입 체크, 함수 호출의 유효성 검사 등을 수행합니다.
- 중간 코드 생성 : 소스 코드를 컴파일러 내부의 중간 표현으로 변환합니다.
- 코드 최적화 : 실행 속도를 높이거나 코드 크기를 줄이는 최적화를 수행합니다.
- 목적 코드 생성 : 최종적으로 어셈블리 코드를 생성합니다.
주요 C++ 컴파일러
- GCC (GNU Compiler Collection)
- Clang
- Microsoft Visual C++ Compiler
어셈블 과정
어셈블러는 어셈블리 코드를 기계어로 변환합니다. 이 과정의 결과물을 목적 파일(object file)이라고 하며, 확장자는 보통 .o (Unix) 또는 .obj (Windows)입니다.
링킹 과정
링커는 여러 목적 파일과 라이브러리를 하나의 실행 파일로 결합합니다. 주요 작업은 다음과 같습니다.
- 심볼 해결 : 외부 참조를 실제 메모리 주소로 연결합니다.
- 메모리 주소 할당 : 각 섹션(코드, 데이터 등)에 메모리 주소를 할당합니다.
- 재배치 : 코드와 데이터의 주소를 조정합니다.
링킹의 종류
- 정적 링킹 : 라이브러리 코드를 실행 파일에 포함시킵니다. 실행 파일의 크기가 커지지만, 배포가 간편합니다.
- 동적 링킹 : 라이브러리를 별도로 유지하고, 실행 시점에 연결합니다. 실행 파일의 크기는 작아지지만, 배포 시 라이브러리도 함께 제공해야 합니다.
실행 파일 구조
실행 파일은 다음과 같은 주요 섹션으로 구성됩니다.
- 텍스트 섹션 : 실행 가능한 코드
- 데이터 섹션 : 초기화된 전역 변수와 정적 변수
- BSS 섹션 : 초기화되지 않은 전역 변수와 정적 변수
- 힙 : 동적으로 할당되는 메모리 영역
- 스택 : 지역 변수와 함수 호출 정보를 저장하는 영역
컴파일 명령어 상세 분석
옵션 설명
-Wall
: 모든 경고 메시지를 출력합니다.-O2
: 최적화 레벨 2를 적용합니다. (0부터 3까지 있으며, 숫자가 클수록 더 강력한 최적화를 수행)-std=c++17
: C++17 표준을 사용합니다.-c
: 컴파일만 수행하고 링크는 하지 않습니다.-o
: 출력 파일의 이름을 지정합니다.
빌드 자동화 도구
대규모 프로젝트에서는 빌드 과정을 자동화하기 위해 다음과 같은 도구들을 사용합니다.
- Make : Makefile을 사용하여 빌드 과정을 정의하고 실행합니다.
- CMake : 크로스 플랫폼 빌드 시스템으로, 다양한 환경에서 일관된 빌드 스크립트를 사용할 수 있게 해줍니다.
- Ninja : 빠른 빌드 속도에 중점을 둔 빌드 시스템입니다.
연습 문제
- 다음 코드의 전처리 결과를 예측해보세요.
- 컴파일러 최적화 레벨에 따른 실행 속도 차이를 측정하는 프로그램을 작성하고, -O0, -O1, -O2, -O3 옵션으로 각각 컴파일하여 결과를 비교해보세요.
- 여러 개의 소스 파일을 사용하는 간단한 프로젝트를 만들고, 이를 빌드하는 Makefile을 작성해보세요.
- 동적 링킹과 정적 링킹의 차이점을 설명하고, 각각의 장단점을 논의해보세요.
참고자료
- "컴파일러 : 원리, 기법, 도구" (앨프레드 V. 에이호 외 저)
- GCC 공식 문서 : https://gcc.gnu.org/onlinedocs/
- LLVM 문서 : https://llvm.org/docs/
- "링커와 로더" (존 R. 레벤)