본문 바로가기
나머지/IT개발.잡다한것.

"stdafx.cpp" "stdafx.h" precompiled header

by 무늬만학생 2012. 10. 22.
반응형

윈도우 프로그래머라면 precompiled header가 익숙할 것이다. stdafx.h 바로 그 녀석이다. C/C++ 컴파일러의 컴파일 단위는 무조건 .c/.cpp 하나씩이다 (여담으로 그래서 파일간, 즉 .obj 파일들 넘어서 최적화 하는 것이 쉽지 않다). 그래서 개개의 .c/.cpp 파일을 컴파일할 때 #include를 하는 모든 헤더를 당연히 매번 파싱 해야한다. 간단한 프로그램은 괜찮은데, windows.h 와 같이 덩치가 무지 큰 헤더 파일을 #include하는 모든 파일을 매번 컴파일하면 시간이 상당히 걸린다. Precompiled header는 이런 비용을 줄이기 위해 나온 것으로 특정 헤더 파일을 미리 파싱한 결과물을 .pch 파일로 덤프시킨다. 그리고 다른 파일들은 이 .pch를 단순히 사용함으로써 중복된 파싱 작업을 없앨 수 있다.

VC++는 디폴트로 이 precompiled header를 사용한다. Precompiled header가 작동하는 원리는 다음과 같다.

  1. 덩치가 크거나 거의 바뀌지 않는 정의 같은 것을 모두 stdafx.h에 넣는다.
  2. stdafx.cpp는 /Yc "stdafx.h" 옵션을 줘서 컴파일 한다. (Create)
  3. 다른 .cpp 파일들은 /Yu "stdafx.h" 옵션을 준다. (Use)

실제로 windows.h 같은 것을 사용하는 프로젝트에서 PCH를 쓰냐 안 쓰느냐는 컴파일 속도에 지대한 영향을 미친다. 하나 오해하지 말아야할 것은 precompiled header의 이름은 꼭 stdafx.h/cpp일 필요가 없다. 아무런 파일 이름도 된다.

그런데 리눅스 gcc도 precompiled header라는 것이 있다. 여기를 보면 분명히 지원을 한다. 직접 테스트는 해보지 않았지만 확장자를 .gch로 하면 gcc가 알아서 만들어 주는 것 같다. 그런데 지금까지 리눅스 프로젝트에서 PCH를 쓰는 경우를 거의 보지 못했다. 컴파일 시간을 매우 단축시킬 수 있는데 사람들이 몰라서 안 쓰는 것일까 아니면 컴파일 하는 동안 커피 한 잔의 여유라도 가지려고 안 쓰는 것일까? 당연히 인텔 C/C++ 컴파일러도 PCH를 지원한다.

 

실제로 PCH의 위력은 대단하다. 요즘 FTP 클라이언트인 FileZilla 3.0 소스를 받아서 좀 고칠 것이 있어서 삽질을 좀 했다. 100여개의 cpp 파일이 있는 작지 않은 규모이다. 컴파일 되는 모습을 보니 파일 하나당 1~2초씩 걸리는 것을 볼 수 있었다. 역시나 PCH를 사용하고 있지 않았다. 그래서 테스트를 좀 해봤다. 다행히 대부분의 모든 파일질라 소스들이 FileZilla.h라는 파일을 공통적으로 #include 하고 있었다. 그래서 이 파일을 PCH로 만들었다. 그랬더니 그 결과는?

파일질라 3.0 클라이언트에는 engine과 interface 두 프로젝트가 있는데 PCH가 없을 때는 50초와 55초의 컴파일 시간이 걸렸다. 그런데 PCH를 사용한 뒤에는 각각 16초와 27초로 거의 절반 이상의 시간이 절약됨을 볼 수 있었다. (사실 파일질라 클라이언트 소스는 윈도우용이라도 VC++에서 완벽히 링크까지 되지 않는다. 그래서 MinGW 깔고 캐삽질이 필요하다. 위의 시간은 대략 링킹을 제외한 대충 컴파일 되는데까지 측정한 시간이다.)

 

이런 비효율은 다른 곳에서도 쉽게 찾아볼 수 있다. 요즘 연구하는데 주로 들여다보는 벤치마크 프로그램 중 ITK 라는 것이 있다. 의료영상에 관련된 소프트웨어 툴킷이다. 이게 좀 무식하게 덩치가커서 툴킷과 Apps를 다 컴파일하면 하드 한 10기가를 차지 한다. 그 뿐만 아니라 컴파일을 다 하는데 40~50분은 족히 걸린다. 8코어 서버 머신에서 돌리면 그나마 빠르지만 듀얼 코어 정도에서 돌리면 세월아 네월아다.

그런데 역시 컴파일 되는 꼬라지를 보고 있으면 욕이 튀어나온다. 예를 들어, 의료영상 이미지 프로세싱 중에 Registration이라는 알고리즘이 있다. 이 알고리즘을 여러가지로 구현한 테스트 프로그램들이 ImageRegistration1, ImageRegistration2 이런식으로 15번까지 있다고 하자. 웃기게도 저 프로그램 자체는 모두 달랑 200줄도 안 되는 .cpp 파일 하나 씩으로 구성되어있다. 대부분은 공통적인 모듈을 그대로 사용한다. 그래서 같은 파일들이 죽으라고 계속 반복적으로 컴파일 된다. (더 최악인 건 최적화 옵션을 빡세게 주면 반복적인 동일한 최적화를 계속 한다는 것)

물론 이건 PCH를 쓴다고 다 해결되는 문제는 아니다. 분명 SharedLib을 씀에도 저런 불필요한 컴파일 작업이 반복되는 것은 다른 멍청함 때문일 것이다. 그러나 수 많은 헤더파일을 적어도 PCH로 만들면 분명히 컴파일 시간은 매우 단축될 것이다.

 

C/C++의 문제점 중 하나가 지저분한 헤더파일로 인한 얽히고 섥힌 의존관계로 길어지는 컴파일 시간일 것이다. 혹시 프로젝트 빌드 시간이 지나치게 길다면 한 번 중복되는 헤더파일들이 반복적으로 파싱이 되고 있지 않은지 살펴보고 이들을 다 PCH로 만들면 좋을 것이다. PCH를 쓰지 않는 덩치큰 프로젝트들을 규탄하는 바이다!! 오늘 하루 종일 컴파일 하다가 홀라당…

p.s. 참고로 VC++에서 특정 소스파일이 물고 있는 헤더파일 목록은 GUI 프로퍼티 페이지에서도 고칠 수 있고 (C/C++ – Advance – Show Includes) 혹은 /showIncludes 옵션으로도 볼 수 있다.

참고: GNU gcc에서 PCH 사용하기

사실 빌드 속도를 가장 높이기 쉬운 방법 중 하나는 IncrediBuild와 같은 툴을 이용하는 방법도 있다. 예전 회사에서 느린 빌드 속도에 답답할 때, 파일 하나씩을 회사의 모든 컴퓨터로 뿌린 다음에 컴파일해서 취합하면 정말 좋겠다라는 생각을 했었는데, 그 아이디어가 구현된 것이 IncrediBuild...


출처 : http://minjang.egloos.com/1956289

유용한 정보 얻으셨으면 아래 광고나 손가락 클릭해주세요~  (로그인 불필요합니다)

반응형