반응형

===================================================================================================


[gcc 컴파일]


1) gcc 파일명(*.c) : Default로 out 파일이 생성된다. (ex a.out)

2) gcc -c 파일명(*.c) : 오브젝트 파일을 생성한다.

3) gcc -c 오브젝트_파일명(*.o) 파일명(*.c)

   gcc -o 실행파일명(*.out) 오브젝트_파일명(*.o)


4) 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





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

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

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

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

1
2
3
4
5
6
7
8
9
// hello.c
#include <stdio.h>

int main( void )
{
    printf("Hello, world\n");

    return 0;
}



  • 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 의 모습은 이렇다.

                    1
                    2
                    3
                    4
                    5
                    6
                    7
                    8
                    9
                    10
                    11
                    12
                    13
                    .SUFFIXES : .c .o .exe

                    .PHONY : all

                    all : hello.exe

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

                    include hello.d

                    hello.exe : hello.o
                        gcc -o $@ $<



                    이제 make 를 실행하면, hello.c 자체가 수정되거나 hello.c 가 포함하는 헤더 파일이 수정되면 새롭게 빌드된다.

                    그런데 문제는 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 은 다음과 같이 쓰여질 수 있다.

                    1
                    2
                    3
                    4
                    5
                    6
                    7
                    8
                    9
                    10
                    11
                    12
                    13
                    14
                    15
                    16
                    17
                    18
                    19
                    PROGRAM := hello.exe
                    SRCS := hello.c

                    PROGRAM_DEPS := $(SRCS:.c=.o)
                    DEPS := $(SRCS:.c=.d)

                    .SUFFIXES : .c .o .exe

                    .PHONY : all

                    all : $(PROGRAM)

                    $(PROGRAM) : $(PROGRAM_DEPS)
                         gcc -o $@ $^

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

                    -include $(DEPS)



                    위 내용을 보면 특정 이름 대신에 변수를 사용한 것 외에도 몇 가지 달라진 점이 있는데, 하나는 16번째 줄에 있는 암묵적 규칙이고, 14번째 줄에 있는 $^ 이다. 암묵적 규칙은 여러개의 파일에 대해 동일한 규칙을  적용하기 위한 것이고, $^ 은 모든 의존 파일들을 뜻한다. 반면에 $< 은 첫번째 의존 파일을 뜻한다.
                    이렇게 해 두면, 다른 프로젝트에 적용을 한다든지 또는 소스가 변경되었다든지 할 때, PROGRAM 과 SRCS 만 바꾸어주면 된다. 소스 파일을 더 추가하고 싶다면 빈 칸을 사이에 두고 파일 이름을 적어주면 된다. 예를 들어 hello.c 외에 world.c 가 추가되었다면 2번째 줄을 이렇게 바꾸면 된다.

                    • SRCS := hello.c world.c


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

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



                    반응형

                    + Recent posts