C++ 링커와 링킹 과정 완전 이해
C++ 프로그램은 전처리 → 컴파일 → 어셈블 → 링킹 단계를 거쳐 실행 파일이 됩니다. 링킹은 여러 오브젝트 파일(.o/.obj)과 라이브러리를 결합하여 최종 실행 파일을 만드는 단계입니다. 링커 오류(undefined reference, multiple definition 등)는 링킹 과정을 이해해야 해결할 수 있습니다.
1. 컴파일과 링킹 분리
섹션 제목: “1. 컴파일과 링킹 분리”// 파일 구조// math.h, math.cpp, main.cpp
// 컴파일 (각 파일 독립적으로)g++ -c math.cpp -o math.o // 오브젝트 파일 생성g++ -c main.cpp -o main.o
// 링킹 (오브젝트 파일 결합)g++ math.o main.o -o program각 컴파일 단위(translation unit)는 독립적으로 컴파일되며, 외부 심볼은 링킹 단계에서 해소됩니다.
2. 심볼 해석 과정
섹션 제목: “2. 심볼 해석 과정”2.1 정의(Definition)와 선언(Declaration)
섹션 제목: “2.1 정의(Definition)와 선언(Declaration)”// 선언: 심볼의 존재를 알림 (헤더에 위치)extern int globalValue; // 변수 선언void calculate(int a, int b); // 함수 선언
// 정의: 실제 구현 (.cpp에 위치)int globalValue = 42; // 변수 정의void calculate(int a, int b) { // 함수 정의 std::cout << a + b << "\n";}2.2 undefined reference 오류
섹션 제목: “2.2 undefined reference 오류”void foo(); // 선언만, 정의 없음
int main() { foo(); // 링커: "undefined reference to foo()"}해결: foo()의 정의가 있는 파일을 링크에 포함.
3. ODR — One Definition Rule
섹션 제목: “3. ODR — One Definition Rule”C++의 핵심 규칙: 같은 엔티티의 정의는 전체 프로그램에서 하나만 존재해야 합니다.
int add(int a, int b) { return a + b; }
// util.cppint add(int a, int b) { return a + b; } // ODR 위반!
// 링커: "multiple definition of add()"3.1 ODR 예외: 인라인 함수
섹션 제목: “3.1 ODR 예외: 인라인 함수”inline 함수는 여러 TU에서 정의될 수 있지만 모든 정의가 동일해야 합니다.
inline int add(int a, int b) { return a + b; } // 여러 TU에서 포함 가능3.2 헤더 가드와 #pragma once
섹션 제목: “3.2 헤더 가드와 #pragma once”// math.h — 이중 포함 방지#pragma once// 또는#ifndef MATH_H#define MATH_Hvoid calculate();#endif4. 링키지(Linkage)
섹션 제목: “4. 링키지(Linkage)”4.1 외부 링키지 (external linkage)
섹션 제목: “4.1 외부 링키지 (external linkage)”다른 TU에서 참조 가능합니다.
int globalVar = 10; // 외부 링키지void func() {} // 외부 링키지4.2 내부 링키지 (internal linkage)
섹션 제목: “4.2 내부 링키지 (internal linkage)”현재 TU에서만 접근 가능합니다.
static int localVar = 10; // 내부 링키지static void localFunc() {} // 내부 링키지
// C++11: 익명 네임스페이스 (권장)namespace { int anotherLocal = 20; // 내부 링키지}4.3 링키지 없음 (no linkage)
섹션 제목: “4.3 링키지 없음 (no linkage)”void func() { int local = 5; // 링키지 없음 — 함수 내부 변수}5. Static vs Dynamic 링킹
섹션 제목: “5. Static vs Dynamic 링킹”5.1 정적 링킹
섹션 제목: “5.1 정적 링킹”# 정적 라이브러리 생성ar rcs libmath.a math.o
# 정적 링킹g++ main.o -L. -lmath -o program- 라이브러리 코드가 실행 파일에 포함
- 배포 시 라이브러리 불필요
- 실행 파일 크기 증가
5.2 동적 링킹
섹션 제목: “5.2 동적 링킹”# 공유 라이브러리 생성g++ -shared -fPIC math.cpp -o libmath.so
# 동적 링킹g++ main.o -L. -lmath -o program# 런타임에 libmath.so 필요- 라이브러리 코드를 메모리에서 공유
- 실행 파일 크기 감소
- 라이브러리 업데이트가 모든 프로그램에 적용
6. extern “C”
섹션 제목: “6. extern “C””C++ 함수는 오버로딩 지원을 위해 이름을 맹글링(mangling)합니다. C 코드와 인터페이스하려면 extern "C"로 맹글링을 억제합니다.
// C++에서 C 함수 사용extern "C" { int c_function(int a, int b); // C 이름 그대로 사용}
// C에서 C++ 함수 노출extern "C" int my_cpp_function(int x) { return x * 2;}
// 헤더에서 C/C++ 공용#ifdef __cplusplusextern "C" {#endif
void shared_api();
#ifdef __cplusplus}#endif맹글링 예
섹션 제목: “맹글링 예”// C++ 함수: void foo(int, double)// 맹글링 후: _Z3foodd (GCC), ?foo@@YAXNH@Z (MSVC)
// extern "C": 맹글링 없이 foo 그대로7. LTO — Link Time Optimization
섹션 제목: “7. LTO — Link Time Optimization”LTO는 링킹 단계에서 여러 TU에 걸친 최적화를 수행합니다.
# GCC LTO 활성화g++ -O2 -flto -c a.cpp -o a.og++ -O2 -flto -c b.cpp -o b.og++ -O2 -flto a.o b.o -o programLTO가 가능한 최적화:
- TU 경계를 넘는 인라인 확장
- 불필요한 심볼 제거 (dead code elimination)
- 크로스 TU 상수 전파
8. 자주 발생하는 링커 오류
섹션 제목: “8. 자주 발생하는 링커 오류”8.1 undefined reference
섹션 제목: “8.1 undefined reference”/usr/bin/ld: main.o: undefined reference to `Database::connect()'원인: Database 클래스 구현 파일을 링크하지 않음
해결: g++ main.o database.o -o program 또는 -ldatabase
8.2 multiple definition
섹션 제목: “8.2 multiple definition”/usr/bin/ld: math.o: multiple definition of `add(int, int)'원인: ODR 위반 — 같은 함수가 두 파일에서 정의됨
해결: 헤더에 있는 정의를 inline으로 만들거나 하나의 .cpp로 이동
8.3 circular dependency
섹션 제목: “8.3 circular dependency”// A가 B에 의존, B가 A에 의존 → 링크 순서 문제g++ a.o b.o // 오류 가능g++ a.o b.o a.o // 순환 참조 해소# 또는g++ -Wl,--start-group a.o b.o -Wl,--end-group9. 심볼 가시성 제어
섹션 제목: “9. 심볼 가시성 제어”// GCC/Clang: 심볼 가시성 제어__attribute__((visibility("default"))) void publicFunc() {} // 외부 노출__attribute__((visibility("hidden"))) void privateFunc() {} // 외부 숨김
// CMake에서set(CMAKE_CXX_VISIBILITY_PRESET hidden)set(CMAKE_VISIBILITY_INLINES_HIDDEN YES)| 개념 | 설명 |
|---|---|
| 링킹 | 오브젝트 파일 결합, 심볼 해소 |
| ODR | 전체 프로그램에서 정의는 하나 |
| 내부 링키지 | static, 익명 네임스페이스 |
| extern “C” | C++ 맹글링 억제 |
| 정적 링킹 | 라이브러리 코드를 실행 파일에 포함 |
| 동적 링킹 | 런타임에 공유 라이브러리 로드 |
| LTO | 링킹 단계 크로스 TU 최적화 |