GCC(GNU Compiler Collection) : C, C++, Java 등의 컴파일 언어를 컴파일하는 컴파일러의 일종이다. 여기서는 C언어를 대상으로 이야기한다.
컴파일 : C언어로 작성된 각각의 소스코드를 어셈블리어로 변환. 결과로 오브젝트 파일이 생성됨.
링크 : 모든 오브젝트 파일을 엮어 binary 파일로 변환해 하나의 실행가능한(executable) 파일을 생성. (.exe 또는 .out 등)
int main(){
foo();
return 0;
}
void foo(){
int a = 1;
}
main.c, func.c 2개의 소스코드를 컴파일하면 컴파일 에러가 발생한다.
gcc -c main.c func.c
그 이유는 모든 소스코드들이 독립적으로 오브젝트파일을 생성해야하는데 main.c에서 사용되는 foo()라는 함수의 정의는 func.c에만 있기 때문이다.
이를 해결하기 위해서는 main.c에 foo()라는 함수를 "선언"해주면 된다.
함수의 정의는 컴파일 과정에서 알 필요 없으므로 에러가 발생하지 않는다.
void foo();
int main(){
foo();
return 0;
}
컴파일을 통해 main.o, func.o가 생성되면 이를 이용해 링크를 수행한다.
gcc main.0 func.0
결과로 실행가능한 a.exe(또는 a.out)파일이 생성되고 이를 실행할 수 있다.
./a.out
이와같이 다른 소스코드의 함수를 사용하려면 함수를 선언해주어야 한다. 이 번거로운 과정을 생략하기 위해 헤더(.h)파일을 이용한다.
#include "func.h"
int main(){
foo();
return 0;
}
void foo();
#include "func.h"
void foo(){
int a = 1;
}
이전과 같이 컴파일+링크를 진행해보니 별 문제가 없어 보인다.
위에서는 컴파일과 링크를 분리해서 진행했지만, 한번에 할 수도 있다.
gcc main.c func.c
./a.out
헤더파일이 다른 경로에 있다면 어떻게 될까?
func.h파일을 다른 경로로 옮긴 뒤 똑같이 시도해보니 컴파일 에러가 발생한다.
컴파일 과정에서 현재 경로나 지정된 경로에서만 헤더파일을 탐색하기 때문에 func.h를 찾지 못한 것인데, -I 커맨드를 이용해 헤더파일 탐색 경로를 추가해줄 수 있다.
gcc -I ./dir main.c func.c
func.c와 func.h를 이용해서 static library를 생성하고 이를 main.c에서 사용해보자.
우선 func.c, funch를 이용해 컴파일을 진행, func.o를 얻는다.
gcc -c -I ./dir func.c
static library를 만들기 위해서는 archiver를 이용해야하는데, ar 커맨드를 이용해 사용할 수 있다.
윈도우의 경우 정적 라이브러리의 확장자가 lib이고 리눅스의 경우는 a이다.
ar rcs libfunc.a func.o
결과로 libfunc.a가 생성된다.
libfunc.a의 foo 함수를 main.c에서 사용하기 위해서는 -L 커맨드를 이용해 라이브러리가 존재하는 경로를 라이브러리 탐색 경로로 추가해주어야 하고, -l 커맨드를 이용해 내가 사용할 탐색 경로 내에 있는 라이브러리를 지정해주어야 한다.
gcc -c main.c -I ./dir # main.o 생성. 헤더파일 경로를 추가해주기 위해 -I 사용.
gcc main.o -L . -l func # libfunc.a를 func로 생략가능.
# 위 2줄을 1줄에 수행
gcc main.c -I ./dir -L . -l func
func.c에 대한 오브젝트 파일을 생성할 때 -fPIC 옵션을 추가해야한다.
gcc -c -fPIC -I ./dir func.c
-shared 커맨드를 추가하고, -o 옵션에서 libfunc.so로 라이브러리 이름을 정해준다.
gcc -shared -o libfunc.so -I ./dir func.o
libfunc.so 파일이 생성되고 main.c와 함께 executable을 생성할 수 있다.
gcc main.c -L . -I ./dir -l func
이를 실행하려고하면 libfunc.so를 찾을 수 없다는 에러가 발생하는데, 동적 라이브러리는 실행 중에도 해당 라이브러리가 필요하기 때문에 런타임 중에 시스템이 so파일을 읽어올 수 있도록 so파일의 경로가 LD_LIBRARY_PATH에 포함되어야 한다.
echo 'export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/so파일이/포함된/폴더' >> ~/.bashrc
터미널을 재시작하거나 source ~/.bashrc
커맨드 후 executable을 실행해보니 정상적으로 작동한다.