CMake使用外部动态库/静态库和头文件
- 一、准备工作
- 二、新建一个新的CMake工程
- 三、开始构建
- 四、为target添加共享库
- 五、链接静态库
一、准备工作
在博文《使用CMake构建静态库和动态库》中已经介绍了libhello动态库的构建和安装,现在我们看看如何使用这个外部动态库。
本文中的示例前提是已经安装了libhello.so共享库。
二、新建一个新的CMake工程
创建一个新的名为usehellolib的CMake工程,在main.cpp中使用libhello.so中提供的函数say_hello().
main.cpp
#include <iostream>
#include "hello.hpp"
int main(int, char**) {
say_hello();
}
工程根目录下的CMakeLists.txt内容如下:
cmake_minimum_required(VERSION 3.0.0)
project(usehellolib VERSION 0.1.0)
add_subdirectory(src)
# 以下内容非必须
include(CTest)
enable_testing()
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)
src 目录下的 CMakeLists.txt内容如下:
add_executable(usehellolib main.cpp)
整个工程的目录结构看起来是这样的:
三、开始构建
按照惯例,到build目录下进行构建
cd build
cmake ..
make
此时会发现报错了,提示找不到hello.hpp
hello.hpp 位于/usr/include/hello 目录中,并没有位于系统标准的头文件路径, 为了让我们的工程能够找到hello.hpp,我们需要引入一个新的指令INCLUDE_DIRECTORIES:
INCLUDE_DIRECTORIES([AFTER|BEFORE] [SYSTEM] dir1 dir2 ...)
这条指令可以用来向工程添加多个特定的头文件搜索路径,路径之间用空格分割,如果路径中包含了空格,可以使用双引号将它括起来,默认的行为是追加到当前的头文件搜索路径的后面,你可以通过两种方式来进行控制搜索路径添加的方式:
- CMAKE_INCLUDE_DIRECTORIES_BEFORE,通过 SET 这个 cmake 变量为 on,可以
将添加的头文件搜索路径放在已有路径的前面。 - 通过 AFTER 或者 BEFORE 参数,也可以控制是追加还是置前。
现在我们在 src/CMakeLists.txt 中添加一个头文件搜索路径,方式很简单,加入
INCLUDE_DIRECTORIES(/usr/include/hello)
进入build目录重新构建,发现找不到头文件的错误已经消失,但是出现了一个新错误:
这是因为我们并没有 link 到共享库 libhello 上。
四、为target添加共享库
我们现在需要完成的任务是将目标文件链接到 libhello,这里我们需要引入两个新的指令
LINK_DIRECTORIES 和 TARGET_LINK_LIBRARIES。
LINK_DIRECTORIES 的全部语法是:
LINK_DIRECTORIES(directory1 directory2 ...)
这个指令非常简单,添加非标准的共享库搜索路径,比如,在工程内部同时存在共享库和可执行二进制,在编译时就需要指定一下这些共享库的路径。这个例子中我们没有用到这个指令。
TARGET_LINK_LIBRARIES 的全部语法是:
TARGET_LINK_LIBRARIES(target library1
<debug | optimized> library2
...)
这个指令可以用来为 target 添加需要链接的共享库,本例中target是一个可执行文件,但是同样可以用于为自己编写的共享库添加共享库链接。
为了解决上面遇到的函数未定义错误,我们向 src/CMakeLists.txt 中添加如下指令:
TARGET_LINK_LIBRARIES(main hello)
也可以写成
TARGET_LINK_LIBRARIES(main libhello.so)
重新构建,这时我们就得到了一个连接到libhello的可执行程序usehellolib,位于build/src目录:
执行看是否能运行成功, 发现仍然有报错:
./usehellolib: error while loading shared libraries: libhello.so.1: cannot open shared object file: No such file or directory
可是文件明明是存在的:
我们来看看ldconfig这个程序,位于/sbin下,它的作用是将文件/etc/ld.so.conf列出的路径下的库文件缓存到/etc/ld.so.cache以供使用,因此当安装完一些库文件,或者修改/etc/ld.so.conf增加了库的新的搜索路径,需要运行一下ldconfig,使所有的库文件都被缓存到文件/etc/ld.so.cache中,如果没做,可能会找不到刚安装的库。
执行一下ldconfig
ldconfig
如果是普通用户的话,需要使用sudo
再次执行程序,此时已经可以正常运行:
检查一下程序的链接情况,可以看到确实链接了libhello共享库:
五、链接静态库
那么如何链接到静态库呢? 很简单,只需要将
TARGET_LINK_LIBRRARIES 指令修改为:
TARGET_LINK_LIBRARIES(usehellolib libhello.a)
重新构建并查看链接情况: