背景
使用C++编写的一个小项目,需要打包成mac下的可执行文件(免安装版本),方便分发给其他mac执行,需要把项目的动态库都打在软件包中,分发之后可以直接运行,而不需要再重复安装。
动态库梳理
经过依赖精简和梳理,项目最终必须依赖的动态库包括:pcl, bzip2, lz4, yaml, rosbag(用于读取rosbag包,后续会有专门的文章会提到如何做到不依赖ros环境)。 在Mac上,这些动态库都已经通过homebrew工具安装好。
brew install cmake bzip2 lz4 pcl
brew 在安装bzip2和 lz4 时,也会默认安装他们的静态库文件(liblz4.a 和 libbz2.a),而pcl库是直接安装的动态库文件。
打包方案
yaml动态库在前面的文章中已经转成了静态库代码的形式包含在了项目里。对于动态库,和linux类似,需要把动态库(dylib)直接打包到存放可执行文件的目录中。不过,不同于linux,mac上需要处理动态库自身的动态库依赖。
由于我们使用homebrew安装依赖库,所以我们在编译时(CMakeLists.txt)中需要在brew的安装路径下查找定位依赖库。
# Homebrew 安装路径
set(HOMEBREW_PREFIX "/usr/local/opt")
静态库处理
对于bzip2和 lz4,我们在编译的时候直接依赖他们的静态库文件,这样比较方便。
# lz4, bzip2 静态库路径
set(LZ4_LIBRARY "${HOMEBREW_PREFIX}/lz4/lib/liblz4.a")
set(BZIP2_LIBRARIES "${HOMEBREW_PREFIX}/bzip2/lib/libbz2.a")
find_package(BZip2 REQUIRED)
# 显式指定 BZip2 静态库(覆盖默认动态库)
if(BZIP2_FOUND)
set(BZIP2_LIBRARIES "${HOMEBREW_PREFIX}/bzip2/lib/libbz2.a")
message(STATUS "BZip2 static lib: ${BZIP2_LIBRARIES}")
endif()
# 定位 lz4 静态库
find_library(LZ4_LIBRARY_RELEASE NAMES liblz4.a PATHS "${HOMEBREW_PREFIX}/lz4/lib" REQUIRED)
find_library(LZ4_LIBRARY_DEBUG NAMES liblz4d.a PATHS "${HOMEBREW_PREFIX}/lz4/lib")
if(LZ4_LIBRARY_RELEASE)
set(LZ4_LIBRARIES ${LZ4_LIBRARY_RELEASE})
if(LZ4_LIBRARY_DEBUG)
set(LZ4_LIBRARIES optimized ${LZ4_LIBRARY_RELEASE} debug ${LZ4_LIBRARY_DEBUG})
endif()
message(STATUS "lz4 static lib found: ${LZ4_LIBRARIES}")
endif()
动态库处理(PCL库)
# PCL 动态库路径
set(PCL_DIR "${HOMEBREW_PREFIX}/pcl/lib/cmake/pcl")
list(APPEND CMAKE_PREFIX_PATH "${PCL_DIR}")
# macOS 动态库运行时搜索路径设置
set(CMAKE_INSTALL_RPATH "@executable_path")
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
# 框架链接(PCL 可能需要的系统框架)
link_libraries("-framework Accelerate" "-framework OpenGL" "-framework Foundation")
find_package(PCL REQUIRED COMPONENTS io)
if(PCL_FOUND)
message(STATUS "PCL Found: ${PCL_LIBRARIES}")
include_directories(${PCL_INCLUDE_DIRS})
else()
message(FATAL_ERROR "PCL not found!")
endif()
编译链接
add_executable(MyApp ...)
target_include_directories(MyApp PUBLIC
${PCL_INCLUDE_DIRS}
${CMAKE_SOURCE_DIR}/thirdparty/yaml-cpp/include
...
)
# 链接配置:PCL动态库 + 其他静态库
target_link_libraries(MyApp PUBLIC
${PCL_LIBRARIES} # PCL动态库
yaml-cpp # 静态源码编译的yaml-cpp
${BZIP2_LIBRARIES} # BZip2静态库
${LZ4_LIBRARIES} # lz4静态库
)
动态库后处理逻辑
首先,可以使用 otool -L 提取依赖的动态库,不管是App还是动态库本身,都可以用这个命令来定位到他们的依赖。这里和linux不同的地方在于,需要递归去处理动态库及动态库自身的依赖。针对以下两种情况分别处理:
-
动态库路径中包含
/usr/local:直接复制对应地址的动态库到目标路径的libs下(dist/libs/) -
动态库路径中包含
@rpath:这种情况比较麻烦,因为根据@rpath并不能定位到动态库的路径,需要根据动态库类型替换@rpath为实际的动态库路径: <


9409

被折叠的 条评论
为什么被折叠?



