[표 1] gcc 옵션
| Option | 의미 |
| -E | 전처리를 실행하고 컴파일을 중단 |
| -c | 소스 파일을 컴파일만 하고 링크를 수행 X, 오브젝트 파일 생성 |
| -o | 바이너리 형식의 출력 파일 이름을 지정, 지정하지 않으면 a.out라는 기본 이름이 적용 |
| -I | 헤더 파일을 검색하는 디렉토리 목록을 추가 |
| -L | 라이브러리 파일을 검색하는 디렉토리 목록을 추가 |
| -l | 라이브러리 파일을 컴파일 시 링크 |
| -g | 바이너리 파일에 표준 디버깅 정보를 포함 |
| -ggdb | 바이너리 파일에 GNU 디버거인 gdb만이 이해할 수 있는 많은 디버깅 정보를 포함 |
| -O | 컴파일 코드를 최적화 |
| -ON | 최적화 N 단계를 지정 |
| -DFOO=RAR | 명령라인에서 BAR의 값을 가지는 FOO라는 선행 처리기 매크로를 정의 |
| -static | 정적 라이브러리를 링크 |
| -ansi | 표준과 충돌하는 GNU 확장안을 취소하며, AnSI/ISO C 표준을 지원한다. 이 옵션은 ANSI 호환 코드를 보장 X |
| -traditional | 과거 스타일의 정의 형식과 같이 정통적인 K&R(Kernighan and Ritchie) C 언어 형식을 지원 |
| -MM | make 호환의 의존성 목록을 출력 |
| -V | 컴파일의 각 단계에서 사용되는 명령을 보여줌 |
많은 옵션 중에 자주 사용하는 옵션을 자세히 다루어 보겠습니다.
- -o 옵션
아무 옵션 없이 gcc를 사용하면 무조건 "a.out"라는 실행 파일을 생성합니다. -o 옵션을 사용하면 원하는 실행 파일의 이름을 생성할 수 있습니다. 이 옵션이 중요한 이유는 서로 다른 c 파일들을 gcc로만 컴파일할 시에 같은 이름의 실행 파일(a.out)로 덮어쓰기가 되므로 이전의 실행 파일이 날아간다.
$ ls
>> test.c
$ gcc test.c
$ ls
>> a.out test.c
$ gcc test.c -o test
$ ls
>> a.out test test.c
- -E 옵션
아래와 같이 "gcc -E test.c"를 입력하면 아래와 같이 전처리된 결과가 화면에 출력이 됩니다. 파일을 저장하려면 -o 옵션을 추가해야 합니다.
$ gcc -E test.c
>> # 1 "test.c"
>> # 1 "<built-in>"
>> # 1 "<command-line>"
>> # 31 "<command-line>"
>> # 1 "/usr/include/stdc-predef.h" 1 3 4
>> # 32 "<command-line>" 2
>> # 1 "test.c"
>> # 1 "/usr/include/stdio.h" 1 3 4
>> # 27 "/usr/include/stdio.h" 3 4
>> ...
>> extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
>> # 868 "/usr/include/stdio.h" 3 4
>>
>> # 2 "test.c" 2
>>
>>
>> # 3 "test.c"
>> int main()
>> {
>> printf("Hello World!\n");
>> return 0;
>> }
- -c 옵션
전처리, 컴파일, 어셈블까지 실행하여 오브젝트 파일을 생성합니다. '분리 컴파일 시' 많이 사용합니다.
$ ls
>> test.c
$ gcc -c test.c
$ ls
>> test.c test.o
- -I 옵션
C소스가 표준 디렉토리가 아닌 위치에 있는 헤더 파일을 가질 때 그 디렉토리의 위치를 지정합니다. 아래 같이 mydir에 있는 myheader.h 파일을 못 읽어 오므로 -I 옵션을 이용하여 사용한다.

$ gcc age.c
>> age.c:2:10: fatal error: myheader.h: 그런 파일이나 디렉터리가 없습니다
>> #include "myhaeder.h"
>> ^~~~~~~~~~~~
>> compilation terminated.
$ gcc age.c -I mydir
$ ./a.out
>> 20
// age.c
#include <stdio.h>
#include "myheader.h"
main()
{
printf("%d\n", AGE);
}
// myheader.h
#define AGE 20
라이브러리 지정 옵션
라이브러리란? 자주 사용되는 유용한 함수에 대한 오브젝트 파일을 모아둔 것, 함수 목록(index)도 포함

책에 의하면 /usr/lib 디렉토리에 라이브러리가 있다고 하는데 나는 없었다...
$ locate libc.a
>> /usr/lib/x86_64-linux-gnu/libc.a
그래서 locate 명령어를 이용하여 검색하니 x86_64-linux-gnu 폴더에 있었다. "libc.a"는 ar 명령어에 의하여 만들어진 아카이브 파일로서 정적라이브러리라고 한다. 이 블로그 글에서는 언급만 하겠다.
이 라이브러리에 있는 오브젝트의 목록을 확인하기 위하여 ar 명령어의 t 옵션을 사용하면,
$ ar t libc.a
>> init-first.o
>> libc-start.o
>> sysdep.o
>> version.o
>> check_fds.o
>> ⋮
다음과 같은 결과가 출력된다.
직접 라이브러리를 만들어 볼 수도 있다.
// minus.c
int minus(int x, int y)
{
return x-y;
}
// plus.c
int plus(int x, int y)
{
return x+y;
}
$ gcc -c plus.c minus.c
$ ls
>> minus.c minus.o plus.c plus.o
$ ar r libmy.a plus.o, minus.o
>> ar: creating libmy.a
$ ls
>> libmy.a minus.c minus.o plus.c plus.o
$ ar t libmy.a plus.o minus.o
- gcc -c plus.c minus.c : plus.c와 minus.c의 오브젝트 파일 생성
- ar r libmy.a plus.o, minus.o : plus.o와 minus.o에 대한 libmy.a 생성
- ar t libmy.a plus.o minus.o : 라이브러리 파일에 목록을 추가(아카이브 인덱스 생성. 아카이브 인덱스를 생성하지 않으면 링크 속도가 느려지고, 시스템 환경에 따라 에러가 발생할 수도 있음)
- -l 옵션 : 표준라이브러리가 아닌 라이브러리를 사용하고자 할 때 그 라이브러리를 지정해 준다. 책의 예에서는 math.h를 이용하여 예를 들었지만 math.h도 표준 라이브러리로 잘 작동하므로 사용 법만 소개드립니다.
$ gcc test.c
>> 라이브러리 오류 발생
$ gcc test.c -l m
>> 잘 작동
gcc의 -l 옵션을 이용하여 libm.a 라이브러리를 가져다 사용한다. 코드를 작성 시에 앞에 "lib"와 뒤에 ".a"를 뺀 나머지 부분만 작성하면 된다.
- -L 옵션
다음은 위에서 만든 libmy.a를 사용하는 방법을 알아보겠다.
다음 c 파일을 컴파일하면 아래와 같은 오류가 발생한다.
# include <stdio.h>
int plus(int x, int y);
int minus(int x, int y);
main()
{
printf("%d %d\n", plus(2,3), minus(2,3));
}
$ gcc 16_9.c
>> /tmp/ccVcSQsD.o: In function `main':
>> 16_9.c:(.text+0x14): undefined reference to `minus'
>> 16_9.c:(.text+0x25): undefined reference to `plus'
>> collect2: error: ld returned 1 exit status
$ gcc 16_9.c -l my
>> /usr/bin/ld: cannot find -lmy
>> collect2: error: ld returned 1 exit status
오류가 발생하는 이유는 링크인 ld가 라이브러리를 찾을 때 /lib, /usr/lib와 같이 정해진 디렉토리만 찾아서다. 그러므로 우리가 만든 libmy.a를 사용하기 위해 libm.a가 있는 디렉토리 lib를 -L 옵션을 이용하여 선언해주면 된다.
$ gcc 16_9.c -l my -L lib
$ ./a.out
>> 5 -1
디버깅 관련 옵션
- -g, -ggdb 옵션
[표 2] -g 옵션의 단계
| 옵션 | 의미 |
| -g1 | 역추적 스택 덤프 생성에 필요한 정보를 포함하지만 지역변수, 문장 번호를 위한 디버깅 정보는 삽입 X |
| -g2 | 확장 기호 테이블, 묹ㅇ 번호, 지역과 외부 변수에 대한 디버깅 정보를 삽입 |
| -g3 | -g2 옵션의 디버깅 정보와 모든 매크로 정의를 삽입 |
// 16_10.c
#include <stdio.h>
main()
{
printf("debugging");
}
$ gcc 16_10.c -o debug
$ gcc -g1 16_10.c -o debug1
$ gcc -g2 16_10.c -o debug2
$ gcc -g3 16_10.c -o debug3
$ ls -l deb*
>> -rwxrwxr-x 1 heewon heewon 8304 4월 18 15:02 debug
>> -rwxrwxr-x 1 heewon heewon 9152 4월 18 15:02 debug1
>> -rwxrwxr-x 1 heewon heewon 10752 4월 18 15:02 debug2
>> -rwxrwxr-x 1 heewon heewon 35048 4월 18 15:02 debug3
- 디버깅 정보가 포함되어 용량이 커진다. 그러므로 최종 파일은 디버깅 옵션 없이 해야 한다.
- 최적화된 코드는 디버깅을 어렵게 만들기 때문에 최적화 수행 전에 디버깅을 하는 것이 좋다.
최적화 옵션
- -O 옵션
불필요하거나 비효율적인 계산 과정이 효율적 계산과정으로 대체되어 코드의 크기와 실행 시간을 줄여주는 방법, 하지만 컴파일 시간이 늘어나고 컴파일 과정에서 메모리 사용량이 늘어난다.
[표 3] -O 옵션의 단계
| 옵션 | 의미 |
| -O1 | -O 옵션과 같은 단계의 옵션으로 최소한으로 스레드 분기 동작 횟수를 줄이고, 호출된 각 함수 반환 시 스택에 인수를 모아 두었다 동시에 꺼내게 해준다. |
| -O2 | -O1 단계의 최적화와 함께 프로세서가 다른 명령어의 결과나 캐시 메모리 또는 메모리의 데이터를 기다리는 동안 컴파일러가 다른 명령어를 실행하도록 한다. 컴파일 시간이 더 오래 걸리지만, 수정된 코드는 더 최적화되어 실행이 빨라진다. |
| -O3 | -O2 단계의 모든 최적화와 루프 해체, 그 밖의 프로세서 전용 특징을 포함 |
※ 이 글은 책 "초보자를 위한 Linux&Unix C 프로그래밍"을 기반으로 작성하였습니다.
'System > Linux' 카테고리의 다른 글
| <Linux> gcc 동작 과정 (3) | 2022.04.15 |
|---|---|
| <Linux> Error: Dpkg: Error Processing [Something] (--Configure) (0) | 2022.04.14 |
| <Linux> Ubuntu 9.04에서 apt-get update 오류 해결법!(Some index files failed to download, they have been ignored, or old ones used instead) (0) | 2022.04.07 |
| <Linux> Command와 Command를 이어 주는 문법 (0) | 2022.03.29 |
| <Linux> Ubuntu 터미널 기본 command 와 단축키 (1) | 2022.03.28 |