You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 22:31:00