정적 라이브러리
정적 라이브러리(.a): 프로그램이 컴파일 및 링크 단계에서 라이브러리 코드를 실행 파일에 복사합니다. 프로그램 실행 시 더 이상 정적 라이브러리가 필요하지 않습니다.
정적 라이브러리 이름은 일반적으로
libXXX.a형식을 가지며, 유효 이름은 접두사lib와 접미사.a를 제거한XXX입니다.
링크 단계에서는 해당 바이너리 파일을 연결하므로, 소스 코드를 공개하고 싶지 않을 때 .o 파일(재배치 가능 목적 바이너리 파일)과 헤더 파일만 제공하여 다른 사람이 사용할 수 있도록 할 수 있습니다.
(.o): 메서드 구현
(.h): 메서드 선언
여러 개의 .o 파일을 하나의 라이브러리 파일로 패키징하여 제공하면, 링크 시 해당 라이브러리에서 구현을 찾습니다.
여러
.o파일 --> 하나의 파일 --> 라이브러리 --> 동적 라이브러리 및 정적 라이브러리
라이브러리의 본질은 .o 파일들의 집합입니다.
다음은 구현 및 패키징 과정의 예시입니다:
libmymath.a:my_add.o my_sub.o
ar -rc $@ $^
my_add.o:my_add.c
gcc -c my_add.c -o my_add.o
my_sub.o:my_sub.c
gcc -c my_sub.c -o my_sub.o
.PHONY:output
output:
mkdir -p mylib/include
mkdir -p mylib/lib
cp -f *.a mylib/lib
cp -f *.h mylib/include
.PHONY:clean
clean:
rm -rf *.o libmymath.a mylib
정적 라이브러리 생성 방법:
# 정적 라이브러리 생성
ar -rc libmymath.a add.o sub.o
# ar은 GNU 아카이브 도구이며, rc는 (replace and create)를 의미합니다.
라이브러리를 다운로드한 사용자는 컴파일 시 gcc에 헤더 파일과 라이브러리의 위치를 지정해야 합니다.
gcc -o main main.c -I./mylib/include -L./mylib/lib -l mymath
# -I 뒤에는 헤더 파일 경로, -L 뒤에는 라이브러리 경로, -l 뒤에는 링크할 라이브러리 이름(유효 이름)을 입력합니다.
순서대로 헤더 파일 경로, 라이브러리 경로, 라이브러리 이름(-l + 유효 이름)을 지정합니다.
gcc의 기본 링크는 동적이지만, 모든 라이브러리가 정적 라이브러리로 지정되면 정적 링크 방식으로 처리됩니다.- 동적 라이브러리와 정적 라이브러리가 혼합된 경우, 동적 라이브러리는 동적 링크, 정적 라이브러리는 정적 링크 방식으로 연결됩니다.
- 하나라도 동적 링크가 포함되면 전체가 동적 링크로 처리됩니다.
동적 라이브러리
동적 라이브러리: 실행 프로그램이 실행 단계에서 해당 동적 라이브러리를 찾아 코드 구현을 연결합니다.
동적 라이브러리 이름은 일반적으로 libXXX.so 형식을 가지며, 접두사
lib와 접미사.so를 제거한XXX가유효 이름입니다.
동적 라이브러리 생성 방법 및 배치 위치는 정적 라이브러리와 유사합니다.
.o파일 생성.o파일을 동적 라이브러리.so로 패키징헤더 파일과.so파일을 각각 별도 폴더에 배치
단, 1단계에서 .o 파일 생성 시 -fPIC 옵션을 추가해야 합니다.
gcc -fPIC -c Add.c Sub.c
-fPIC: 위치 독립 코드(Position Independent Code)를 생성합니다.
2단계: 모든 .o 파일을 동적 라이브러리로 패키징할 때 -shared 옵션을 사용합니다.
gcc -shared -o libmymath.so *.o
3단계: 헤더 파일과 .so 파일을 각각 폴더에 배치합니다.
정적 라이브러리 방식으로 컴파일하면 실행 파일은 생성되지만 실행되지 않습니다.
gcc -o mymatn main.c -I ./mylib/include -L ./mylib/lib -l mymath
ldd명령어로 확인하면 동적 라이브러리를 찾지 못한 것을 볼 수 있습니다.
이유는 동적 링크가 프로그램 실행 중에 동적 라이브러리를 찾기 때문입니다. gcc 컴파일 시 라이브러리를 찾는 것은 컴파일 단계에만 해당되며, 컴파일 완료 후의 단계는 gcc와 관련이 없습니다.
실행 단계에서 운영 체제(OS)와 셸(shell)이 동적 라이브러리의 위치를 알아야 합니다.
시스템이 동적 라이브러리를 찾도록 하는 방법:
- 방법 1: 환경 변수에 추가 (권장하지 않음)
시스템은 LD_LIBRARY_PATH 환경 변수에서 라이브러리를 찾습니다. 이 환경 변수에 동적 라이브러리 경로를 추가합니다.
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:동적_라이브러리_경로
단, 이 방법은 셸을 다시 열면 사라지므로(메모리 수준 환경 변수) 매번 설정해야 합니다.
- 방법 2:
/etc/ld.so.conf.d파일 설정
/etc/ld.so.conf.d 디렉토리 내 파일에는 라이브러리 경로가 저장되며, 시스템도 이 경로에서 라이브러리를 찾습니다.
새 파일을 만들고 동적 라이브러리 경로를 저장한 후, sudo ldconfig 명령어로 시스템에 업데이트하면 실행 가능합니다.
# 예시: /etc/ld.so.conf.d/mylib.conf 파일 생성 후 경로 입력
sudo ldconfig
-
방법 3: 심볼릭 링크 생성
- 실행 파일 경로에 심볼릭 링크 생성: 실행 파일과 동일한 디렉토리에 동적 라이브러리의 심볼릭 링크를 생성합니다. 프로그램은 동일 디렉토리에서 라이브러리를 찾습니다.
- 시스템
lib64경로에 심볼릭 링크 생성:/usr/lib64등의 시스템 라이브러리 경로에 심볼릭 링크를 생성해도 동일한 효과를 얻을 수 있습니다.
# 실행 파일 경로에 심볼릭 링크 생성 예시 ln -s /path/to/libmymath.so ./libmymath.so
동적 라이브러리의 로딩
정적 라이브러리 로딩: 컴파일 단계에서 라이브러리 코드를 소스 프로그램 파일에 복사한 후 컴파일하고, 프로세스 주소 공간을 통해 CPU가 접근하여 실행합니다.
동적 라이브러리 로딩: 실행 파일 my.exe가 printf 함수를 동적 링크 방식으로 호출한다고 가정합니다.
lib.so(예:printf동적 라이브러리)는 위치 독립 코드를 생성하는.o파일로 만들어집니다.my.exe컴파일 시,my.exe내printf위치에는lib.so에서printf의 오프셋 주소(또는 오프셋)가 저장됩니다.my.exe실행 시, 먼저my.exe를 메모리에 로드하고 프로세스 주소 공간에 따라 코드를 순차적으로 실행합니다.printf실행 시점에 CPU는my.exe실행을 중단하고lib.so를 메모리에 로드합니다.- 동적 라이브러리가 메모리에 로드되면, 페이지 테이블을 통해 물리 주소를 논리 주소로 변환하고 내용을 공유 영역에 직접 매핑합니다.
- 공유 영역에는
printf함수의 동적 라이브러리 시작 주소가 있으며,my.exe에 저장된 오프셋을 이용하여 함수 구현을 찾을 수 있습니다.
따라서 동일한 동적 라이브러리를 사용하는 여러 프로세스는 하나의 동적 라이브러리를 메모리에 한 번만 로드하면 됩니다. 다른 프로세스는 페이지 테이블을 통해 자신의 공유 영역에 매핑한 후, 공유 영역을 통해 메모리의 동적 라이브러리에 접근할 수 있습니다.