使用CPack打包后程序无法从lib目录读取关联dylib求助
macOS Sonoma下CPack打包游戏程序动态库路径问题解决
环境
- macOS Sonoma 14.3
- MacBook Pro M2
- Homebrew包管理
问题
使用CPack打包游戏程序后,程序运行时仍尝试从Homebrew的安装路径读取动态库,而非打包文件夹内的bin/lib目录。
具体现象
- 删除打包后
lib目录中的LuaCpp.dylib,运行程序提示找不到@rpath/libluacpp.dylib(说明该库已配置为从bin/lib路径读取,符合预期); - 删除Homebrew目录下的
SDL_image.dylib,程序崩溃,提示无法读取/opt/homebrew/opt/sdl2_image/lib/libSDL2_image-2.0.0.dylib,但删除打包后lib目录中的该文件无报错; - 仅LuaCpp能正常从打包的
lib目录读取,Lua、SDL2、SDL2_image均异常。
错误日志示例
LuaCpp缺失时的错误
dyld[51173]: Library not loaded: @rpath/libluacpp.dylib Referenced from: <DFF279D6-542E-30DB-AF11-8A48C9619EA8> /Users/me/RainSDL/packages/Game-0.1-Darwin/bin/Game Reason: tried: '/Users/me/RainSDL/packages/Game-0.1-Darwin/bin/lib/libluacpp.dylib'
SDL2_image缺失时的错误
dyld[51216]: Library not loaded: /opt/homebrew/opt/sdl2_image/lib/libSDL2_image-2.0.0.dylib Referenced from: <DFF279D6-542E-30DB-AF11-8A48C9619EA8> /Users/me/RainSDL/packages/Game-0.1-Darwin/bin/Game Reason: tried: '/opt/homebrew/opt/sdl2_image/lib/libSDL2_image-2.0.0.dylib' (no such file), '/System/Volumes/Preboot/Cryptexes/OS/opt/homebrew/opt/sdl2_image/lib/libSDL2_image-2.0.0.dylib', '/opt/homebrew/opt/sdl2_image/lib/libSDL2_image-2.0.0.dylib' (no such file)
原CMakeLists.txt配置
cmake_minimum_required(VERSION 3.12) # Project name and version project(Game VERSION 0.1) # Set compiler paths and build type set(CMAKE_C_COMPILER "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc") set(CMAKE_CXX_COMPILER "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++") set(CMAKE_BUILD_TYPE "Build") # Change to "Build" for proper lua script linking # Set optimization level set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3") # Set C++ standard set(CMAKE_CXX_STANDARD 11) # Find Lua find_package(Lua REQUIRED) # Find LuaCpp find_library(LUACPP_LIBRARIES NAMES LuaCpp PATHS /usr/local/lib) # Find SDL2 find_package(SDL2 REQUIRED) # Find SDL2 image find_package(SDL2_image REQUIRED) # Include directories include_directories( ${LUA_INCLUDE_DIR} ${SDL2_INCLUDE_DIRS} "/usr/local/include/LuaCpp" # LuaCpp headers "/opt/homebrew/Cellar/sdl2_image/2.8.2_1/include/SDL2" # SDL2 image headers ) # Add your source files file(GLOB_RECURSE SOURCES "src/*.cpp") # Create the executable add_executable(Game ${SOURCES}) # Link against libraries target_link_libraries(Game ${SDL2_LIBRARIES} ${SDL2_IMAGE_LIBRARY} ${LUA_LIBRARIES} ${LUACPP_LIBRARIES} # Linked library ) # Set LC_RPATH if(APPLE) set_target_properties(Game PROPERTIES INSTALL_RPATH "@executable_path/../bin/lib") endif() # Copy necessary dynamic libraries to the lib directory add_custom_command(TARGET Game POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/lib COMMAND ${CMAKE_COMMAND} -E copy_if_different ${LUACPP_LIBRARIES} ${LUA_LIBRARIES} ${SDL2_IMAGE_LIBRARY} $<TARGET_FILE:SDL2::SDL2> ${CMAKE_CURRENT_BINARY_DIR}/lib ) # Use CPack to create a distributable package install(TARGETS Game RUNTIME DESTINATION bin ) # Install libraries install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib DESTINATION bin ) # Install Lua scripts directory install(DIRECTORY ${CMAKE_SOURCE_DIR}/src/lua DESTINATION bin/src ) # Determine the relative path from the executable to the Lua scripts directory file(RELATIVE_PATH LUA_SCRIPTS_RELATIVE ${CMAKE_INSTALL_PREFIX} ${CMAKE_SOURCE_DIR}/src/lua) # Define a compile definition for the Lua scripts path if(CMAKE_BUILD_TYPE STREQUAL "Debug") target_compile_definitions(Game PRIVATE LUA_SCRIPTS_PATH="src/lua") else() target_compile_definitions(Game PRIVATE LUA_SCRIPTS_PATH="${LUA_SCRIPTS_RELATIVE}") endif() # CPack configuration set(CPACK_OUTPUT_FILE_PREFIX "${CMAKE_BINARY_DIR}/packages") include(CPack)
尝试的无效解决方案:循环修改rpath脚本
尝试通过循环调用install_name_tool修改动态库的rpath,但未生效:
if(APPLE) # List of shared libraries to modify set(SHARED_LIBRARIES ${LUACPP_LIBRARIES} ${LUA_LIBRARIES} ${SDL2_IMAGE_LIBRARY} ${SDL2_LIBRARIES} ) # Loop over each shared library foreach(LIBRARY ${SHARED_LIBRARIES}) # Get the filename of the shared library get_filename_component(LIBRARY_NAME "${LIBRARY}" NAME) add_custom_command(TARGET Game POST_BUILD COMMAND install_name_tool -change "${LIBRARY}" "@rpath/${LIBRARY_NAME}" "$<TARGET_FILE:Game>") endforeach() # print the new path add_custom_command(TARGET Game POST_BUILD COMMAND otool -L "$<TARGET_FILE:Game>") endif()
最终生效的解决方案:硬编码路径修改
通过硬编码动态库的原始路径,调用install_name_tool修改程序的动态库链接路径,问题得以解决:
if(APPLE) # I have to hardcode these because otherwise the paths are wrong add_custom_command(TARGET Game POST_BUILD COMMAND install_name_tool -change "/opt/homebrew/opt/lua/lib/liblua.dylib" "@rpath/liblua5.4.dylib" "$<TARGET_FILE:Game>") add_custom_command(TARGET Game POST_BUILD COMMAND install_name_tool -change "/usr/local/include/LuaCpp" "@rpath/libluacpp.dylib" "$<TARGET_FILE:Game>") add_custom_command(TARGET Game POST_BUILD COMMAND install_name_tool -change "/opt/homebrew/opt/sdl2_image/lib/libSDL2_image-2.0.0.dylib" "@rpath/libSDL2_image-2.0.0.dylib" "$<TARGET_FILE:Game>") add_custom_command(TARGET Game POST_BUILD COMMAND install_name_tool -change "/opt/homebrew/opt/sdl2/lib/libSDL2-2.0.0.dylib" "@rpath/libSDL2-2.0.0.dylib" "$<TARGET_FILE:Game>") # print the new path add_custom_command(TARGET Game POST_BUILD COMMAND otool -L "$<TARGET_FILE:Game>") endif()
内容的提问来源于stack exchange,提问作者Coding Guy
相关产品推荐
相关产品推荐

