CMake 学习四:CMake 构建静态库和动态库
Posted myw31415926
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CMake 学习四:CMake 构建静态库和动态库相关的知识,希望对你有一定的参考价值。
文章目录
CMake 构建静态库和动态库
本章介绍 CMake 构建静态库和动态库的方法,先看看静态库和动态库的区别:
- 静态库的扩展名一般为 *.a 或 *.lib;动态库的扩展名一般为 *.so 或 *.dll ;
- 静态库在编译时会直接整合到目标文件中,编译成功的可执行文件可独立运行;
- 动态库在编译时不会整合到目标文件中,可执行程序无法单独运行,需要有动态库文件;
一般动态库比较常用。下面通过两个实例来分别讲解 CMake 构建静态库和动态库的方法。
CMake 构建静态库
任务实例:构建静态库 libadd.a ,提供 AddFunc 函数,函数内部做加法运算。代码结构如下
[mayw@localhost lib_a]$ tree .
.
├── CMakeLists.txt
└── lib
├── add.cpp
├── add.h
└── CMakeLists.txt
头文件 lib/add.h 中的内容
#ifndef ADD_H_
#define ADD_H_
int AddFunc(int m, int n);
#endif // ADD_H_
源文件 lib/add.cpp 中的内容
#include "add.h"
int AddFunc(int m, int n)
return m + n;
lib/CMakeLists.txt 中的内容
set(lib_src add.cpp)
add_library(add STATIC $lib_src)
add_library 参数说明
- add :库文件名称,Linux 上生成库文件会自动加上前后缀,如当前的静态库文件名称为 libadd.a;
- STATIC :静态库,动态库为 SHARED;
- $lib_src :构造库文件所需的源码文件。
最外层 CMakeLists.txt ,生成的库文件放在 build/lib 目录中
cmake_minimum_required(VERSION 3.5)
project(libadd)
add_subdirectory(lib lib)
此时使用外部构建方法,在 build/lib 目录中会生成静态库 libadd.a 。
$ mkdir build
$ cd build
$ cmake ..
$ make
CMake 构建动态库
构建动态库也很简单,只需要讲 lib/CMakeLists.txt 中的内容改为
set(lib_src add.cpp)
add_library(add SHARED $lib_src)
此时同样使用外部构建方法,在 build/lib 目录中会生成动态库 libadd.so 。
同时构建静态库和动态库
很多开源软件都同时提供了动态库和静态库,如果使用两条 add_library 指令是不行的。如下:
# 如果用这种方式,只会构建一个动态库,不会构建静态库,虽然静态库的后缀是 *.a
add_library(add SHARED $lib_src)
add_library(add STATIC $lib_src)
# 修改静态库的名字,可以同时构建动态库和静态库,但构建出的库文件名称不同(libadd.so,libadd_static.a)
add_library(add SHARED $lib_src)
add_library(add_static STATIC $lib_src)
此时,需要使用 set_target_properties 指令,设置库文件的输出的名称,对于动态库,还可以通过该指令设置动态库的版本号。如下指令可以同时构建动态库和静态库
set(lib_src add.cpp)
add_library(add_static STATIC $lib_src)
# 将 add_static 重命名为 add
set_target_properties(add_static PROPERTIES OUTPUT_NAME "add")
# cmake 在构建一个新的 target 时,会尝试清理掉使用这个名称的库,
# 所以在构建 libadd.so 时,就会清理掉 libadd.a
set_target_properties(add_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
add_library(add SHARED $lib_src)
set_target_properties(add PROPERTIES OUTPUT_NAME "add")
set_target_properties(add PROPERTIES CLEAN_DIRECT_OUTPUT 1)
使用外部构建方法,会在 build/lib 目录中同时生成静态库和动态库 libadd.a 和 libadd.so 。
设置动态库版本号
一般开源软件的动态库都有一个版本号,如 grpc 的动态库
libgrpc++.so -> libgrpc++.so.1.48
libgrpc++.so.1.48 -> libgrpc++.so.1.48.0
libgrpc++.so.1.48.0
可以在 lib/CMakeLists.txt 中进行如下设置
set_target_properties(add PROPERTIES VERSION 1.2 SOVERSION 1)
其中 VERSION 指代动态库版本,SOVERSION 指代 API 版本。编译后会产生如下链接
[mayw@localhost lib]$ ll lib*
-rw-rw-r--. 1 mayw mayw 1398 Dec 31 17:49 libadd.a
lrwxrwxrwx. 1 mayw mayw 11 Dec 31 17:50 libadd.so -> libadd.so.1
lrwxrwxrwx. 1 mayw mayw 13 Dec 31 17:50 libadd.so.1 -> libadd.so.1.2
-rwxrwxr-x. 1 mayw mayw 7896 Dec 31 17:50 libadd.so.1.2
CMake 调用库文件
安装库文件
在调用库文件之前,需要先安装头文件和库文件,当然,也可以直接将头文件和库文件拷贝给调用者(有点 low 了)。这里采用专业一点的方法:使用 CMake install 进行安装。在 lib/CMakeLists.txt 中添加如下内容
# 将头文件放到指定的 include 目录下
install(FILES add.h DESTINATION include)
# 将库文件安装到指定目录中
# TARGETS 指目标二进制文件,LIBRARY 指动态库,ARCHIVE 指静态库
install(TARGETS add add_static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
使用外部构建进行编译安装,将工程安装到 /tmp/add 目录中
$ cmake -DCMAKE_INSTALL_PREFIX=/tmp/add ..
$ make
$ make install
[ 50%] Built target add
[100%] Built target add_static
Install the project...
-- Install configuration: ""
-- Installing: /tmp/add/include/add.h
-- Installing: /tmp/add/lib/libadd.so.1.2
-- Installing: /tmp/add/lib/libadd.so.1
-- Installing: /tmp/add/lib/libadd.so
-- Installing: /tmp/add/lib/libadd.a
注意,CMake 构建时要通过 -DCMAKE_INSTALL_PREFIX
指定安装路径,否则会安装到默认的 /usr/local 目录中,这需要管理员权限。
调用库文件
重新新建一个工程用于测试库文件调用
[mayw@localhost add_test]$ tree .
.
├── add
│ ├── include
│ │ └── add.h
│ └── lib
│ ├── libadd.a
│ ├── libadd.so -> libadd.so.1
│ ├── libadd.so.1 -> libadd.so.1.2
│ └── libadd.so.1.2
├── build
├── CMakeLists.txt
└── src
├── CMakeLists.txt
└── main.cpp
add 目录表示要使用的外部头文件和库文件,src/main.cpp 中的调用源码
#include <iostream>
#include "add.h"
int main(int argc, char* argv[])
std::cout << "hello world" << std::endl;
std::cout << "AddFunc(3, 4)=" << AddFunc(3, 4) << std::endl;
return 0;
根目录中 CMakeLists.txt 中的内容如下
cmake_minimum_required(VERSION 3.5)
project(add_test)
add_subdirectory(src)
src/CMakeLists.txt 中的内容如下
# 指定引用库的头文件路径,否则会提示找不到头文件
include_directories($PROJECT_SOURCE_DIR/add/include)
# 指定引用库的库文件路径,否则会提示 undefined reference to ,表示为引入库文件
link_directories($PROJECT_SOURCE_DIR/add/lib)
add_executable(add_test main.cpp)
# 为 hello 程序链接库文件 libadd.so
target_link_libraries(add_test add)
PROJECT_SOURCE_DIR 前面已经有说明,表示当前工程的源码路径。其中 target_link_libraries
的语法和用法如下
target_link_libraries(<target> [item1 [item2 [...]]]
[[debug|optimized|general] <item>] ...)
# 以下写法都可以
target_link_libraries(myproject add) # 连接动态库 libad.so,默认优先链接动态库
target_link_libraries(myproject libadd.a) # 显示指定链接静态库
target_link_libraries(myproject libadd.so) # 显示指定链接动态库
target_link_libraries(myproject -lcomm) # 链接动态库 libad.so
若动态库和静态库都存在,此时此时 target_link_libraries
指令 默认优先链接动态库 。使用外部构建方法,在 build/src 目录中会生成可执行文件 add_test 。
$ mkdir build
$ cd build
$ cmake ..
$ make
$ ./src/add_test
hello world
AddFunc(3, 4)=7
特殊的环境变量 CMAKE_INCLUDE_PATH 和 CAMKE_LIBRARY_PATH
这两个是环境变量等同于指定 cmake 编译时引入的头文件和库文件的路径。注意,它们是环境变量,而不是 cmake 的变量,可以在 Linux 的 bash 中进行设置。
使用 cmake 如何静态链接一些库和动态链接其他库?
【中文标题】使用 cmake 如何静态链接一些库和动态链接其他库?【英文标题】:with cmake how to link some libs statically and others dynamically? 【发布时间】:2013-06-18 16:52:02 【问题描述】:如何告诉 CMake 静态链接一些库和动态链接其他库?
我想编译一个静态链接到所有依赖库的 C++ exe,除了 glic
谢谢
【问题讨论】:
【参考方案1】:库的 CMake 方法是首先使用 find_library
找到它们,然后使用 target_link_libraries
中的结果。
在find_library
调用期间选择使用静态库还是动态库:
如果您不介意使用哪个版本,请致电find_library(MYLIB mylib)
如果你想要一个静态库,使用find_library(MYLIB libmylib.a)
(这是针对linux的,你会在windows等上搜索.lib)
如果你想要动态库,请使用find_library(MYLIB libmylib.so)
然后测试是否使用if (MYLIB)
找到您的库并将其链接到您的目标:target_link_libraries(mytarget $MYLIB)
【讨论】:
以上是关于CMake 学习四:CMake 构建静态库和动态库的主要内容,如果未能解决你的问题,请参考以下文章