본문 바로가기

Linux

gcc 컴파일 옵션

 

디렉토리구조에 이어 오늘은 gcc 컴파일 옵션에 대해 알아보겠습니다.


제 경험상 학교에서는 기본적인 -o 옵션정도, 회사에서는 Makefile 에 의한 자동 컴파일을 하기때문에 많은 분들이 컴파일 옵션을 잘 모르시는것 같습니다.
(컴파일옵션을 잘 모르시면 프로그램이 어떻게 동작하는지, 그리고 실행화일을 만들기 위해 어떤것들이 필요하며 디버깅은 어떻게 하는지 등을 모를수 있습니다. )
 

쉘에서 man gcc 해보시면 gcc 및 옵션에 대해 친절하지도, 그렇다고 쉽지도 않은 영어 설명이 나옵니다. 휴~


이렇게 많은 옵션중에서 반드시 필요한 몇개만 알아보도록 하겠습니다. 오늘 알아볼 옵션은 -v, -I,

-o, -D 정도입니다. (그외의 옵션은 Makefile 시간과 필요시에 그때그때 알아보도록 하겠습니다..^^)


컴파일 옵션 설명을 위해 간단한 C 소스를 하나 작성하겠습니다. 모두 잘 아시는 Hello, World 소스입니다


--------------------------------------------------------------
  #include <stdio.h>

  int main(int argc,char** argv)
  {
    printf("Hello, World\n");

    return 0;
  }
--------------------------------------------------------------


위 소스를 helloworld.c 로 저장한후에 gcc helloworld.c 실행하면 해당디렉토리에 a.out 실행화일이 생성됩니다.


 

[그림 1]


[1] -v 옵션 (컴파일 과정을 보여주는 옵션입니다)
그럼 여기서 질문하나 할까요? 컴파일과정, 즉 현재 사용하는 gcc 버젼 및 소스에서 삽입한 stdio.h 가 어느 디렉토리에 있는지등의 정보를 보려면 어떤 옵션을 사용할까요?

바로 -v  옵션입니다. -v 옵션을 사용해 컴파일 하면 컴파일러 버젼 정보, include 디렉토리, 에셈블러정보, 실행화일 형식등의 많은 정보를 보실수 있습니다. 다음 그림과 같이 gcc -v helloworld.c 를 해보고 위 [그림 1]과 비교해 보겠습니다.



[그림2]


[그림 2] 에서 보듯이 -v 옵션을 적용하면 다양한 컴파일과정이 출력됩니다. gcc 컴파일러 버젼은 3.2.2 이고 gcc 가 stdio.h 등의 헤더파일을 찾아가는 경로는 /usr/local/include, /usr/include,

/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/include 입니다.


[2] -o 옵션 (출력파일의 이름 지정하는 옵션입니다)

위에서 보듯이 출력파일의 이름을 특별히 지정하지 않으면 모든 이름은 a.out 으로 나타납니다. 실행파일의 이름을 주고 싶을땐 -o 옵션을 주시면 됩니다 (숫자 0 이 아닌 알파벳 o 입니다...). 즉, gcc -o <실행파일이름> <소스파일이름> 또는 gcc <소스파일이름> -o <실행파일이름> 으로 지정하시면 됩니다..중요한것은 -o 다음에는 반드시 출력파일이름이 와야합니다. 실수로 gcc -o <소스파일이름> <출력파일이름> 하시면 대재앙입니다....


다음은 출력파일의 이름을 helloworld 로 주는경우를 나타내 보았습니다



[그림3]


[3] -D 옵션 (외부에서 #define 을 정의하는 옵션입니다)

-D 옵션을 알아보기 위해 처음 제시한 helloworld.c 소스를 약간 수정해보겠습니다. 즉, 소스에 #ifdef ~ #endif 를 추가했습니다.


--------------------------------------------------------------
  #include <stdio.h>

  int main(int argc,char** argv)
  {

    #ifdef   TEST
    printf("Hello, World\n");

    #else

    printf("Hello, New World\n");

    #endif


    return 0;
  }
--------------------------------------------------------------

소스에서 보듯이 TEST 가 정의되어 있으면 Hello, World 를 출력하고, 정의되어 있지 않으면 Hello, New World 를 출력하는 소스입니다. 이렇게 조건부컴파일을 할때 유용하게 사용되어 지는 것이 -D 옵션입니다. (실무에서 개발중일때는 DEBUG  라는 매크로를 사용하다가 실제 출시할때는 정의하지 않응 방식을 사용합니다.)


사용방법은 다음과 같습니다.

gcc -D<매크로이름>


다음 그림 4는 -D 옵션을 사용하지 않고 컴파일/실행한 화면입니다. 결과에서 보듯이 'Hello, New World' 가 출력되었습니다



[그림 4]


다음 그림5는 -D 옵션을 사용하여 컴파일/실행한 화면입니다. 밑줄에 표시된 부분처럼 컴파일시에

-DTEST 가 정의되어 있고 실행시 'Hello, World' 가 출력됩니다



[그림 5]


[4] -I 옵션 (컴파일러가 헤더파일을 탐색할 디렉토리지정 옵션입니다)

일반적으로 C 소스에서 "AAA.h" 라고 하면 현재 작업디렉토리에서 AAA.h 를 찾고 <BBB.h> 라고 하면 컴파일러가 참조하는 디렉토리를 탐색해서 해당파일을 찾습니다. -v 옵션에서 보았듯이 gcc 컴파일러는 헤더파일의 디렉토리를 /usr/include, /usr/local/include, /usr/lib/gcc-lib/i386-redhat-linux/3.2.2/include 로 부터 탐색합니다. 그러나 실무에서는 특정디렉토리에 회사 고유의 헤더파일을 만들어 보관합니다. 이럴때 컴파일러로 하여금 특정 디렉토리를 기존의 디렉토리와 함께 탐색할수 있게 해 주는 옵션이 -I 입니다. 사용법은 다음과 같습니다

(영어 대문자 I 입니다..숫자 1이 아닙니다..)


gcc -I<디렉토리경로>


이해를 쉽게 하기 위해 helloworld.c 소스를 약간 수정해보겠습니다.

--------------------------------------------------------------
  #include <stdio.h>

  #include <myheader.h>


  int main(int argc,char** argv)
  {
    P("Hello, World\n");

    return 0;
  }
--------------------------------------------------------------

myheader.h 는 현재 디렉토리아래의 common 이라는 디렉토리에 넣어두겠습니다. 그리고 myheader.h 에는 다음과 같은 구문이 정의 되어 있습니다.


#define  P  printf



[그림 6]


위 결과에서 보듯이 참조하는 디렉토리에 /home/thelegend/test/common 이 추가되었습니다. 즉, gcc -I/home/thelegend/test/common  에서 지정한 옵션입니다..