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

如何通过CMake让编译出的二进制程序加载自身目录下的.so文件

解决方案

核心问题分析

当前程序的RUNPATH同时包含$ORIGIN和项目内SFML/lib路径,动态链接器会按顺序查找,因此优先加载了项目目录下的库。要实现优先加载程序自身目录下的.so文件,需要让$ORIGIN成为唯一的优先查找路径,同时确保程序目录下存在对应的SFML库文件。

步骤1:修改CMakeLists.txt,精确控制RPATH

替换原有链接器flags设置,改用CMake目标属性单独控制目标程序的RPATH,避免路径叠加:

cmake_minimum_required(VERSION 3.28)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED YES)

project(sfmlsnake)

add_executable(${PROJECT_NAME}
    sources/*.cpp  # 替换为实际源文件列表
)

# 设置RPATH为程序自身目录,确保优先查找当前目录
set_target_properties(${PROJECT_NAME} PROPERTIES
    BUILD_RPATH_USE_ORIGIN TRUE
    INSTALL_RPATH "$ORIGIN"
    BUILD_RPATH "$ORIGIN"
)

# 仅在编译阶段使用项目内SFML库路径,不写入最终RPATH
target_link_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/SFML/lib)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/SFML/include)
target_link_libraries(${PROJECT_NAME} sfml-graphics sfml-window sfml-system)

add_subdirectory(tinyfiledialogs)
target_link_libraries(${PROJECT_NAME} tinyfiledialogs)

关键改动:

  • 用set_target_properties直接指定目标的BUILD_RPATH和INSTALL_RPATH为$ORIGIN,替代全局链接器flags,避免和原有路径叠加
  • 将target_link_directories的PUBLIC改为PRIVATE,确保该路径仅用于编译链接阶段,不会被加入程序的最终RPATH

步骤2:自动复制SFML库到程序输出目录

编译完成后需要把SFML/lib下的.so文件复制到程序所在的build目录,可通过CMake自定义命令自动完成:

# 在add_executable之后添加以下代码
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_directory
        ${CMAKE_CURRENT_SOURCE_DIR}/SFML/lib/
        $<TARGET_FILE_DIR:${PROJECT_NAME}>
)

步骤3:验证配置结果

编译完成后,检查RPATH是否符合预期:

objdump -x sfmlsnake | grep 'R.*PATH'

正常输出应为:RUNPATH $ORIGIN

再用ldd确认库加载路径:

ldd sfmlsnake | grep sfml

输出的库路径应指向程序所在目录下的.so文件,而非系统/usr/lib或项目SFML/lib目录。

额外说明

  • $ORIGIN是Linux动态链接器的特殊变量,代表程序自身所在目录,逻辑和Windows下优先查找exe目录一致
  • 发布程序时,只需将程序和目录下的SFML库一起打包,无需依赖系统安装的SFML版本

内容的提问来源于stack exchange,提问作者Hubert Gonera

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 10:25:13