프로그램의 빌드 과정
C/C++과 같은 언어로 작성된 소스 코드는 컴퓨터가 실행 가능한 바이너리 파일로 변환되어야 한다. 이 과정은 여러 단계를 거치며, 각각의 단계에서 소스 코드는 점차 저수준 형태로 바뀌게 된다. 이러한 일련의 과정을 빌드(build)라고 한다. 일반적으로 다음과 같은 네 단계를 거친다.
1. 전처리 (Preprocessing)
첫 번째 단계는 전처리기(preprocessor)가 수행한다. 이 단계에서는 소스 코드에 포함된 전처리 지시문들을 처리한다.
- #include로 포함된 헤더 파일의 내용이 소스 코드에 삽입된다.
- #define으로 정의된 매크로가 치환된다.
- 조건부 컴파일 지시문(#ifdef, #ifndef 등)이 해석된다.
전처리 결과는 확장자가 .i인 파일로 저장되며, 아직 컴파일이 되지 않은 순수한 텍스트 코드이다.
2. 컴파일 (Compiling)
전처리된 결과물은 컴파일러에 의해 어셈블리어 코드로 변환된다. 이 과정에서는 문법 검사와 함께 프로그램 구조에 대한 해석이 이루어진다.
- 전처리된 C/C++ 코드가 추상 구문 트리(Abstract Syntax Tree)로 변환된다.
- 구문 트리를 기반으로 중간 표현(IR)이 생성된다.
- IR을 바탕으로 최적화를 수행한 후, 어셈블리어로 변환된다.
이 결과는 .s 확장자를 가지는 어셈블리 파일로 저장된다.
3. 어셈블 (Assembling)
어셈블러는 어셈블리어 코드를 기계어로 번역하여 목적 파일(object file)을 생성한다.
- 목적 파일은 .o 또는 .obj 확장자를 가진다.
- 이 파일은 실제 기계어 명령어가 포함되어 있지만, 단독으로 실행할 수는 없다.
- 내부적으로는 심볼 정보, 섹션 정보, 참조 정보 등이 포함되어 있다.
이 단계까지는 함수 호출 등 외부 심볼이 아직 연결되지 않은 상태이다.
4. 링크 (Linking)
마지막 단계는 링커가 수행하며, 여러 개의 목적 파일과 라이브러리를 하나로 결합하여 실행 파일을 생성한다.
- 각 목적 파일 내에 있는 심볼들을 분석하여, 서로 참조하는 함수나 변수의 주소를 연결한다.
- 표준 라이브러리나 사용자 정의 라이브러리도 이 단계에서 함께 연결된다.
- 결과물은 .exe, .out, 또는 플랫폼에 따라 적절한 실행 파일 형식이 된다.
링킹은 정적 링크(static linking)와 동적 링크(dynamic linking)로 나뉘며, 동적 링크는 실행 시에 라이브러리를 연결한다.