CMake中使用file(GET_RUNTIME_DEPENDENCIES)处理框架依赖的方法
macOS下CMake打包时区分普通库与Framework依赖的解决方案
问题说明
当依赖为普通动态库时,以下CMake配置可正常完成打包并运行:
project(sample) add_library(Foo SHARED foo.cpp foo.h) add_executable(mytest main.cpp) target_link_libraries(mytest Foo) set_target_properties(mytest PROPERTIES INSTALL_RPATH "@loader_path/") install(TARGETS mytest RUNTIME DESTINATION bin) install( CODE "file(GET_RUNTIME_DEPENDENCIES EXECUTABLES \$<TARGET_FILE:mytest> RESOLVED_DEPENDENCIES_VAR DEPS) foreach(DEP \${DEPS}) file(INSTALL \${DEP} DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) endforeach()" )
执行cmake -DCMAKE_INSTALL_PREFIX=/tmp ..和make install后,/tmp/bin/mytest可正常运行。
但将依赖改为Framework后:
project(sample) add_library(Foo SHARED foo.cpp foo.h) set_target_properties(Foo PROPERTIES FRAMEWORK TRUE PUBLIC_HEADER "foo.h") add_executable(mytest main.cpp) target_link_libraries(mytest Foo) set_target_properties(mytest PROPERTIES INSTALL_RPATH "@loader_path/") install(TARGETS mytest RUNTIME DESTINATION bin) install( CODE "file(GET_RUNTIME_DEPENDENCIES EXECUTABLES \$<TARGET_FILE:mytest> RESOLVED_DEPENDENCIES_VAR DEPS) foreach(DEP \${DEPS}) file(INSTALL \${DEP} DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) endforeach()" )
执行相同步骤后,/tmp/bin/mytest启动失败,报错dyld: Library not loaded: @rpath/Foo.framework/Versions/A/Foo。原因是仅复制了Framework中的二进制文件,未完整复制整个Framework目录结构。
修改方案
调整install CODE块,增加Framework判断与完整复制逻辑,并提前配置正确的RPATH:
完整配置代码
project(sample) add_library(Foo SHARED foo.cpp foo.h) set_target_properties(Foo PROPERTIES FRAMEWORK TRUE PUBLIC_HEADER "foo.h") add_executable(mytest main.cpp) target_link_libraries(mytest Foo) # 配置RPATH,同时覆盖当前目录和上级Frameworks目录(符合macOS标准布局) set_target_properties(mytest PROPERTIES INSTALL_RPATH "@loader_path/;@loader_path/../Frameworks") install(TARGETS mytest RUNTIME DESTINATION bin) install( CODE "file(GET_RUNTIME_DEPENDENCIES EXECUTABLES \$<TARGET_FILE:mytest> RESOLVED_DEPENDENCIES_VAR DEPS) foreach(DEP \${DEPS}) # 检查当前依赖是否属于Framework string(FIND \${DEP} \".framework/\" FRAMEWORK_POS) if(FRAMEWORK_POS GREATER -1) # 提取Framework根目录路径 string(SUBSTRING \${DEP} 0 \${FRAMEWORK_POS} FRAMEWORK_DIR) string(APPEND FRAMEWORK_DIR \".framework\") # 完整复制整个Framework到标准Frameworks目录 file(INSTALL \${FRAMEWORK_DIR} DESTINATION ${CMAKE_INSTALL_PREFIX}/Frameworks) else() # 普通动态库直接复制到bin目录 file(INSTALL \${DEP} DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) endif() endforeach()" )
逻辑说明
- RPATH配置:提前给可执行文件添加
@loader_path/../Frameworks路径,符合macOS应用的Framework标准存放位置,确保dyld能找到Framework。 - Framework判断:通过
string(FIND)检查依赖路径中是否包含.framework/,识别Framework类型依赖。 - 完整复制Framework:提取Framework的根目录(而非仅二进制文件),将整个Framework目录复制到
${CMAKE_INSTALL_PREFIX}/Frameworks,保留其完整目录结构。 - 普通库处理:保持原有逻辑,将普通动态库复制到bin目录。
执行cmake -DCMAKE_INSTALL_PREFIX=/tmp ..和make install后,/tmp/bin/mytest即可正常运行。
内容的提问来源于stack exchange,提问作者user3667089
相关产品推荐
相关产品推荐

