카테고리 없음

gcc 컴파일 옵션 정리

Jay.P Morgan 2023. 10. 3. 00:28

[gcc 컴파일]

  1. gcc 파일명(*.c) : Default로 out 파일이 생성된다. (ex a.out)
  2. gcc -c 파일명(*.c) : 오브젝트 파일을 생성한다.
  3. gcc -c 오브젝트_파일명(*.o) 파일명(*.c)
  4. gcc -o 실행파일명(*.out) 오브젝트_파일명(*.o)
  5. gcc -o 실행파일 파일명(*.c) : 실행 파일을 만든다. (3번을 한줄로...)

[gcc 옵션]

  1. -Wall 옵션 : 모든 모호한 코딩에 대해서 경고를 보내는 옵션
  2. -W 옵션 : 합법적이지만 모호한 코딩에 대해서 경고를 보내는 옵션
  3. -W -Wall 옵션 : 아주 사소한 모호성에 대해서도 경고가 발생
  4. O2 옵션 : 최적화 레벨 2로 설정. (대부분의 최적화를 시도)
  5. -E 옵션 : 전처리 과정의 결과를 화면에 보이는 옵션(전처리과정 중 발생한 오류를 검증)
    ※ enhanced Tip: --save-temps 옵션
  6. -S 옵션 : cc1으로 전처리된 파일을 어셈블리 파일로 컴파일까지만 수행하고 멈춘다.
    (*.s)`
  7. -c 옵션 : as에 의한 어셈블까지만 수행하고 링크는 수행하지 않는다.
  8. -v 옵션 : gcc가 컴파일을 어떤 식으로 수행하는지를 화면에 출력한다.
  9. --save-temps 옵션 : 컴파일 과정에서 생성되는 중간 파일인 전처리 파일(*.i)과 어셈블리 파일(*.s)을 지우지 않고, 현재 디렉토리에 저장한다.(오류 분석에 사용)

[cpp0 옵션]

: 소스내에서 사용된 헤더 파일과 define 매크로와 관련된 옵션들이다.

전처리 과정에서 오류가 발생한다면 cpp0 옵션들을 점검해야 한다.

  1. -l 옵션 : 전처리 과정에서 헤더 파일을 탐색하는 기본 디렉토리를 추가할 때 사용하는 옵션
  2. -include 옵션 : 헤더 파일을 소스내에 추가할 때 사용한다.
  3. -D[매크로] 옵션 : 매크로를 외부에서 define 할 때 사용한다.
  4. -D[매크로]=[매크로 값] 옵션 : 소스 내에 #define [매크로] [매크로 값] 옵션을 추가한 것과 동일하다.
  5. -U[매크로] 옵션 : -D와 반대로 소스 파일 내에 #undef[매크로] 옵션을 추가한 것과 동일하다.
  6. -M / -MM 옵션 :
    -M 옵션 - make를 위한 소스 파일의 모든 종속 항목을 출력
    -MM 옵션 - 기본 include 디렉토리에 있는 헤더 파일은 빼고 종속 항목을 출력한다.
  7. -nostdinc 옵션 : 디폴트 include 디렉토리(usr/include)에서 헤더 파일을 탐색하지 않고, -l 옵션으로 추가한 디렉토리에서만 헤더 파일을 찾는다.
  8. -C 옵션 : -E 옵션과 함께 사용하며, 전처리 과정에서 주석을 제거하지 않는다.
  9. -Wp,[옵션들] 옵션 : 만약 cpp0와 gcc의 옵션이 같은 것으로 중복되면 gcc 옵션으로 해석되므로,
        gcc의 해석을 거치지 않고 바로 cpp0 옵션으로 전달하고 싶을 때 사용한다.

[cc1 옵션]

: "C언어 옵션, 경고 옵션, 최적화 옵션, 디버깅 옵션"의 4가지 종류

"경고 수위 조절 or 최적화 수위 조절"을 하고 싶을 때 사용한다.

1. C언어 옵션 : C언어 종류와 표준에 관련된 옵션

    1) -ansi 옵션 : ANSI C 표준에 부합하는 소스를 작성하고자 할 때 사용하는 옵션

    2) -std=\[C 표준들\] 옵션 : 기타 다른 표준들을 지정하고자 할 때 사용한다.

    3) -traditional 옵션 : 오래된 Traditional C 문법으로 문법을 검사한다.

    4) -fno -asm 옵션 : gnu89 문법을 바탕으로 asm, inline, typeof 키워드를 사용하지 않기를 원할 때 사용한다.

2. 경고 옵션 : cc1의 옵션을 조정하여 경고 수위를 조절할 수 있다.

    1) -W / -Wall 옵션 (gcc 옵션 참고)

    2) -w(소문자) 옵션 : 모든 경고 메시지를 제거한다.

    3) -Werror 옵션 : 모든 경고를 컴파일을 중단하는 오류로 취급한다.
             (경고가 하나만 나와도 컴파일이 중단된다.)

    4) -pedantic 옵션 : ANSI C89 표준에서 요구하는 모든 경고 메시지를 표시한다.

    5) -pedantic-errors 옵션 : ANSI C89 표준에서 요구하는 모든 오류 메시지를 표시한다.

    6) -Wtraditional 옵션 : 소스가 ANSI C와 K&R C 간에 서로 다른 결과를 가져올 수 있는 부분이 있다면 경고한다.

3. 최적화 옵션 :

            ⓐ 실행 파일의 크기를 줄여 메모리와 하드디스크의 사이즈를 절약 (큰 의미 X)
            ⓑ 실행 파일의 크기를 줄여 실행 속도를 향상시키는 것.
    1) -O0 옵션 : 최적화를 수행하지 않는다.

    2) -O1 옵션 : -O0보다는 조금 낫다.

    3) -O2 옵션 : 가장 많이 사용하는 옵션. 일반 응용 프로그램이나 커널을 컴파일 할 때 사용
                 (거의 대부분의 최적화를 수행한다.)

    4) -O3 옵션 : 가장 높은 레벨의 최적화. 모든 함수를 인라인 함수와 같이 취급한다.
                (Call 인스트럭션은 사용 X. but, 되도록이면 사용하지 않는 것이 좋다. 

               → 너무나 많은 소스의 변경이 가해지기 때문에 왜곡이 발생할 위험이 있다.)

    5) -O5 옵션 : 사이즈 최적화를 실행한다. (공간이 협소한 곳에서 사용 - 임베디드 시스템)

4. 디버깅 옵션

    1) -g 옵션 : gdb에게 제공하는 정보를 바이너리에 삽입한다.
                (-g 옵션을 사용하지 않고 gdb로 디버깅하면, 역어셈 → 어셈블리 코드로만 디버깅 가능)

    2) -pg 옵션 : 프로파일을 위한 코드를 삽입한다.
                (-pg 옵션으로 컴파일 → gmon.out(프로파일 정보) → gprof로 gmon.out 파일 분석)

[as의 옵션]

: gcc는 as의 옵션에 대해서는 알지 못한다. -Wa,[as 옵션들] 형식으로 gcc를 거치지 않고 바로 전달해야 한다.

-Wa, -al, -as와 같은 형식으로 사용하면 as에게 -al -as 옵션이 같이 전해진다.

-Wa,[as 옵션들]

    1) -al 옵션 : 어셈블된 인스트럭션을 보인다.

    2) -as 옵션 : 정의된 심볼을 보인다.

    3) -l\[패스\] 옵션 : include 디렉토리를 지정한다. 어셈블리 소스 내에서 사용된 include 지정자가 지정하는 헤더파일을 찾고자 할 때 사용한다.

    4) -W / --no-warn : 경고 메시지를 출력하지 않는다.

    5) -march=\[아키텍처 문자열\] : 해당 어셈블리

[collect2 / ld 옵션]

: 링크 옵션

    1) -L\[라이브러리 디렉토리\] 옵션 : 라이브러리를 찾을 디렉토리를 지정한다.

    2) -l 옵션 : 같이 링크할 라이브러리를 지정한다.

    3) -shared 옵션 : 공유 라이브러리와 정적 라이브러리가 같이 있을 경우, 공유 라이브러리를 우선하여 링크한다.
                    (아무 옵션을 주지 않아도 공유 라이브러리를 우선으로 링크한다.)

    4) -static 옵션 : 정적 라이브러리와 공유 라이브러리가 같이 있다면, 정적 라이브러리를 우선하여 링크한다.
                    (속도는 빠르지만 파일 사이즈가 커진다는 점 고려할 것!)

    5) -nostdlib 옵션 : 링크시에 표준 C 라이브러리를 사용하지 않는다.
                    (OS, 부트로더와 같은 프로그램을 컴파일 할 때 사용)

    6) -nostartfiles 옵션 : crt1.o 등과 같은 start up 파일을 링크하지 않는다.
                    (OS, 부트로더와 같은 프로그램을 컴파일 할 때 사용)

    7) -Wl,\[링크 옵션들\] 옵션 : gcc를 거치지 않고 바로 링크에게 옵션을 정해주고자 할 때 사용한다. (사용법은 -Wa와 동일한다.)

< 유용한 링크 옵션들 >


            ① -s 옵션 : 실행 파일에서 심볼 테이블을 제거

            ② -x 옵션 : 출력 파일에서 로컬 심볼 제거

            ③ -n 옵션 : 텍스트 영역을 읽기 전용으로 만듬

            ④ -r 옵션 : 추후 링크가 가능하게 오브젝트를 만듬

            ⑤ -e \[name\] 옵션 : 시작 심볼을 name 심볼로 사용 (default 시작심볼 : \_start 심볼)

            ⑥ -M 옵션 : 심볼들의 정보를 자세하게 출력

            ⑦ oformat \[format\] 옵션 : 주어진 형식의 오브젝트 파일을 생성

출처 : http://lvzuufx.blogspot.kr/2014/09/gnu-make-gcc-auto-dependency-makefile.html

[GNU Make 와 gcc 를 이용한 auto-dependency Makefile 만들기

OS/2, 프로그래밍, 컴퓨터, 과학, 일상의 기록

lvzuufx.blogspot.com](http://lvzuufx.blogspot.kr/2014/09/gnu-make-gcc-auto-dependency-makefile.html)

Autotools, CMake, qmake 같은 빌드 도구나 Open Watcom 의 wmake 같은 경우에는 자체적으로 auto-dependency 를 지원하거나 이를 위한 지시자를 제공한다. 하지만 GNU Make 의 경우에는 이러한 기능을 자체적으로 지원하지도 않고, 이를 위한 지시자를 제공하지도 않는다.

하지만, 다행히도 gcc 를 이용해서 이 기능을 구현할 수 있다. 우선 이에 필요한 gcc 의 기능부터 살펴보자.

-M 옵션 : 해당 소스 파일의 의존성을 GNU Make 의존성 규칙에 맞추어 출력한다. 시스템 헤더 파일들도 포함된다.

예를 들어, 다음과 같은 hello.c 를 생각해보자.

Colored By Color Scripter™

  • gcc -M hello.c

이를 실행한 결과는 이렇다.

  • hello.o: hello.c f:/lang/gcc/usr/include/stdio.h \
  • f:/lang/gcc/usr/include/sys/cdefs.h \
  • f:/lang/gcc/usr/include/sys/gnu/cdefs.h \
  • f:/lang/gcc/usr/include/features.h f:/lang/gcc/usr/include/sys/_types.h \
  • f:/lang/gcc/usr/include/machine/_types.h \
  • f:/lang/gcc/usr/include/386/_types.h

-MM 옵션 : -M 옵션과 비슷한데, 시스템 헤더 파일은 제외한다.

  • gcc -MM hello.c

다음은 실행 결과이다.

  • hello.o: hello.c

-MP 옵션 : -M 또는 -MM 옵션과 함께 쓰일 때, 헤더 파일들에 대한 phony 타겟을 만든다. 이는 헤더 파일이 지워졌을 때, 오류가 발생하는 것을 방지한다.

  • gcc -M -MP hello.c

다음은 실행 결과이다.

  • hello.o: hello.c f:/lang/gcc/usr/include/stdio.h \
  • f:/lang/gcc/usr/include/sys/cdefs.h \
  • f:/lang/gcc/usr/include/sys/gnu/cdefs.h \
  • f:/lang/gcc/usr/include/features.h f:/lang/gcc/usr/include/sys/_types.h \
  • f:/lang/gcc/usr/include/machine/_types.h \
  • f:/lang/gcc/usr/include/386/_types.h
  • f:/lang/gcc/usr/include/stdio.h:
  • f:/lang/gcc/usr/include/sys/cdefs.h:
  • f:/lang/gcc/usr/include/sys/gnu/cdefs.h:
  • f:/lang/gcc/usr/include/features.h:
  • f:/lang/gcc/usr/include/sys/_types.h:
  • f:/lang/gcc/usr/include/machine/_types.h:
  • f:/lang/gcc/usr/include/386/_types.h:

-MT 옵션 : -M 또는 -MM 옵션과 함께 쓰일 때, 타겟의 이름을 바꾼다.

  • gcc -M -MT hello_MT.o hello.c

다음은 실행 결과이다.

  • hello_MT.o: hello.c f:/lang/gcc/usr/include/stdio.h \
  • f:/lang/gcc/usr/include/sys/cdefs.h \
  • f:/lang/gcc/usr/include/sys/gnu/cdefs.h \
  • f:/lang/gcc/usr/include/features.h f:/lang/gcc/usr/include/sys/_types.h \
  • f:/lang/gcc/usr/include/machine/_types.h \
  • f:/lang/gcc/usr/include/386/_types.h

-MF 옵션 : -M 또는 -MM 옵션과 함께 쓰일 때, 출력 결과를 해당 장치 또는 파일로 보낸다.

  • gcc -M -MF hello.d hello.c

이 때 실행 결과는 표준 출력 장치에 나타나는 것이 아니라 hello.d 라는 파일에 저장된다.

바로 이 옵션들을 통해서 auto-dependecy Makefile 파일을 만들 수 있다. 문제는 이 내용을 Makefile 파일에서 어떻게 활용할 것인가이다.

의존성 파일부터 만들어 보자. 의존성 파일을 만들기 위한 기본적인 형태는 다음과 같다.

  • hello.d : hello.c
  • gcc -M -MP -MF $@ $<

이제는 이렇게 만들어진 의존성 파일을 포함시켜야 한다. GNU Make는 이를 위해 include 지시자를 지원한다.

  • include hello.d

이때 hello.d 가 없다면 주어진 생성 규칙을 통해서 새로이 만들거나 갱신한다. 그럼에도 불구하고 hello.d 를 만들 수 없다면, GNU Make 는 오류를 보고하고, 중지한다.

마지막으로 실행 파일의 의존성 규칙을 추가해주면 된다.

  • hello.exe : hello.o

물론 다음과 같은 기본적인 내용이 Makefile 앞 부분에 더 추가되어야 한다.

  • .SUFFIXES : .c .o .exe
  • .PHONY : all
  • all : hello.exe

완성된 Makefile 의 모습은 이렇다.

Colored By Color Scripter

그런데 문제는 hello.d 파일 자체는 한 번 만들어지면 hello.c 가 수정되지 않는 이상, 다시 갱신되지 않는다. 왜냐하면 hello.d 파일에 대한 의존성은 hello.c 밖에 없기 때문이다. 이 문제는 hello.d 의 의존성을 hello.o 의 의존성과 동일하게 만들어주면 된다. 위 8번째 줄을 아래와 같이 바꾸자.

  • gcc -M -MP -MT "$(@:.d=.o) $@" -MF $@ $<

GNU Make 의 다중 대상 기능을 이용한 것으로. 타겟이 "hello.o" 에서 "hello.o hello.d" 로 된다.

GNU Make 를 실행하다보면 hello.d 가 지워진 경우에, 다음과 같은 오류 메세지가 출력된다.

  • Makefile:10: hello.d: No such file or directory

이 오류 메세지가 나오더라도 중단되지는 않지만, 뭔가 꺼림칙하다. 어떻게 없앨 수 없을까 ? 바로 -include 를 쓰면 된다.

이 예제의 경우에는 소스 파일이 하나에 불과해서 이 정도이지만, 소스 파일이 여러 개일 경우에는 해당 소스 파일마다 일일이 추가해줘야 한다. 그리고 다른 프로젝트에 쓰기에도 수정해야 할 것이 많다. 이 얼마나 불편한가 ? 이를 개선해 보자.

우리가 고려할 것은 실행 파일과, 소스 파일이다. 다른 모든 것들은 이들로부터 변형될 수 있다. 이들을 위한 변수를 도입하자. PROGNAME 과 SRCS 에 실행파일과 소스 파일을 담자.

  • PROGNAME := hello.exe
  • SRCS := hello.c

이제 의존성 파일 변수와 실행 파일을 만들기 위한 목적 파일 변수를 도입하자.

  • PROGNAME_DEPS := $(SRCS:.c=.o)
  • DEPS := $(SRCS:.c=.d)

이 내용들을 반영하면 위 Makefile 은 다음과 같이 쓰여질 수 있다.

Colored By Color Scripter™

Colored By Color Scripter

위 내용을 보면 특정 이름 대신에 변수를 사용한 것 외에도 몇 가지 달라진 점이 있는데, 하나는 16번째 줄에 있는 암묵적 규칙이고, 14번째 줄에 있는 $^ 이다. 암묵적 규칙은 여러개의 파일에 대해 동일한 규칙을 적용하기 위한 것이고, $^ 은 모든 의존 파일들을 뜻한다. 반면에 $< 은 첫번째 의존 파일을 뜻한다.

이렇게 해 두면, 다른 프로젝트에 적용을 한다든지 또는 소스가 변경되었다든지 할 때, PROGRAM 과 SRCS 만 바꾸어주면 된다. 소스 파일을 더 추가하고 싶다면 빈 칸을 사이에 두고 파일 이름을 적어주면 된다. 예를 들어 hello.c 외에 world.c 가 추가되었다면 2번째 줄을 이렇게 바꾸면 된다.

  • SRCS := hello.c world.c

이외에도 여러가지 컴파일 플래그나 링커 플래그, 컴파일러나 링커를 위한 여러 변수들을 도입하면 훨씬 더 유연한 Makefile 이 될 것이다.

그리고 기회가 된다면 추후에 여러 개의 실행 파일과 DLL 등을 한꺼번에 빌드할 수 있는 Makefile 에 대해서도 글을 쓰도록 하겠다.