rpath란 Run-time search path로, 위키피디아에 따르면 “rpath는 실행 파일이나 라이브러리에 하드코딩 된 런타임 검색 경로를 지정한다.” 고 되어있다.
rpath 는 바이너리 파일(shared library 또는 실행 파일)에 임베드된 경로이다. 이 경로는 바이너리가 런타임시에 링크해야 하는 라이브러리 중 최우선 검색 경로이다.
고객의 상황에 따라 LD_LIBRARY_PATH 또는 /usr/lib 경로를 설정이 어려운 경우가 있다(보안상 이슈 등).
그럴 경우에, 배포하는 제품에서 필요한 shared library (편의상 libA.so 라고 명명) 위치를 설정하고, libA.so 라이브러리의 디펜던시 라이브러리들을 libA.so 라이브러리 기준으로 찾게 하려고 한다.
리눅스는 ELF 형식의 바이너리는 rpath 라고 부르는 "실행시 라이브러리를 찾을 경로 정보"를 컴파일 시점에 넣어줄 수 있으며 이 정보는 LD_LIBRARY_PATH 환경 변수 전에 참고된다. (참고)
컴파일할 때 Makefile에 $ORIGIN
키워드를 넣어 설정한다.
LDFLAGS += -Wl,-rpath,'$$ORIGIN/../lib'
$ORIGIN
이라고 하면 Makefile의 규칙인 변수에 $
를 적어주는 것으로 적용하므로 $$
두개를 사용해야 한다.
$ORIGIN
키워드는 Linux, Solaris(SUN), HP-UX IA에 있지만 AIX에는 없는걸 확인했다.
라이브러리가 생성된 후 런타임 링커가 프로그램을 시작시킬 때 $ORIGIN
키워드를 프로그램을 실행시킨 현재 경로로로 전환시킨다. (나: 영어는 프로그램이라 번역했지만 설명을 이어 보면 $ORIGIN
이 설정된 shared library라고 볼수있겠다.)
The $ORIGIN token is kept inside your program after it's created and when the runtime linker starts to run your program it will replace $ORIGIN with the current path that your program was invoked from. (링크)
man ld
명령어로 -rpath 옵션 설명을 확인해봤다. -rpath 옵션을 사용하면 런타임시 shared object 위치를 알려준다고 되어있다.
-rpath=dir
Add a directory to the runtime library search path. This is used when linking an ELF executable with shared objects. All -rpath arguments are concatenated and passed to the runtime linker, which uses them to locate shared objects at runtime. The -rpath option is also used when locating shared objects which are needed by shared objects explicitly included in the link;
설정한 rpath 가 잘 동작하는지 확인해본다.
컴파일할 때 Makefile에 $ORIGIN
키워드를 넣어 설정한다.
LDFLAGS += -Wl,-rpath,'$$ORIGIN/../lib2'
rpath를 $ORIGIN/../lib2
라고 설정했다. 디펜던시 라이브러리는 ../lib2 에 찾겠다는 뜻.
rpath 가 설정되었는지는 readelf -d
로 확인해본다.
# readelf -d A.so
Dynamic section at offset 0x1abc23 contains 28 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libpthread.so.0]
0x0000000000000001 (NEEDED) Shared library: [libB.so]
0x0000000000000001 (NEEDED) Shared library: [libC.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000001d (RUNPATH) Library runpath: [$ORIGIN/../lib2]
RUNPATH 가 잘 설정되어 있는 것을 확인한다
ldd
명령어로 디페던시 라이브러리 위치를 설정한 위치에 잘 찾고있는지 확인한다.
# ldd libA.so
...
libB.so => /home/./../lib2/libB.so
libC.so => /home/./../lib2/libC.so
...
다음과 같이 세 디렉토리를 만든다.
test
|_ test.c
lib1
|_ libA.so
lib2
|_ libB.so
|_ libC.so
테스트 파일이 있는 위치에서 gcc 빌드해본다.
옵션 두개를 구분할 줄 알아야 한다.
gcc test.c -I. -Wl,-rpath,'$ORIGIN/../lib1' -L../lib1 -lA