Creating Static Libraries in Linux
1. 오브젝트 파일 컴파일
2. 아카이브 파일 생성
3.
$gcc -Og -c foo.c bar.c //1단계
$-r[cs] libmy.a foo.o bar.o // 2단계 cs생략가능. 아카이브 파일 생성 명령어. 아카이브 이름 충돌 생기지 않도록!!
//-r, -rc, -rs
$ar -t libmy.a //아카이브에 해당하는 오브젝트 파일 보기
$nm -s libmy.a //아카이브의 심볼테이블 보기
$ar -x libmy.a
//반대로 ar -x 옵션 설정 시 아카이브가 오브젝트 파일들로 풀리게 된다.
리눅스에서 ar 명령어는 아카이브 파일(보통 .a 파일)을 생성하거나 수정하는 데 사용된다. ar 명령어의 옵션들인 -r, -rc, -rs는 비슷한 목적을 가지고 있지만, 각각의 동작은 약간씩 다르다.
ar -r
- 기본적인 기능: 기존 아카이브 파일에 파일을 추가하거나 기존 파일을 교체하는 데 사용된다.
- 동작 방식:
- 아카이브 파일에 지정된 파일을 추가한다.
- 이미 아카이브에 동일한 이름의 파일이 있으면, 그 파일을 교체한다.
- -r 옵션은 파일을 덧붙이는 방식으로 동작하며, 아카이브 내 파일의 순서나 정렬에 영향을 주지 않는다.
ar -rc
- 기본적인 기능: -r 옵션과 유사하지만, 아카이브 파일이 없다면 새로 생성하고, 새로 추가된 파일이 아카이브의 맨 앞에 오도록 한다.
- 차이점:
- -c 옵션은 아카이브가 이미 존재하는 경우, 기존 파일을 덮어쓰지 않고, 아카이브에 파일을 추가하도록 한다.
- 아카이브가 없으면 새로 생성하고, 추가된 파일은 아카이브의 앞에 배치된다.
ar -rs
- 기본적인 기능: -r과 -s 옵션을 조합한 것이다.
- 동작 방식:
- -r: 아카이브에 파일을 추가하거나 교체한다.
- -s: 아카이브 파일에 심볼 테이블을 추가하거나 갱신한다. -s 옵션은 주로 정적 라이브러리를 다룰 때 유용하다.
- 이 옵션은 파일을 추가하면서 심볼 테이블을 갱신하려는 경우에 사용된다.
프로그램 배포 시 static library와 header 파일만 주면 사용자는 링킹해서 사용할 수 있다.
Static Library 사용방법
$gcc -static main.o -L. -lmy
//L. : 라이브러리 검색 경로 -L.옵션이 없다면, 디폴트로 /lib or /usr/lib 경로를 찾게 됨.
//-lmy : 라이브러리 이름. 링커에게 libmy.so(shared) -> libmy.a(-static 옵션 - 정적 링킹에서.a만 찾도록)라는 이름의 라이브러리를 찾아야 한다고 전달
//.a .so 모두 찾지 못하면 링커는 에러를 발생시킨다.
//명시적으로 static 링킹. 디폴트는 dynamic 링킹
-L. 옵션의 필요성 → 아카이브를 만들게 되면 새로운 경로에 저장하는 것이 일반적. 따라서 아카이브를 만든
current working directory 에서 아카이브를 찾아야 한다. 라이브러리가 특정 시스템 기본 라이브러리 경로에 없다면, -L. 옵션을 통해 라이브러리 경로를 직접 지정해야 한다.
libc.a 라이브러리는 standard C library 로 기본적으로 함께 링킹된다. ( static 링킹으로 명시적 지정했기 때문에! 자동으로 정적 링킹)
static 링킹으로 지정했을 경우! 작성한 모든 라이브러리가 정적으로 링킹된다.
정적링킹 특성상 a.out 파일의 size가 크다는 단점이 있다. 하지만, 런타임 시에 수행속도가 굉장히 빠르고 안정적으로 동작한다.
→ a.out 파일 생성 (main.o foo.o _exit.o .... )
//특정 심볼의 포함여부를 확인
$nm -s a.out | grep bar // not found!!!
$nm -s a.out | grep foo
//result -> 000....114a T foo
//공유 라이브러리 포함여부 확인 (dynammic)
$ldd a.out
//not a dynamic executable
Problem... command linde order matters
링커 알고리즘은 스캔하는 동안 최근 해결되지 않은 참조들의 리스트를 유지한다. 따라서 하나라도 남아있게 되면 링킹 에러가 생긴다.
→ 커맨드 라인의 순서가 중요!!! 참조가 있는 오프젝트파일을 먼저 작성해야 한다.
라이브러리를 먼저 작성할 경우, 뒤이어 나오는 오브젝트 파일들의 참조문제를 해결할 수 없다.
→ 라이브러리를 가장 끝에 작성하자!
$gcc -static main.o -L. -lmy
$gcc -static -L. -lmy main.o //링킹 에러
Q. -static 옵션이 없다면?
gcc main.o -L. -lmy -o prog //.so file을 우선적으로 찾는다.
//vs
gcc -static main.o -L. -lmy -o progstatic
/* libmy.a에는 정적링킹을 유지한다. 하지만, libc는 동적링킹 되어있다. */
앞서 언급했듯 링커은 기본적으로 '동적링킹'을 수행한다. 즉, shared library(.so) 을 먼저 찾고, 찾지 못하면 static링킹을 수행한다. -static 옵션 설정 시 링커는 동적 라이브러리는 아예찾지 않고 정적 라이브러리만 사용한다.
$ldd prog //ldd 동적 링킹 확인
/*
linux-vdso.so.1 => (0x00007fff7b5f3000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f87bd9bb000)
/lib/ld-linux-x86-64.so.2 (0x00007f87bdd76000)
*/
$ls -al progstatic prog
/*
-rwxr-xr-x 1 user user 12345678 Nov 26 10:00 progstatic //파일 크기가 훨씬 크다
-rwxr-xr-x 1 user user 2345678 Nov 26 10:01 prog
*/
/ls: 리스트(list) 명령어로, 현재 디렉토리 내의 파일과 디렉토리 목록을 출력
//-a: -a 옵션은 숨겨진 파일(이름이 .으로 시작하는 파일)을 포함하여 모든 파일을 나열.여기서는 숨겨진 파일도 표시하지만, 일반적으로 실행 파일에 관련된 정보에선 큰 차이가 없을 수 있다.
//-l: -l 옵션은 long listing 형식으로 파일의 상세 정보를 표시한다. 이 정보에는 파일의 권한, 소유자, 크기, 수정 시간 등이 포함된다.
프로그램 prog의 경우 동적으로 libc.so를 링킹하고, libmy.so 파일을 찾지 못했으니 libmy.a 을 정적으로 링킹한다.
반면, progstatic 프로그램은 정적링킹이 -static으로 명시되어 있어 .a 파일만 찾게 되고, libmy.a 와 libc.a를 정적으로 링킹한다.
(표준 라이브러리파일은 .so / .a 모두 존재)
$gcc -c addvec.c mulvec.c //.o 파일
$ar rs libvector.a addvec.o mulvec.o //ar에서는 옵션을 공백으로 구분하여 나열해도 정상적으로 작동
$gcc - static main.c ./libvector.a // 인자로 주는 방법 1
//vs
$gcc -static -L. -lvector // 확장성 높은 방법 2
//find libvector.a in the current working directory
- 방법 1 ($gcc -static main.c ./libvector.a)은 직접 파일 경로를 지정하는 방식으로, 경로가 명확하고 단일 파일을 처리할 때 유용하지만, 확장성이 떨어집니다.
- 방법 2 ($gcc -static -L. -lvector)는 라이브러리 경로(-L.)와 라이브러리 이름(-lvector)을 사용하는 방식으로, 확장성과 유연성이 뛰어나며, 라이브러리 경로를 여러 번 지정하고 다양한 라이브러리를 사용할 때 편리합니다.
Static Library 의 장단점
장점
- 컴파일 시, 실행파일로 직접 링킹되기 때문에 실행파일이 독립적으로 존재할 수 있다. (실행파일만으로도 모든 기능을 수행함) 실행파일 배포 시 추가적인 라이브러리 파일이 필요없기 때문에 배포가 간편하다.
- 외부 의존 없이 독립적인 실행이 가능하다. 즉, 라이브러리 위치에 의존하지 않는다. 정적 라이브러리는 컴파일 시점에 프로그램에 포함되기에 프로그램 실행 시 라이브러리의 경로를 찾는 과정이 없다.
- 실행 속도가 빠르다. 미리 컴파일되어 실행파일에 포함되므로 별도의 로딩시간이 없다.
단점
- 실행파일에 모든 라이브러리 코드를 포함해 실행파일의 크기가 크게 증가할 수 있다.
- duplication . 여러 프로그램이 동일한 정적 라이브러리를 사용할 경우, 실행 시 디스크에서 메모리로 라이브러리로 전달되면 디스크 뿐만 아니라 메모리에서도 duplication 발생. 메모리 낭비
- 라이브러리 수정 시 해당 라이브러리를 사용하는 모든 프로그램을 재컴파일해야 하기에 유지관리에 복잡하다. rebuild everything!!!
'Major S-T-U-D-Y > System Programming' 카테고리의 다른 글
[시스템 프로그래밍] 8 . Process (0) | 2024.12.19 |
---|---|
[시스템 프로그래밍] 12 (1) 예외 제어흐름 (커널 모드) (0) | 2024.12.02 |
[시스템 프로그래밍] 7. (3) 링킹과정 1단계 : 심볼 해석과 재배치 (0) | 2024.11.26 |
[시스템 프로그래밍] 7. (2) Linking 정적/동적 링킹 과정과 (0) | 2024.11.22 |
[시스템 프로그래밍] 7. Linking (1) 분할컴파일과 extern/static modifier (0) | 2024.11.21 |