<aside> 🎯

한 줄 핵심 — 일하는 건 언제나 컴파일러(gcc) 하나뿐이다. make는 그 gcc를 대신 쳐주는 손, CMake는 그 손이 읽을 대본을 대신 써주는 작가.

셋은 대체재가 아니라 위아래로 쌓인 층이고, 실무에서 시간을 잡아먹는 건 맨 위(CMake)가 아니라 맨 아래의 링크와 툴체인이다.

</aside>

1. 4층 지도 — 누가 무슨 일을 하나

하는 일 리눅스 윈도우(VS) 대응물
① 빌드 생성기 레시피를 만들어 준다. 직접 컴파일은 안 함 CMake (CMakeLists.txt) 없음 — 사람이 GUI로 프로젝트 설정
② 레시피 "무엇이 무엇에 의존하고, 바뀌면 무슨 명령을 실행하라" makefile .vcxproj (XML)
③ 빌드 실행기 레시피를 읽고 바뀐 것만 골라 명령 실행 make MSBuild
④ 컴파일러 · 링커 실제로 소스를 기계어로 바꾸고 하나로 묶음 gcc / g++ , ld cl.exe , link.exe

<aside> 💡

VS만 써 왔다면 이 층이 안 보이는 게 정상. F5 한 번에 ②③④가 전부 들어 있었을 뿐이다.

리눅스는 같은 걸 분해해서 손으로 다루는 것이지, 새로운 개념이 아니다.

</aside>

<aside> ⚠️

자주 하는 오해 — "gcc로 빌드하냐, CMake로 빌드하냐"는 질문 자체가 성립하지 않는다.

CMake를 써도 마지막엔 gcc가 돈다. CMake가 있고 없고는 ①층의 유무일 뿐이다.

</aside>


2. 선행 개념 — 소스가 실행파일이 되기까지

이걸 모르면 위의 도구들이 왜 필요한지 안 와닿는다. .cpp 하나가 실행파일이 되는 길은 네 단계다.

main.cpp
  │  ① 전처리 (Preprocess)   #include 를 펼치고 #define 을 치환     → main.i
  │  ② 컴파일 (Compile)      C++ 문법을 어셈블리로                  → main.s
  │  ③ 어셈블 (Assemble)     어셈블리를 기계어 목적파일로           → main.o
  │  ④ 링크 (Link)           여러 .o 와 라이브러리를 하나로 묶음    → 실행파일
단계 손으로 해보는 법 여기서 나는 에러
① 전처리 g++ -E main.cpp -o main.i 헤더를 못 찾음 — No such file (해결: -I 로 경로 추가)
②③ 컴파일 g++ -c main.cppmain.o 문법·타입 에러. 한 파일 안에서 판정 가능한 것들
④ 링크 g++ main.o util.o -o app undefined reference — 선언은 봤는데 몸통이 어디에도 없음 (해결: -l 로 라이브러리 추가, 또는 그 .o 를 빼먹음)

<aside> 🔑

첫 갈림길은 "컴파일 에러냐 링크 에러냐"다.

error: 로 파일·줄번호가 찍히면 ②③ — 그 파일만 보면 된다.

undefined reference to ... 가 뜨면 ④ — 소스는 멀쩡하고 빌드 구성이 틀린 것이다. 이걸 구분 못 하면 엉뚱한 파일을 몇 시간 들여다본다.

</aside>

<aside> 📐

왜 굳이 .o 로 나누나 — 파일 100개짜리 프로젝트에서 한 줄 고쳤을 때 그 파일 하나만 다시 컴파일하고 나머지 99개의 .o 는 재활용하기 위해서다.

이 "바뀐 것만 다시" 를 자동으로 판정해주는 게 다음 장의 make 다.

</aside>


3. make와 makefile — 레시피와 그걸 읽는 손

makefile의존 관계와 명령을 나열한 텍스트 파일이다. 문법은 딱 세 줄짜리 구조다.

CXX      = g++
CXXFLAGS = -O2 -g -Wall -I./include
OBJS     = main.o util.o session.o

# 목표파일 : 이것들에 의존한다
app: $(OBJS)
	$(CXX) -o $@ $(OBJS) -lpthread       # 링크 (④)

# .cpp 하나를 .o 하나로 바꾸는 일반 규칙
%.o: %.cpp
	$(CXX) $(CXXFLAGS) -c $< -o $@       # 컴파일 (②③)

clean:
	rm -f $(OBJS) app
기호
목표: 의존들 "목표를 만들려면 이것들이 먼저 필요하다"
$@ 목표 이름 (위 예에서 app 또는 main.o)
$< 첫 번째 의존 파일 (위 예에서 main.cpp)
% 와일드카드. %.o: %.cpp = 모든 cpp를 같은 방식으로 처리
명령 줄 들여쓰기 반드시 탭. 스페이스면 에러 — makefile 입문자의 1번 함정

<aside> 💡

make의 존재 이유는 한 문장 — 목표파일과 의존파일의 수정 시각을 비교해서, 의존이 더 최신일 때만 명령을 실행한다.

그래서 아무것도 안 고치고 make 를 또 치면 make: 'app' is up to date. 만 뜬다. 이게 증분 빌드다.

</aside>

<aside> 🧭

실무에서 makefile을 건드리는 순간은 딱 정해져 있다 — ① 소스 파일을 새로 추가했을 때(목록에 등록) ② 컴파일 옵션·매크로를 추가할 때 ③ 라이브러리를 새로 링크할 때.

처음부터 쓸 일은 거의 없고, 읽고 고칠 줄만 알면 된다.

</aside>