0


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 中的内容

#ifndefADD_H_#defineADD_H_intAddFunc(int m,int n);#endif// ADD_H_

源文件 lib/add.cpp 中的内容

#include"add.h"intAddFunc(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 3117:49 libadd.a
lrwxrwxrwx. 1 mayw mayw   11 Dec 3117:50 libadd.so -> libadd.so.1
lrwxrwxrwx. 1 mayw mayw   13 Dec 3117:50 libadd.so.1 -> libadd.so.1.2
-rwxrwxr-x. 1 mayw mayw 7896 Dec 3117: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
$ makeinstall[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"intmain(int argc,char* argv[]){
    std::cout <<"hello world"<< std::endl;
    std::cout <<"AddFunc(3, 4)="<<AddFunc(3,4)<< std::endl;return0;}

根目录中 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 中进行设置。

标签: 学习 c++ linux

本文转载自: https://blog.csdn.net/myw31415926/article/details/128508447
版权归原作者 myw31415926 所有, 如有侵权,请联系我们删除。

“CMake 学习四:CMake 构建静态库和动态库”的评论:

还没有评论