CMake编程实践(五) 编译静态库和动态库

2023-11-06

使用Cmake 编译库

本篇使用CMake编译一个动态库和静态库,并安装到系统中,对应的工程是cmake-utilsbox-lib

编译静态库

指定编译静态库,关键词为static,不添加关键字默认静态库

add_library(utils ${LIB_SOURCE})

在使用该库的工程中链接都刚才编译的库:

target_link_libraries(${PROJECT_NAME} utils)

编译动态库

指定编译动态库,关键词为shared

add_library(utils SHARED ${LIB_SOURCE})

在使用该库的工程中链接都刚才编译的库:

target_link_libraries(${PROJECT_NAME} utils)

网上很多文章说 cmake在构建一个新的库时,会尝试清理掉其他使用这个名字的库,但我测试并不会清除,我的cmake version 3.5.1
但这需要编译两次有点麻烦,所以可以在cmake中指定同时输出静态库和动态库

先来看下目录树

.
├── CMakeLists.txt
├── doc
│ └── Introduction.txt
├── README.md
├── src
│ ├── CMakeLists.txt
│ ├── utilsbox.cpp
│ └── utilsbox.h
└── test
    ├── CMakeLists.txt
    └── main.cpp

先来看下项目根CMakeLists.txt,由于本次主要编译的是库,无法直接验证,所以用了ADD_TEST指令指定了一个测试程序,用来验证库是否正常可用,但这不是强制的,主要是顺便也学习下ADD_TEST的用法。其他的没什么特别的,看注释已经很清楚了。

# 声明编译要求cmake最低版本
CMAKE_MINIMUM_REQUIRED(VERSION 3.0)

# ADD_DEFINITIONS(-std=c++11)

# 声明一个cmake工程
PROJECT(UtilsBox)

# 添加子目录, 并指定指定中间二进制和目标二进制存放的位置
ADD_SUBDIRECTORY(src bin)
ADD_SUBDIRECTORY(test)

# 这里相当于定义一个指定的测试程序,以便make test调用
ADD_TEST(utilsbox-test ${PROJECT_BINARY_DIR}/test/utilsbox-test)
ENABLE_TESTING()

# 安装当前工程中doc/目录下的所有内容到doc目录下
INSTALL(DIRECTORY doc/ DESTINATION doc)

src/CMakeLists.txt

# 声明编译要求cmake最低版本
CMAKE_MINIMUM_REQUIRED(VERSION 3.0)

# 配置支持C++11
ADD_DEFINITIONS(-std=c++11)

# 添加库源文件
SET(LIB_SOURCE utilsbox.cpp)

# 添加静态库,关键词为static
ADD_LIBRARY(utilsbox STATIC ${LIB_SOURCE})

# 添加动态库,关键词为shared
ADD_LIBRARY(utilsbox_shared SHARED ${LIB_SOURCE})

# 指定动态库的输出名称
SET_TARGET_PROPERTIES(utilsbox_shared PROPERTIES OUTPUT_NAME "utilsbox")

# 指定动态库版本, 视需求而定,可不加
# VERSION:动态库版本,SOVERSION:API版本
SET_TARGET_PROPERTIES(utilsbox_shared PROPERTIES VERSION 0.1.1 SOVERSION 0)

# 指定库编译输出目录
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)

# 指定库安装位置
# SET(CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR}/lib_utilsbox)

INSTALL(FILES utilsbox.h DESTINATION include)
INSTALL(TARGETS utilsbox utilsbox_shared
    # 动态库安装位置
    LIBRARY DESTINATION lib
    # 静态库安装位置
    ARCHIVE DESTINATION lib
    )

上面主要用到了ADD_LIBRARY用于编译生成库,使用STATIC关键字或不加任何关键字默认生成静态库,使用SHARED关键字生成动态库,由于在CMake体系中不允许存在两个同名的库,所以我们把动态库的名称后面加了一个_shared后缀,为了保证最终生成的库名称是相同的,所以又使用了SET_TARGET_PROPERTIES()中的OUTPUT_NAME选项指定动态库输出的名称。虽然绕了一圈,但最终目的是同时编译出同名的静态库和动态库。

SET_TARGET_PROPERTIES() 指令用来指定动态库版本(静态库我试过无效)。

SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib),指定编译生成的库存放在lib目录下

使用INSTALL指定库的安装位置,注意LIBRARY指定动态库的目录,ARCHIVE指定静态库的路径,具体用法在前面已经讲过了,这里就不赘述了。

src/utilsbox.cpp

#include <iostream>
#include <stdarg.h>
#include <vector>
#include "utilsbox.h"

using namespace std;

std::string UtilsBox::GetVersion()
{ 
 std::string version = UTILSBOX_VERSION;
 return version;
}

std::string UtilsBox::format(const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    int len = vsnprintf(nullptr, 0, fmt, ap);
    va_end(ap);
    std::string buf(len+1, '\0');
    va_start(ap, fmt);
    vsnprintf(&buf[0], buf.size(), fmt, ap);
    va_end(ap);
    buf.pop_back();
    return buf;
}

UtilsBox::format()用来格式化输入字符串,和printf的功能类似,但返回的是string。

src/utilsbox.h

#ifndef UTILSBOX_H
#define UTILSBOX_H

#include <string>

#define UTILSBOX_VERSION "v0.1.1"

namespace UtilsBox
{
    std::string GetVersion(void);
    std::string format(const char *fmt, ...);
}

#endif

test/CMakeLists.txt

# 声明编译要求cmake最低版本
CMAKE_MINIMUM_REQUIRED(VERSION 3.0)

# 添加源文件
SET(SOURCE main.cpp)

# 指定库的位置为项目根目录下的lib目录
LINK_DIRECTORIES(${PROJECT_SOURCE_DIR}/build/lib)
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src)

# 添加一个可执行程序,名称和工程名称保持一致
ADD_EXECUTABLE(utilsbox-test ${SOURCE})
TARGET_LINK_LIBRARIES(utilsbox-test utilsbox)

test/main.cpp

#include <iostream>
#include "utilsbox.h"

using namespace std;

int main(int argc, char** argv)
{
 cout << UtilsBox::GetVersion() << endl;
 return 0;
}

一个简单的测试程序,测试输出的库是否正常。

编译:

mkdir build && cd build
cmake ..
make
# 可以看到在build/lib/下已经生成静态库和动态库了
ls ./lib 
libutilsbox.a libutilsbox.so libutilsbox.so.0 libutilsbox.so.0.1.1

#安装
sudo make install
[ 33%] Built target utilsbox
[ 66%] Built target utilsbox_shared
[100%] Built target utilsbox-test
Install the project...
-- Install configuration: ""
-- Up-to-date: /usr/local/doc
-- Up-to-date: /usr/local/doc/Introduction.txt
-- Up-to-date: /usr/local/include/utilsbox.h
-- Installing: /usr/local/lib/libutilsbox.a
-- Installing: /usr/local/lib/libutilsbox.so.0.1.1
-- Up-to-date: /usr/local/lib/libutilsbox.so.0
-- Up-to-date: /usr/local/lib/libutilsbox.so

可以看到已经安装到/usr/local/lib/下了
至此我们已经完成了静态库和动态库的编译生成和安装,完成了以下几个功能点:
1.同时输出静态库和动态库
2.指定动态库版本(静态库我试过无效)
3.指定库编译输出的目录
4.指定库安装的目录
5.指定库存放目录

cmake-demo源码已上传到github,欢迎Star

下篇我们将会使用到此次编译好的库。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CMake编程实践(五) 编译静态库和动态库 的相关文章

随机推荐

  • 简单的介绍一下:柔性数组

    对于柔性数组 其实这个是在如今的大学生书本上是很难能找到的 原因在于 笔者现在就是大学生一枚 但是在C语言的书本上没有涉及到柔性数组的部分 经查略资料 我们可以找到 在如今的C语言中 C99规定 结构体中允许最后一个元素是未知大小的数组 这
  • 微信小程序支付后端逻辑

    小程序报名 生成订单 public function make order if IS POST data openid I POST openid data total I POST data total data crsNo W dat
  • SSM小技巧(一)、Controller中互相调用session中存储的内容

    首先 你需要在一个Controller中往session中存内容 取的名字必须含有大写字母 虽然博主也不清楚为什么 如果有知道的人请一定要通知博主 博主将感激不尽 Controller SessionAttributes Save 将Mod
  • LLM微调

    下面我只是分析讲解下这些方法的原理以及具体代码是怎么实现的 不对效果进行评价 毕竟不同任务不同数据集效果差别还是挺大的 文章目录 0 hard prompt soft prompt区别 1 Prefix Tuning 2 Prompt Tu
  • 实例 :教你使用简单神经网络和LSTM进行时间序列预测(附代码)

    翻译 张玲 校对 丁楠雅 本文约1500字 建议阅读5分钟 作者基于波动性标准普尔500数据集和Keras深度学习网络框架 利用python代码演示RNN和LSTM RNN的构建过程 便于你快速搭建时间序列的预测模型 图片来源 Pixaba
  • Gradle是什么

    以下总结作为本人学习笔记使用 Gradle是一个开源的自动构建工具 可以作为android studio工程的依赖管理和打包工具 包括三方库和jar包的依赖和链接 java和res等资源的编译和打包 1 在gradle之前 android的
  • 【JavaScript 编程语言】简介JavaScript 简介,手册规范

    1 1JavaScript 简介 让我们来看看 JavaScript 有什么特别之处 我们可以用它实现什么 以及哪些其他技术可以与其搭配产生奇妙的效果 什么是 JavaScript JavaScript 最初被创建的目的是 使网页更生动 这
  • AI 图片生成3D模型之

    AI 可以通过学习大量的图像数据来生成 3D 模型 这些模型可以用于许多不同的目的 如游戏开发 建筑设计和动画制作 为了生成 3D 模型 AI 系统通常需要输入许多 2D 图像 这些图像可以是从不同角度拍摄的照片或者是从视频中截取的帧 AI
  • mmdetection报错 TypeError: vars() argument must have __dict__ attribute

    下载官方代码 安装好环境后第一个demo就报错 报错1 error the following arguments are required img config checkpoint 添加 报错2 manager pyplot show
  • Spring Secutity oAuth2的学习

    李哥的博客不能看了 写文档又很浪费时间 先投个懒 贴个流程图 想去李哥哪里学习的小伙伴 这里有地址 17 Spring Security oAuth2 创建资源服务器2 哔哩哔哩 bilibili 项目中使用到了Oauth2 然后来李哥这里
  • java实现获取两个list交集,并集,差集

    import java util ArrayList import java util List import static java util stream Collectors toList public class Main publ
  • java读取文件方法大全

    一 多种方式读文件内容 1 按字节读取文件内容 2 按字符读取文件内容 3 按行读取文件内容 4 随机读取文件内容 import java io BufferedReader import java io File import java
  • PHP性能优化

    PHP性能优化首先分为三个方向 PHP语言级别的性能优化 gt PHP周边问题的性能优化 gt PHP自身优化 一 PHP语言级别的性能优化 1 多使用PHP 的内置函数 2 少使用错误抑制符 会产生额外的opcode开销 opcode 当
  • 练习二、用JS语言输入数组并判断是否数组,并从小到大进行冒泡排序

    功能描述 在界面输入以逗号间隔开的字符串 转换成数组并判断是否有效 有效即进行排序 选择冒泡排序 主要考点 以输入框为输入参数入口 进行逐步推导 2 1 输入框是字符串需要转换成数组 2 2 一个输入框 要是输入双位数还是会分割成 单位数值
  • Linux中在线yum源的配置

    在线源的配置 配置环境 root localhost cat etc redhat release CentOS release 6 5 Final root localhost uname r 2 6 32 431 el6 x86 64
  • c语言六子棋(Alpha-Beta剪枝算法)

    c语言Alpha Beta剪枝算法六子棋 介绍 Alpha Beta剪枝算法是一种用于优化博弈树搜索的算法 可以在搜索过程中减少不必要的计算 从而提高搜索效率 该算法常用于博弈游戏 如六子棋 六子棋是一种类似于五子棋的棋类游戏 在一个六边形
  • 响应支付宝宣布的刷脸支付商业化

    二维码普及才没多久 刷脸支付已经悄无声息的走进我们的生活 刷脸支付作为一种全新的支付方式 将彻底改变人类的生活方式 有些人感慨道 这个时代变化太快了 快到一切技术的发展犹如坐上了火箭 去年8月中下旬 广电运通与深圳地铁腾讯共同打造生物识别
  • 为什么选择SpringCloud

    SpringCloud的诞生 SpringCloud是集成了众多开源的框架 利用SpringBoot的开发便利性实现服务治理 服务注册与发现 负载均衡 数据监控 REST API发布方式等 基本囊括了分布式框架所需要的所有功能 是一套易开放
  • 饮冰l于 2021-02-05 15:16:54 发布 1288收藏 11分类专栏: 图 文章标签: 算法 数据挖掘 机器学习 深度学习版权图 专栏收录该内容66 篇文章 23 订阅订

    前言 本文的作者认为对于 GNN 的可解释性不足 基于此 作者在节点分类任务上提出可以通过将忽略图结构的浅层模型与两个利用标签结构中相关性的后处理方法相结合 超越或匹配最先进的 GNN 具体如下 i 误差相关性 传播训练数据中的残余误差以纠
  • CMake编程实践(五) 编译静态库和动态库

    使用Cmake 编译库 本篇使用CMake编译一个动态库和静态库 并安装到系统中 对应的工程是cmake utilsbox lib 编译静态库 指定编译静态库 关键词为static 不添加关键字默认静态库 add library utils