지금의 프로그램은 워낙 방대해져서, 여기저기의 라이브러리들을 참조하여 만들어진다. 여기서는 실제 라이브러리를 만들어보고 이를 사용하는 방법에 대해 설명한다.

예제 프로그램

먼저 라이브러리를 만들기 위해 앞으로 사용할 예제 프로그램을 소개한다. 이해를 돕기위해 아래와 같이 아주 단순하게 만들었다.

#include <stdio.h>
 
int test(void)
{
	printf("test!!!!\n");
 
	return 0;
}
#include <stdio.h>
 
int test1(void)
{
	printf("test1111!!!!\n");
 
	return 0;
}
#include <stdio.h>
 
int test2(void)
{
	printf("test2222!!!!\n");
 
	return 0;
}

라이브러리 생성

위의 예제 코드를 이용하여 각각 라이브러리를 만들어보겠다.

라이브러리를 만들기 위해서는 컴파일을 해야 한다.

#gcc -fPIC -c test.c test1.c test2.c
#ls 
test.c  test.o  test1.c  test1.o  test2.c  test2.o
#file test.o
test.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped

빌드 후에 보면, 각각 오브젝트 파일(.o)이 생성된 것을 알 수 있다. 이 파일들은 실행(excutable)할 수 없다(빌드시 -c 옵션). 이 파일들을 사용하여 static library 를 만들어 보겠다.
아래와 같이 Makefile 을 작성한다.

CC=gcc
 
all: lib static
 
lib:
    gcc -fPIC -c test.c test1.c test2.c
 
static: 
    ar r mytest.a *.o
 
clean:
    rm -f test *.o *.a

오브젝트 파일들을 모아 mytest.a 라는 정적 라이브러리를 생성했다.

이제 앞서 만든 라이브러리를 사용해보자. main.c 라는 소스파일을 만들고, 여기서 앞서 만든 라이브러리에 정의된 함수를 호출해보고, 이를 참조하여 빌드해보겠다.

#include <stdio.h>
 
int main(void)
{
	printf("here is static!!!\n");
 
	test();
	test1();
	test2();
 
	return 0;
}

아래와 같이 Makefile 을 수정하였다.

CC=gcc
 
all: lib static
 
lib:
    gcc -fPIC -c test.c test1.c test2.c
 
static: 
    ar r mytest.a *.o
    gcc main.c mytest.a -o static-main
 
clean:
    rm -f test *.o *.a static-main

빌드 하면, main 이라는 실행파일이 생성된 것을 볼 수 있다.

#./static-main
here is static!!!
test!!!!
test1111!!!!
test2222!!!!
#rm -f mytest.a
#./static-main
here is static!!!
test!!!!
test1111!!!!
test2222!!!!

위와 같이 빌드 시 참조했던 정적 라이브러리 파일을 삭제해도 전과 동일하게 실행된다.

이제는 공유 라이브러리를 만들어 보자! 먼저 Makefile 을 살펴보자.

CC=gcc
 
all: lib static shared
 
lib:
	gcc -fPIC -c test.c test1.c test2.c
 
static:	
	ar r mytest.a *.o
	gcc main.c mytest.a -o static-main
 
shared:
	gcc -shared -Wl,-soname,libmytest.so -o libmytest.so *.o        // 추가 
 
clean:
	rm -f static-main shared-main *.o *.a /lib/x86_64-linux-gnu/libmytest.so

빌드하면 libmytest.so 라는 공유 라이브러리가 만들어 진다.

앞서 생성한 공유 라이브러리를 이용해 빌드해보자.

CC=gcc
 
all: lib static shared
 
 
lib:
	gcc -fPIC -c test.c test1.c test2.c
 
static:	
	ar r mytest.a *.o
	gcc main.c mytest.a -o static-main
 
shared:
	gcc -shared -Wl,-soname,libmytest.so -o libmytest.so *.o
	gcc main.c -L/root/test-0606 -lmytest -o shared-main               // 추가 
 
clean:
	rm -f static-main shared-main *.o *.a /lib/x86_64-linux-gnu/libmytest.so

빌드시에 참조할 공유라이브러리의 경로와 파일명을 옵션 파라미터를 사용하여 지정해주어야 한다. 이때 주의할 것은 라이브러리의 이름으로 앞의 lib 와 뒤의 .so 를 뺀 나머지의 이름, 즉 mytest 가 라이브러리의 이름이다.
빌드되면, shared-main 파일이 생성된다. 이 파일을 실행해보자!

#./shared-main
./shared-main: error while loading shared libraries: libmytest.so: cannot open shared object file: No such file or directory

아래와 같은 에러메세지를 볼 수 있다. 무엇이 잘못된 것일까?
원인을 찾기 위해 strace 라는 프로그램을 사용하자.

#strace ./shared-main 
execve("./shared-main", ["./shared-main"], [/* 35 vars */]) = 0
brk(0)                                  = 0x1b32000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff59eef9000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("tls/x86_64/libmytest.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("tls/libmytest.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("x86_64/libmytest.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("libmytest.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/root/test-0606/tls/x86_64/libmytest.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/root/test-0606/tls/x86_64", 0x7fff01fd9020) = -1 ENOENT (No such file or directory)
open("/root/test-0606/tls/libmytest.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/root/test-0606/tls", 0x7fff01fd9020) = -1 ENOENT (No such file or directory)
open("/root/test-0606/x86_64/libmytest.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/root/test-0606/x86_64", 0x7fff01fd9020) = -1 ENOENT (No such file or directory)
open("/root/test-0606/libmytest.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/root/test-0606", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=83059, ...}) = 0
mmap(NULL, 83059, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7ff59eee4000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/tls/x86_64/libmytest.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu/tls/x86_64", 0x7fff01fd9020) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/tls/libmytest.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu/tls", 0x7fff01fd9020) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/x86_64/libmytest.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu/x86_64", 0x7fff01fd9020) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libmytest.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu", {st_mode=S_IFDIR|0755, st_size=12288, ...}) = 0
open("/usr/lib/x86_64-linux-gnu/tls/x86_64/libmytest.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu/tls/x86_64", 0x7fff01fd9020) = -1 ENOENT (No such file or directory)
open("/usr/lib/x86_64-linux-gnu/tls/libmytest.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu/tls", 0x7fff01fd9020) = -1 ENOENT (No such file or directory)
open("/usr/lib/x86_64-linux-gnu/x86_64/libmytest.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu/x86_64", 0x7fff01fd9020) = -1 ENOENT (No such file or directory)
open("/usr/lib/x86_64-linux-gnu/libmytest.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu", {st_mode=S_IFDIR|0755, st_size=61440, ...}) = 0
open("/lib/tls/x86_64/libmytest.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/tls/x86_64", 0x7fff01fd9020) = -1 ENOENT (No such file or directory)
open("/lib/tls/libmytest.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/tls", 0x7fff01fd9020)        = -1 ENOENT (No such file or directory)
open("/lib/x86_64/libmytest.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64", 0x7fff01fd9020)     = -1 ENOENT (No such file or directory)
open("/lib/libmytest.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
open("/usr/lib/tls/x86_64/libmytest.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/tls/x86_64", 0x7fff01fd9020) = -1 ENOENT (No such file or directory)
open("/usr/lib/tls/libmytest.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/tls", 0x7fff01fd9020)    = -1 ENOENT (No such file or directory)
open("/usr/lib/x86_64/libmytest.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64", 0x7fff01fd9020) = -1 ENOENT (No such file or directory)
open("/usr/lib/libmytest.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib", {st_mode=S_IFDIR|0755, st_size=16384, ...}) = 0
writev(2, [{"./shared-main", 13}, {": ", 2}, {"error while loading shared libra"..., 36}, {": ", 2}, {"libmytest.so", 12}, {": ", 2}, {"cannot open shared object file", 30}, {": ", 2}, {"No such file or directory", 25}, {"\n", 1}], 10./shared-main: error while loading shared libraries: libmytest.so: cannot open shared object file: No such file or directory
) = 125
exit_group(127)                         = ?
+++ exited with 127 +++

출력된 내용을 보면, libmytest.so 라는 공유라이브러리를 찾지 못하는 것이다. 리눅스 시스템에서는 라이브러리를 특정 디렉토리에 저장하고 이 경로에 PATH 를 지정한다. 따라서 공유라이브러리로 빌드된 프로그램은 어디서든 실행이 가능하다.

이 경로가 어디인지 확인하기 위해서, '/etc/ld.so.conf' 파일을 보자. 여기서 다시 '/etc/ld.so.conf.d/x86_64-linux-gnu.conf' 파일을 보면, '/lib/x86_64-linux-gnu/' 아래에 PATH 가 걸린 것을 알 수 있다.
이제 앞서 만든 공유 라이브러리 파일(libmytest.so)을 PATH 가 걸린 곳으로 복사하자.

CC=gcc
 
all: lib static shared
 
 
lib:
	gcc -fPIC -c test.c test1.c test2.c
 
static:	
	ar r mytest.a *.o
	gcc main.c mytest.a -o static-main
 
shared:
	gcc -shared -Wl,-soname,libmytest.so -o libmytest.so *.o
	gcc main.c -L/root/test-0606 -lmytest -o shared-main
	mv libmytest.so /lib/x86_64-linux-gnu/                           // 추가
 
clean:
	rm -f static-main shared-main *.o *.a /lib/x86_64-linux-gnu/libmytest.so

이제 다시 실행해보자.

#./shared-main 
here is static!!!
test!!!!
test1111!!!!
test2222!!!!
#rm /lib/x86_64-linux-gnu/libmytest.so 
rm: 일반 파일 `/lib/x86_64-linux-gnu/libmytest.so'를 제거할까요? y
root@ubuntu:~/test-0606# ./shared-main 
./shared-main: error while loading shared libraries: libmytest.so: cannot open shared object file: No such file or directory

제대로 실행된다. 이 상태에서 공유 라이브러리를 삭제해보자. 실행 에러가 발생하는 것을 알 수 있다.

위의 방법은 PATH 를 잡기 위해 기존의 PATH 가 걸린 곳으로 공유 라이브러리 파일을 복사했다. 하지만, 복사할 필요없이 현재(공유라이브러리가 있는 경로)위치를 바로 PATH 가 걸리게 할 수도 있다.
아래와 같이 쉘에서 실행하자.

#export LD_LIBRARY_PATH=`echo $LD_LIBRARY_PATH`:`pwd`

그리고 다시 shared-main 을 실행해보자.

  • computer/programming/라이브러리_생성_및_사용하기.txt
  • Last modified: 3 years ago
  • by likewind