目录
1.CMakeLists.txt 以及编译动态链接库
2.同时生成动态库与静态库
3.工程集成动态连接库
4.工程集成静态连接库
5.分目录编译
1.CMakeLists.txt 以及编译动态链接库
CMakeLists.txt 是 跨平台编译工具cmake 用于生成工程编译文件makefile的命令文件,有了makefile就可以使用make命令构建程序
以测试工程为例,当前目录环境如下:
这里的cmake/mat/CMakeLists.txt就是用于生成libmat.so 或libmat.a的命令文件
CMakeLists.txt内容:这里用于生成动态链接库
使用CMake 与 CMakeLists.txt生成makefile:
在build文件夹下执行: make .. 后输出如下:
现在生成了makefile文件,可以直接执行make 启动编译了:
编译后的结果在cmake/mat/build 下,这里是一个动态链接库:libmat.dylib 等同于linux系统下的libmat.so
2.同时生成动态库与静态库
修改CMakeLists.txt如下:
# 编译mat库
cmake_minimum_required(VERSION 3.4.1)
set(target_name mat)
project(${target_name})
set(SDK_DIR "/Users/sssrank/AndroidStudioProjects/baidu/vscodespace/codespace/project")
set(SDK_SRC_DIR "src/mat")
set(ABS_SRC_DIR ${SDK_DIR}/${SDK_SRC_DIR})
set(SDK_INC
${ABS_SRC_DIR}
)
set(SDK_SRC
${ABS_SRC_DIR}/mat.cpp
)
# 生成动态库
add_library(${target_name} SHARED ${SDK_SRC})
# 生成静态库
add_library(${target_name}_static STATIC ${SDK_SRC})
# target_include_directories(${target_name} PRIVATE_HEADER ${SDK_INC})
include_directories(${SDK_INC})
target_link_libraries(${target_name})
# 静态库文件重命名
set_target_properties(${target_name}_static PROPERTIES OUTPUT_NAME ${target_name})
target_link_libraries(${target_name}_static)
这里添加了add_library,属性是STATIC,表示引入静态库; 注意要生成的静态库在makefile中不能重名,这里加了_static后缀,并且在输出时,通过set_target_properties修改静态库的输出名为${target_name},以保持与动态库一致
输出文件:
这里动态库、静态库大小差异不是很明显,但如果工程文件较多,或者依赖第三方库的话,二者差别较大
3.工程集成动态连接库
先写main.cpp,其中调用libmat.so库中的方法
目录结构:
make/main/CMakeLists.txt内容:
# 编译mat库
cmake_minimum_required(VERSION 3.4.1)
set(target_name main)
project(${target_name})
set(SDK_DIR "/Users/sssrank/AndroidStudioProjects/gnss/vscodespace/codespace/project")
set(SDK_SRC_DIR "src")
set(ABS_SRC_DIR ${SDK_DIR}/${SDK_SRC_DIR})
set(SDK_INC
${ABS_SRC_DIR}
)
set(SDK_SRC
${ABS_SRC_DIR}/main.cpp
)
include_directories(${SDK_INC})
# 加载动态链接库
set(LIB_MAT mat)
add_library(${LIB_MAT} SHARED IMPORTED)
set_target_properties(${LIB_MAT} PROPERTIES IMPORTED_LOCATION ${SDK_DIR}/cmake/mat/build/libmat.dylib)
# 输出目录
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
# 编译可执行文件
add_executable(${target_name} ${SDK_SRC})
target_link_libraries(${target_name}
${LIB_MAT}
)
其中动态加载libmat.dylib库文件,最后使用add_executable编译出可执行文件, target_link_libraries链接libmat.so
输出:
执行:这里打印一个3x3矩阵
注意:这里也可以使用link_directories,如下,相当于 g++中的 -L${SDK_DIR}/cmake/mat/build,增加动态库的搜索目录,如下:
link_directories(${SDK_DIR}/cmake/mat/build)
4.工程集成静态连接库
在第三方库的引入位置直接使用libmat.a静态库的地址即可:
# 编译mat库
cmake_minimum_required(VERSION 3.4.1)
set(target_name main)
project(${target_name})
set(SDK_DIR "/Users/sssrank/AndroidStudioProjects/baidu/vscodespace/codespace/project")
set(SDK_SRC_DIR "src")
set(ABS_SRC_DIR ${SDK_DIR}/${SDK_SRC_DIR})
set(SDK_INC
${ABS_SRC_DIR}
)
set(SDK_SRC
${ABS_SRC_DIR}/main.cpp
)
include_directories(${SDK_INC})
# 加载动态链接库
set(LIB_MAT mat)
add_library(${LIB_MAT} STATIC IMPORTED)
set_target_properties(${LIB_MAT} PROPERTIES IMPORTED_LOCATION ${SDK_DIR}/cmake/mat/build/libmat.a)
# 输出目录
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
# 编译可执行文件
add_executable(${target_name} ${SDK_SRC})
target_link_libraries(${target_name}
${LIB_MAT}
)
这里引用动态库也可以使用find_libraries指令
编译结果:
可以看到集成静态库的可执行程序的大小要比使用动态库的main程序大很多
5.分目录编译
cmake下的目录结构:
编译由cmake/CMakeLists.txt控制,其内容如下:
执行时会分别执行子目录下的CMakeLists.txt:
这里修改 cmake/main/CMakeLists.txt引入库的方式: 去掉了红框中的内容,执行编译时会去搜索libmat.dylib
6.其他问题
6.1SDK编译 链接参数--whole-archive
介绍两个ld指令:
--whole-archive :把之后包含的静态库中的函数、变量等符号也输出到动态库中
--no-whole-archive :停止输出
这俩参数一般是在我们打包SDK时, 例如要发布的库:libsdk.so,其中包含了其他的静态库libinternal1.a libinternal2.a,想一同打包发布,供用户调用:
gcc -shared -o libsdk.so -L. -Wl,--whole-archive libinternal1.a libinternal2.a -Wl,--no-whole-archive
6.2开源库编译参数
在一个sdk工程中,打包成动态链接库时 想集成所使用的第三方静态库,遇到报错:
提示需要 使用-fPIC重新编译sqlite3
在sqlite编译 configure时增加-D宏定义:
$$CFLAGS="-DSQLITE_ENABLE_COLUMN_METADATA -fPIC" ./configure
不同平台下或者gcc,生成的makefile不会添加-fpic地址无关的选项, 最好自己编译时手动加上这一项