Search

[C++, CMake] RPATH와 동적 라이브러리

Last update:

RPATH

C/C++ 실행파일이 동적 라이브러리를 사용할 때, 링커는 아래 디렉터리를 차례대로 탐색한다.
RPATH - 대부분의 UNIX 시스템에서 지원되며, 실행 파일에 연결되는 디렉토리 목록. RUNPATH가 있을 경우 무시됨
→ RPATH는 실행파일에 포함되는 설정임
LD_LIBRARY_PATH - 디렉토리 목록을 포함하는 환경 변수
RUNPATH - RPATH와 동일하지만, LD_LIBRARY_PATH 이후에 검색됨. 현재 대부분의 Linux 시스템에서 지원됨
/etc/ld.so.conf - 추가 라이브러리 디렉토리를 나열하는 ld.so의 설정 파일
기본 내장 디렉토리 - 기본적으로 /lib와 /usr/lib
그런데 같은 동적 라이브러리라고 하더라도, A 실행파일과 B 실행파일이 사용하고자 하는 버전이 다를 수도 있다. 이럴 경우 각 실행파일이 사용하고자 하는 라이브러리를 독립적으로 설정해주는 방법이 RPATH(또는 RUNPATH)다.

CMake와 RPATH

CMake 프로젝트에서는 실행파일을 빌드 트리에서 실행할 것이냐, 설치 트리에서 실행할 것이냐에 따라 RPATH도 달라져야 한다.
실행파일이 빌드 트리에서 실행될 때, 사용하는 라이브러리 역시 같은 프로젝트 내에서 빌드된 경우, RPATH는 빌드트리를 가리켜야 한다.
실행파일이 install된 경우는 RPATH가 빌드트리를 가리키지 않아야 한다.
하지만 애석하게도 RPATH를 간단하게 변경할 수 있는 방법은 아직 존재하지 않는다. RPATH는 컴파일될 때 실행파일에 새겨지는 설정이기 때문이다.
CMake는 버전 2.6부터 실행파일을 빌드할 때, 설치 트리의 RPATH가 빌드 트리의 RPATH보다 긴 경우, 빌드 트리의 RPATH에 패딩을 붙여놓는다. 그리고 설치할 때 RPATH를 변경하는 식으로 작동한다. 2.6버전 이전에는 install 시 RPATH를 다시 설정하기 위해 링킹 과정을 다시 거쳐야 했다.

Default RPATH 설정

CMake는 기본적으로 실행파일에서 사용한 라이브러리들의 빌드 트리 경로를 RPATH로 설정한다. 그리고 install 시에 RPATH를 지워서 빈 상태로 만든다. 아래는 Default 설정 그대로이다.
# use, i.e. don't skip the full RPATH for the build tree set(CMAKE_SKIP_BUILD_RPATH FALSE) # when building, don't use the install RPATH already # (but later on when installing) set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) # the RPATH to be used when installing set(CMAKE_INSTALL_RPATH "") # don't add the automatically determined parts of the RPATH # which point to directories outside the build tree to the install RPATH set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
Shell
복사
Default 설정을 그대로 두면 실행파일을 빌드 트리에서 직접 실행할 수 있는 반면, install된 실행파일은 직접 LD_LIBRARY_PATH같은 환경변수에 라이브러리 위치를 추가하거나, 라이브러리를 default 라이브러리 디렉터리에 넣어주는 방법 등을 통해 링킹을 해줘야 한다.

항상 Full RPATH를 설정하기 (실행파일이 동적 라이브러리(.so) 파일을 찾도록 설정하는 방법)

필요한 라이브러리가 LD_LIBRARY_PATH나 install 위치와 관계 없이 찾을 수 있도록 하고싶은 경우 아래처럼 하면 된다.
# use, i.e. don't skip the full RPATH for the build tree set(CMAKE_SKIP_BUILD_RPATH FALSE) # when building, don't use the install RPATH already # (but later on when installing) set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") # add the automatically determined parts of the RPATH # which point to directories outside the build tree to the install RPATH set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # the RPATH to be used when installing, but only if it's not a system directory list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir) if("${isSystemDir}" STREQUAL "-1") set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") endif("${isSystemDir}" STREQUAL "-1")
Shell
복사
/usr/bin처럼 시스템이 기본적으로 라이브러리를 찾아보는 디렉터리를 시스템 기본 링크 디렉터리라고 하는데, CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES는 그 목록을 가지고 있다. install 경로(CMAKE_INSTALL_RPATH)가 해당 목록에 없을 경우 CMAKE_INSTALL_RPATH에 등록을 해주는 것이다.

$ORIGIN

Linux에서 링커(ld.so)는 rpath 내에 있는 $ORIGIN이라는 문자열(토큰)을 현재 실행파일의 경로로 치환한다. 따라서 공유 라이브러리를 찾을 때 실행 파일의 위치를 기준으로 상대 경로를 지정할 수 있게 해주고, 어디에 복붙해 놓아도 잘 작동하는 패키지를 만들 수 있다.
set_target_properties(<target> PROPERTIES INSTALL_RPATH "$ORIGIN")
Shell
복사
그런데 달러 사인($) 관련해서 이스케이핑에 문제가 좀 있나보다. 관련 글

RPATH 확인하기 (Ubuntu)

readelf -d main_app
Shell
복사

기타

LD_LIBRARY_PATH를 설정하는 방법도 있다(비권장)
export LD_LIBRARY_PATH=/usr/local/lib
Plain Text
복사

References

관련 문서