CMake 常用总结二:CMake 生成静态库与动态库
引言
CMake 实践帮助我们对 CMake 有一个系统全面的了解,并且有大量示例以供参考,至少在实际项目中可以让我们有能力看懂并修改项目中现有的 CMake 。
阅读完 CMake 实践文档,认为自己的任务也就结束了,可这样总感觉不是自己的东西,不如整理一下并吸收其中自己认为最有用的东西,这样也能极大的减轻自己的记忆负担。
与此同时 CMake 实践行文组织过于复杂,不方便遇到问题时快速查阅,所以我做了一些调整与总结,希望能够对读者更加友好。
本文不能代替 CMake 实践文档,有时间还是把 CMake 实践文档认真阅读一遍。
CMake 生成库
假设我们存在一个这样的任务:
- 建立一个静态库和动态库,提供 HelloFunc 函数以供其他程序编程使用,HelloFunc 向终端输出 Hello World 字符串。
- 安装头文件与共享库。
静态库和动态库的区别
- 静态库的扩展名一般为“.a”或“.lib”;动态库的扩展名一般为“.so”或“.dll”。
- 静态库在编译时会直接整合到目标程序中,编译成功的可执行文件可独立运行(如果程序编译成功,即使离开静态库,程序也是可以独立运行)。
- 动态库在编译时不会放到连接的目标程序中,即可执行文件无法单独运行(如果程序编译成功,必须要有动态库的存在程序才可以运行,比如使用windows运行一些游戏程序时,会报缺少 .dll 文件的错误,导致程序无法正常运行,其实就是缺少动态库)。
CMake 生成库简单实例
按照惯例,我们先来一个简单地实例,以便对 CMake 生成库有一个直观的了解。
创建以下工程结构
yxm@192:~/test3$ tree . ├── build ├── CMakeLists.txt └── lib├── CMakeLists.txt├── hello.cpp└── hello.h2 directories, 4 files
hello.h中的内容
#ifndef HELLO_H #define Hello_Hvoid HelloFunc();#endif
hello.cpp中的内容
#include <iostream> #include "hello.h"void HelloFunc(){std::cout << "Hello World" << std::endl; }
项目中的cmake内容
PROJECT(HELLO) ADD_SUBDIRECTORY(lib bin)
lib中CMakeLists.txt中的内容
SET(LIBHELLO_SRC hello.cpp) ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
ADD_LIBRARY 指令详细可见下文 CMake 语法。
外部编译过程:
进入 build,运行 cmake …
在 build 目录下,运行 make 命令编译 Makefile 文件,并生成动态库。
CMake 同时构建静态库与动态库
生成动态库与静态库
有上面的例子可以看出,使用 ADD_LIBRARY 指令就可以同时构建静态和动态库:
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
ADD_LIBRARY(hello STATIC ${LIBHELLO_SRC})
但是如果使用这种方式,只会构建一个动态库,不会构建出静态库,虽然静态库的后缀是.a,此时我们可以修改静态库的名字,这样是可以同时构建动态库和静态库:
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})
但是我们往往希望他们的名字是相同的,只是后缀不同而已,此时可以使用 SET_TARGET_PROPERTIES 指令(该指令详细可见下文 CMake 语法),修改lib目录下CMakeLists.txt文件:
SET(LIBHELLO_SRC hello.cpp)ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})# 对hello_static的重名为hello
SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello")
# cmake 在构建一个新的target 时,会尝试清理掉其他使用这个名字的库,如果没有清理还是会只会构建一个动态库,不会构建出静态库
SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})# 对hello_static的重名为hello
SET_TARGET_PROPERTIES(hello PROPERTIES OUTPUT_NAME "hello")
SET_TARGET_PROPERTIES(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)
外部编译过程:
进入 build,运行 cmake …
在 build 目录下,运行 make 命令编译 Makefile 文件,并生成动态库与静态库。
修改动态库版本号
同时我们还可以修改动态库的版本号
// 一般动态库都有一个版本号的关联
libhello.so.1.2
libhello.so ->libhello.so.1
libhello.so.1->libhello.so.1.2
修改 lib/CMakeLists.txt ,重新构建看看结果:
SET(LIBHELLO_SRC hello.cpp)ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello")SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})SET_TARGET_PROPERTIES(hello PROPERTIES OUTPUT_NAME "hello")
SET_TARGET_PROPERTIES(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)
SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)
安装共享库和头文件
本例中我们将 hello 的共享库安装到 <prefix>/lib 目录;将 hello.h 安装到 <prefix>/include/hello 目录,这样共享库才能够被调用。
修改lib目录下CMakeLists.txt文件:
SET(LIBHELLO_SRC hello.cpp)ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello")SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})SET_TARGET_PROPERTIES(hello PROPERTIES OUTPUT_NAME "hello")
SET_TARGET_PROPERTIES(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)# 文件放到该目录下
INSTALL(FILES hello.h DESTINATION include/hello)# 二进制,静态库,动态库安装都用TARGETS
# ARCHIVE 特指静态库,LIBRARY 特指动态库,RUNTIME 特指可执行目标二进制。
INSTALL(TARGETS hello hello_static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
外部编译过程:
进入 build,运行 cmake -DCMAKE_INSTALL_PREFIX=/usr …
注意:安装的时候,指定一下路径,放到系统下,-D之后加不加空格都可。
注意:直接安装在 usr 系统目录下,以便后续可以直接调用
在 build 目录下,运行 make 命令编译 Makefile 文件,并生成动态库与静态库。
在 build 目录下,运行 make install
使用外部动态库和头文件
新建一个目录来使用外部共享库和头文件,创建以下工程结构:
yxm@192:~/test4$ tree . ├── build ├── CMakeLists.txt └── src├── CMakeLists.txt└── main.cpp2 directories, 3 files
main.cpp中的内容
#include <hello.h>int main(){HelloFunc(); }
项目中的CMakeLists.txt内容
PROJECT(HELLO) ADD_SUBDIRECTORY(src bin)
src中CMakeLists.txt中的内容
ADD_EXECUTABLE(hello main.cpp)
外部编译过程:
进入 build,运行 cmake …
在 build 目录下,运行 make 命令编译 Makefile 文件。注意此时 make 会报错:
解决:make 后头文件找不到的问题
make 时会提示找不到头文件,两种解决方法:
- 修改成 include <hello/hello.h> ,但这样修改代码冗余。
- 当然也可以使用一下关键字:INCLUDE_DIRECTORIES (详细见下文 CMake 语法)
这里使用第二种方法,在src下的 CMakeLists.txt 文件中加入头文件搜索路径:
INCLUDE_DIRECTORIES(/usr/include/hello)
ADD_EXECUTABLE(hello main.cpp)
外部编译过程:
进入 build,运行 cmake …
在 build 目录下,运行 make 命令编译 Makefile 文件。注意此时还是 make 会报错:
解决:找到引用的函数问题
报错信息:undefined reference to `HelloFunc()',所以我们需要将 .so 文件关联起来。
解决方法有两种:
关键字:LINK_DIRECTORIES 添加非标准的共享库搜索路径
指定第三方库所在路径,LINK_DIRECTORIES(/home/myproject/libs)
关键字:TARGET_LINK_LIBRARIES 添加需要链接的共享库(详细见下文 CMake 语法)
TARGET_LINK_LIBRARIES 的时候,只需要给出动态链接库的名字就行了。
这里使用第二种方法,在src下的 CMakeLists.txt 文件中添加需要链接的共享库(主要要插在executable的后面):
INCLUDE_DIRECTORIES(/usr/include/hello)
ADD_EXECUTABLE(hello main.cpp)
TARGET_LINK_LIBRARIES(hello libhello.so)
外部编译过程:
进入 build,运行 cmake …
在 build 目录下,运行 make 命令编译 Makefile 文件。
在 build/bin 目录下,运行 ./hello ,执行结果如下:
yxm@192:~/test4/build$ cd bin/ yxm@192:~/test4/build/bin$ ./hello Hello World
注意:如果你的 linux 虚拟机是64位会报错,需要移动动态库到64位下:
使用外部静态库
上面的例子使用的是外部动态库,如果想要使用外部静态库,步骤也是相同的,只需要将上面例子中.so换成.a即可,不过使用外部静态库不需要头文件。
TARGET_LINK_LIBRARIES(main libhello.a)
补充:
特殊的环境变量 CMAKE_INCLUDE_PATH 和 CMAKE_LIBRARY_PATH
注意:这两个是环境变量而不是 cmake 变量,可以在linux的bash中进行设置
我们上面例子中使用了绝对路径INCLUDE_DIRECTORIES(/usr/include/hello)来指明include路径的位置,我们还可以使用另外一种方式,使用环境变量export CMAKE_INCLUDE_PATH=/usr/include/hello
CMake 语法
(1)ADD_LIBRARY 语法
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
- hello:就是正常的库名,生成的名字前面会加上lib,最终产生的文件是libhello.so
- SHARED,动态库 STATIC,静态库
- ${LIBHELLO_SRC} :源文件
(2)SET_TARGET_PROPERTIES 语法
这条指令可以用来设置输出的名称,对于动态库,还可以用来指定动态库版本和 API 版本
对hello_static的重名为hello,例如:SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME “hello”)
指定动态库版本和 API 版本,例如:SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)
其中VERSION 指代动态库版本,SOVERSION 指代 API 版本。
(3)INCLUDE_DIRECTORIES 语法
找头⽂件:可以用来向工程添加多个特定的头文件搜索路径,路径之间用空格分割
(4)TARGET_LINK_LIBRARIES 语法
TARGET_LINK_LIBRARIES 用于从链接库到执⾏⽂件上
CMake 常用总结二:CMake 生成静态库与动态库相关推荐
- cmake:add_library生成静态库和动态库
此文为:轻松入门cmake系列教程 有时我们只需要编译出动态库,静态库,然后等着让其它程序去使用.让我们看下这种情况该如何使用cmake 实验 实验一:生成静态库 编写代码 项目结构如下: [CMak ...
- CMake教程(二)- 添加静态库文件和动态库文件
CMake教程(二)- 添加静态库文件和动态库文件 什么是库文件 静态链接库 动态链接库 静态库和动态库的区别 如何在CMake中添加库文件 CMake 中 target_link_libraries ...
- HelloWorld CMake Demo 03:CMake中构建静态库与动态库及其使用
继续完善Hello World,建立它的共享库,包括静态库和动态库. 本节的任务: 1,建立一个静态库和动态库,提供HelloFunc函数供其他程序编程使用,HelloFunc向终端输出Hello W ...
- CMake I 编译静态库、动态库和对象库
目录 一.源文件 1.Message.h 2.Message.cpp 3.helloworld.cpp 二.CMakeLists.txt 1.源文件 2.CMake语言说明 (1)cmake_mini ...
- android jni通过cmake使用第三方静态库和动态库
google 官方现在推荐使用cmake来构建jni. 本人正好工作需要使用第三方的静态库和动态库,写此文 权当做个记录. 首先修改app的build.gradle文件 ndk {abiFilter ...
- 【Cmake实战:番外】库、动态库和静态库(.dll,.so,.lib,.a)
[Cmake实战:番外]库.动态库和静态库(.dll,.so,.lib,.a) 一.什么是库 二.库的种类 三.命名方式 四.动态库和静态库的特点 五.如何知道一个可执行程序依赖哪些库 六.linux ...
- Linux下GCC生成和使用静态库和动态库详解(二)
2.1准备好测试代码hello.h.hello.c和main.c: hello.h(见程序1)为该函数库的头文件. hello.c(见程序2)是函数库的源程序,其中包含公用函数hello,该函数将在屏 ...
- 用gcc生成静态库和动态库和使用opencv库编写打开摄像头压缩视频
文章目录 一.用gcc生成静态库和动态库 1.编辑生成程序hello.h.hello.c.main.c 2.将hello.c生成.o文件 3.使用静态库 4.动态库的使用 二.a与.so库文件的生成与 ...
- GCC生成静态库和动态库
目录 1)阅读.理解和学习材料"用gcc生成静态库和动态库.pdf"和"静态库.a与.so库文件的生成与使用.pdf",请在Linux系统(Ubuntu)下如实 ...
最新文章
- 吴恩达机器学习入门 2018 高清视频公开,还有习题解答和课程拓展,网友:找不到理由不学!...
- 审稿人眼中的好论文到底长什么样?
- 牛客第七场 Sudoku Subrectangles
- 字典删除多个键值对方法_Life is short,you need Python——Python序列(元组、字典、集合)...
- dataGridView 行头那一块儿空白是否可见的设置
- linux备份mysql怎样操作,Linux下自动备份MySQL数据库详细操作步骤(转载)
- 聊聊微服务架构及分布式事务解决方案!
- 【Java系列】八大排序算法
- 跑得快,打不死!清华大学开发“小强”机器人,壮汉狂踩也挡不住前进步伐
- Android前台服务讲解一
- MIMO系列之分集与复用
- 在小百合注册了一个帐号
- Office Visio 2007 中文版 安装
- pip install 使用豆瓣源
- matlab最大回撤值,用matlab计算区间最大回撤值和最大回撤率
- 自定义小程序中的showToast
- 一定要讲给孩子们的20个小故事
- 【计算机毕业设计】基于微信小程序的高校课堂考勤签到系统
- 地质灾害防治网格化管理平台
- 数据结构与算法-普利姆算法(Prim) | 尚硅谷韩顺平
热门文章
- css制作3D立体旋转效果
- mc1.8.1怎么局域网java_我的世界Minecraft局域网联机方法 这几步你要了解
- CISCO X8系列AP升级详解
- 计算机二级自学考试,关于全国计算机等级考试(NCRE)与高等教育自学考试课程衔接的通知...
- 苟日新,日日新,又日新
- Converter/MultiBinding示例
- CSS-三栏布局新手上路
- 为什么越来越多的网站域名不加www前缀?
- 谷歌手机pixel4 夜景_您应该购买Google Pixel 4a的5个理由
- win10局域网中只能发现部分计算机,Windows10系统局域网中共享计算机找不到怎么办...