GCC의 C 컴파일(빌드) 과정과 단계별 산출물

GCC는 GNU Compiler Collection의 약자입니다. (https://gcc.gnu.org)

GNU는 “GNU’s Not Unix!”라는 재귀적 문장의 첫 머리 글자 어이며 자유 소프트웨어 운동과 관련 있는 UNIX 형태의 운영체제를 뜻합니다. 이 글에선 자세히 다루지 않겠습니다. (https://www.gnu.org/home.ko.html)

GCC는 컴파일러 컬렉션이란 이름처럼 C 컴파일러만이 아니라 C++, Objective-C, Fortran, Ada, Go 등 많은 언어의 컴파일러 컬렉션입니다.

이 글에선 C 컴파일 과정만 서술합니다.

명령어 gcc는 C 컴파일러가 아니라 빌드 과정을 차례로 실행하는 명령어입니다. 즉 전처리기를 호출하고 컴파일러를 호출하고 어셈블러를 호출하고 링커를 호출하는 일을 합니다. 그래서 컴파일러 드라이버라 불립니다.

빌드란 전처리와 컴파일(+어셈블리)과 링킹 과정을 합한 것입니다. 보통은 컴파일 과정에 전처리 과정을 포함한다고 설명하여 컴파일 + 링킹으로 설명하는 글이 많습니다.

전처리 과정은 #include와 #define과 #if 등 파일을 포함하거나 매크로를 치환하거나 컴파일할 부분을 선택하는 등의 작업을 하는 과정입니다.

컴파일이란 고급 언어(C, C++ 등)를 0과 1로 된 기계어로 바꾸는 과정이며 저급 언어(어셈블리어)를 기계어로 바꾸는 어셈블리 과정은 컴파일과 완전히 별개로 취급하기보단 컴파일의 특수한 경우로 취급합니다.

링킹은 컴파일된 각각의 파일들을 하나의 실행 파일로 만드는 과정입니다. 컴파일 과정에서 소스 파일이 각각 오브젝트 파일이 되고 링킹 과정에서 하나가 되는 것입니다.

터미널에서 man gcc 명령으로 도움말을 보면 Options Controlling the Kind of Output이란 부분이 있습니다. 설명을 보면 컴파일 과정은 네 단계까지 있고 preprocessing(전처리), compilation proper(컴파일), assembly(어셈블리), linking(링킹) 순서로만 진행한다고 합니다.

더 읽어보면 이미 설명한 것처럼 각 어셈블리어 파일은 오브젝트 파일이 되고, 링킹 과정은 모든 오브젝트 파일을 하나의 실행 가능 파일로 만드는 과정이라고 쓰여있습니다.

//hello.c
#include<stdio.h>
int main(){
  printf("Hello\n");
}

위와 같은 간단한 C 파일을 가지고 진행해봅시다.

gcc hello.c

명령으로 a.out 파일이 만들어지고

./a.out

으로 실행할 수 있습니다.

gcc -o hello hello.c

-o를 붙여 a.out이 아닌 이름을 정할 수도 있습니다. 여기까지는 다 아는 이야기일 텐데요.

다음 명령으로 빌드 과정에서 삭제되는 중간 단계의 결과물을 현재 디렉터리에 남겨봅시다.

gcc --save-temps -o hello hello.c

hello hello.c hello.i hello.o hello.s 다섯 파일이 있군요.

hello는 -o를 안 넣었다면 a.out이 되었을 최종 결과물인 실행 파일이고, hello.c는 C 소스 파일이니 나머지 i, o, s가 무엇인지만 알면 되겠지요.

이것 역시 man 페이지에 설명이 있습니다.

i는 전처리 된 C 소스 코드이고, s는 어셈블러 코드라고 합니다.

o는 man 페이지에서 찾을 수 없었지만 오브젝트 코드입니다.

즉 hello.c – 전처리 – hello.i – 컴파일 – hello.s – 어셈블리 – hello.o – 링킹 – hello(a.out) 과정을 거친다는 것을 알 수 있습니다.

gcc --save-temps -v -o hello hello.c

정말 그런지 -v 옵션을 추가하여 실행해봅시다.

man 페이지에 -v 옵션의 설명을 보면 컴파일을 진행하면서 실행된 명령을 표준 오류 출력(모니터)에 보여준다고 합니다.

실행하면 많은 글자가 출력되는데 COLLECT_GCC_OPTIONS로 시작하는 부분들만 보면

/usr/lib/gcc/x86_64-linux-gnu/5/cc1 -E로 hello.i를 만들고(전처리)

/usr/lib/gcc/x86_64-linux-gnu/5/cc1로 hello.s를 만들고(컴파일)

as로 hello.o를 만들고(어셈블리)

/usr/lib/gcc/x86_64-linux-gnu/5/collect2로 hello가 만들어지는 것(링킹)을 알 수 있습니다.

이것으로 gcc라는 명령어는 cc1 -E를 호출해 전처리하고 cc1을 호출해 컴파일하고 as를 호출해 어셈블리하고 collect2를 호출해 링킹한다는 것을 알 수 있었습니다.

SW Level Up

mail@swlevelup.com

You may also like...

댓글 남기기

이메일은 공개되지 않습니다.