A.4.1 hello.c 를 컴파일 하기
$ gcc hello.c
$ ./a.out
hello.c 를 위와 같이 컴파일 하게 되면 실행 파일 명이 자동으로 a.out으로 정해집니다. 따라서 두 번째 명령어로 a.out을 실행시킵니다.
A.4.2 -o 옵션
위의 hello.c 를 컴파일 한 결과가 a.out으로 만들어 졌는데 이것을 우리가 원하는 이름 (ex.hello)로 만들고 싶을 때 -o 옵션을 사용합니다. o는 output의 약자이며 출력 파일 명의 이름을 지정하는 옵션입니다.
$ gcc -o hello.o hello.c
or
$ gcc hello.c -o hello
순서를 바꿔도 무방합니다. (참고로 저는 첫 번째를 사용하고 있습니다) 그리고 실행은 ./hello로 하면 됩니다.
A.4.3 -c 옵션
컴파일 작업만 할 경우에 사용합니다. c는 compile의 약자이며 오브젝트 파일(.o)만 만듭니다.
$ gcc -c hello.c
를 할 경우에 hello.o 파일이 만들어집니다.
A.4.4 여러 소스파일 묶어 실행 파일 만들기
어떤 프로그램의 소스 파일이 foo.c와 bar.c로 이루어져 있다고 가정하고, baz라는 이름의 실행 파일을 만들 때는
$ gcc -o baz foo.c bar.c
$ ./baz
로 한방에 처리를 할 수 있는 반면 번거롭게 두 단계를 거쳐 할 수도 있습니다.
$ gcc -c foo.c
$ gcc -c bar.c or $ gcc -c foo.c bar.c
를 한 다음에
$ gcc -o baz foo.o bar.o
를 해도 동일한 결과인 실행 파일 baz가 생성됩니다.
gcc는 c컴파일런데 어떻게 오브젝트 파일(.o)를 써도 될까 라는 의문이 드는데, 사실 gcc는 c 컴파일러가 아닌 c 컴파일러를 수행하는 프로그램입니다. c 언어에서 실행파일을 만드려면 2단계로 이루어 집니다.
- compile (컴파일러가 .c를 .o로 만드는 과정)
- link (링커가 .o와 라이브러리 파일을 링크해 실행 파일 a.out을 만드는 과정)
실제로 1번을 수행하는 놈은 c 컴파일러의 실질적 이름인 cc1이 수행을 하고 2번은 링커의 이름인 ld가 수행합니다.
gcc -o baz foo.c bar.c 를 수행할 때 gcc는 .c와 .o의 파일 확장자를 구별 해 적절하게 cc1(c 컴파일러)와 ld(링커)를 수행합니다(.c 인 경우에는 cc1, .o인 경우에는 링커를 불러 수행하겠죠)
A.4.5 -I 옵션(대문자 i)
-I 옵션은 헤더파일이 들어있는 곳을 지정해주는 옵션입니다.
#include <stdio.h> vs #include "myHeader.h"
<stdio.h>같은 경우에는 시스템 표준 헤더 디렉토리인 /usr/include 기준으로 찾아 포함시킵니다. 반면에 "myHeader.h"는 현재 컴파일러가 실행되고 있는 현재 디렉토리를 기준으로 헤더 파일을 찾습니다. 만약 현재 컴파일러가 실행되고 있는 현재 디렉토리와 다른 경로에 헤더파일을 include하기 위해서는 명시적으로 -I<디렉토리>로 정해줍니다.
$gcc -c myDS -I..
$gcc -c myDS -ImyLib
첫 번째는 헤더파일이 부모 디렉토리에 헤더파일이 존재할 경우에 사용합니다. 두 번째는 현재 디렉토리의 myLib디렉토리에 있다는 뜻입니다.
A.4.6 라이브러리
라이브러리는 프로그래밍을 할 때 반복적으로 사용하는 함수들을 따로 떼서 모아놓은 것을 의미합니다. 이점은 매번 컴파일 할 필요 없이 그냥 링커가 링크만 하면 사용할 수 있습니다. 컴파일 할 필요 없는 이유는 라이브러리 안에 오브젝트 파일(-o)가 모아져 있습니다.
라이브러리 확장자는 (.a)인데 이는 archive를 의미합니다.
라이브러리(도서관)에 인덱스가 존재하듯이 라이브러리 파일에도 인덱스가 존재합니다. 만약 도서관에 책을 순서 없이 집어 넣는 다면 책을 찾기가 힘든 것과 같습니다. 라이브러리의 구성은 아래와 같습니다.
- 라이브러리 = 목차(index) + (a.o + b.o + c.o +.....)'
실제로 /usr/lib 디렉토리에 있는 라이브러리 파일 libc.a를 열어보면(라이브러리 파일의 이름은 lib로 시작합니다)
$ cd /usr/lib
$ ar t libc.a
iofprintf.o
ioprintf.o
iosprintf.o
....
많은 오브젝트 파일(.o)들이 libc.a에 담겨 있는 것을 볼 수 있습니다.
이번에는 3개의 소스 파일(.c)을 이용해 직접 예제 라이브러리를 만들어보겠습니다. 파일명은 foo.h, foo.c, main.c 입니다.
// foo.h
extern void foo_hello(void);
// foo.c
#include <stdio.h>
#include "foo.h"
void foo_hello(void)
{
printf("foo_hello\n");
}
// main.c
# include "foo.h"
int main(void)
{
foo_hello();
return 0;
}
라이브러리를 만들기 위해서 다음 명령어를 칩니다.
$ gcc -c foo.c
$ ar r libmylib.a foo.o
$ ar s libmylib.a
$ ar t libmylib.a foo.o
$ gcc -o main foo.c -lmylib
를 치면 ld: cannot open -lmylib: No such file or directory와 같은 에러 메세지를 뱉습니다. 하지만 아래 글을 계속 따라가면 에러는 없어집니다.
-l 옵션(소문자 L)
-l은 링크할 라이브러리의 이름을 명시 해주는 옵션입니다. 헤더파일의 경로를 지정했을 때 썼던 -I(대문자 i)처럼 경로를 바짝 붙여 씁니다.
위에서 라이브러리 파일인 libmylib.a를 만들었는데 막상 사용은 -lmylib로 했습니다. 이유는 애초에 라이브러리 파일의 시작 이름이 lib이기 때문입니다. 그리고 -l 옵션은 애초에 라이브러리를 링크하므로 확장자도 생략해주세요. 바뀐 이름을 잘 기억해주시길 바랍니다.
-L 옵션
위에서 라이브러리의 이름을 명시 해주었다면 이번에는 라이브러리의 경로를 지정해주어야 합니다. 어느 때와 마찬가지로 바짝 붙여 씁니다. 형식은 -L<디렉토리명> 입니다. 리눅스에서 라이브러리를 찾을 때 헤더 파일을 찾는 것과 마찬가지로 /lib, /usr/lib, /usr/local/lib와 같은 정해진 경로에서만 찾게 되있습니다. 에러는 다음과 같이 고칩니다.
추가로 #include "헤더파일명.h"와 세트인 -I(대문자 i) 옵션 같은 경우에는 현재 컴파일이 실행되는 디렉토리에서 헤더파일을 찾았습니다. 반면에 링커 ld는 현재 작업 디렉토리에 라이브러리 파일이 있어도 절대 찾지 않습니다. 따라서 ld에게 라이브러리의 위치를 정확히 알려줘야 합니다. 아래와 같이 타이핑 하면 현재 디렉토리(-L.)에 있는 libmylib.a 파일을 링킹합니다.
$ gcc -o main foo.c -lmylib -L.
그리고 ./main 으로 실행을 확인합니다
출처 : http://doc.kldp.org/KoreanDoc/html/gcc_and_make/gcc_and_make-1.html
'OS > Embedded OS' 카테고리의 다른 글
부록 A.5 Makefile을 짜보자 (0) | 2021.08.24 |
---|---|
부록 A.3 실행 파일 형식 (0) | 2021.08.24 |
부록 A.2 ABI (0) | 2021.08.24 |
부록 A.1 ARM 아키텍처 기초 지식 (0) | 2021.08.16 |
2장 개발 환경 구성하기 (0) | 2021.08.14 |