build/bin/myapp # libmyapp.so と絶対パスでリンクしている
build/lib/libmyapp.so
みたいなケースで, install して
dist/bin/myapp
dist/lib/libmyapp.so
のようになると libmyapp.so へのリンクが絶対パスなので
cmake で install すると .so のリンクが not found になる...
Linux を考えます.
また, build 時と install 時でディレクトリの構成は変わらないものとします.
再現 repo
再現テスト用の repo を作りました.
原因
デフォルトでは, ビルド時は RPATH
(runtime) が使われ, インストール時は RPATH なしで処理されます.
そのため, install すると RPATH のパスが空になり, binary と .so でディレクトリを分けている場合 .so not found になります.
また, build 時も基本は絶対パスでのリンクになっていますので, build フォルダをコピーして install 相当にして対応というのもできないです.
解決方法(絶対パス)
構成にもよりますが, 最低限 CMAKE_INSTALL_RPATH
を設定すればよいようです.
cmake_minimum_required(VERSION 3.16)
project(MyApp C CXX)
set(LIB_SOURCES mylib.cc)
set(CMAKE_SKIP_BUILD_RPATH FALSE)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
add_library(mylib SHARED ${LIB_SOURCES})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set_target_properties(mylib PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
)
install(TARGETS mylib LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib)
add_executable(myapp myapp.cc)
target_link_libraries(myapp PRIVATE mylib)
install(TARGETS myapp RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
Install 時, ログに
Set runtime path of "/home/syoyo/work/cmake-rpath-experiment/dist/lib/libmylib.so" to "/home/syoyo/work/cmake-rpath-experiment/dist/lib"
のようになってきちんと runtime path 処理されているのを確認しましょう.
ORIGIN で相対パスにする(推奨)
上記だとしかしインストールディレクトリでの絶対パスで処理されるため, さらにインストールディレクトリを移動したりしたときは .so が見つからなくなります.
より汎用には, $ORIGIN
を利用して相対にするのが推奨でしょう.
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib"
(↑のリンクにあるように, CMAKE_INSTALL_RPATH
でグローバルではなく target の property で設定するのが推奨ではある)
$ORIGIN
利用だと以下のような感じになりました.
libmylib.so => /home/syoyo/work/cmake-rpath-experiment/dist/bin/./../lib/libmylib.so (0x00007f3a3e266000)
ただ, ビルド構成によっては /path/to/bin/../bin/../lib
みたいなややこしいパスになってしまうようですので, 単に ../lib
でもいいかもしれません.
set(CMAKE_INSTALL_RPATH "../lib")
libmylib.so => ../lib/libmylib.so