CMake 教程(二)添加库

目录

  • 一、实例一——创建库
    • 1、add_library
    • 2、target_include_directories()、target_link_libraries()
      • 2.1 target_include_directories()
      • 2.2 target_link_libraries()
    • 3、实例操作
  • 二、实例二——添加选项
    • 1、option()
    • 2、实例操作


在第一节 CMake 教程(一)初识 CMake 中,我们已经了解和实现了通过 CMake 来创建一个基本项目。本节我们将通过两个实例来学习如何在项目中创建和使用库。

一、实例一——创建库

1、add_library

要在 CMake 中添加库,就需要使用 add_library 命令来指定哪些源文件应组成库。

add_library(<name> [<type>] [EXCLUDE_FROM_ALL] <sources>...)

其作用为:添加一个名为 <name> 的库目标,该目标要从命令调用中列出的源文件构建。

参数说明:

  • <name> 对应于逻辑目标名称,并且在项目中必须是全局唯一的。构建的库的实际文件名是根据本机平台的约定(例如 lib<name>.a<name>.lib)构建的。
  • 可选的 <type> 指定要创建的库的类型:
    • STATIC:链接其他目标时使用的目标文件存档。
    • SHARED:一个动态库,可以由其他目标链接并在运行时加载。
    • MODULE:一个插件,它不能被其他目标链接,但可以在运行时使用类似 dlopen 的功能动态加载。

如果未给出 <type>,则默认值为 STATICSHARED

2、target_include_directories()、target_link_libraries()

我们可以使用一个或多个子目录来组织项目,而不是将所有源文件放在一个目录中。在这种情况下,我们将专门为我们的库创建一个子目录。在这里,我们可以添加新的 CMakeLists.txt 文件和一个或多个源文件。在顶级 CMakeLists.txt 文件中,我们将使用 add_subdirectory() 命令将子目录添加到构建中。

创建库后,它通过 target_include_directories()target_link_libraries() 连接到我们的可执行目标。

2.1 target_include_directories()

target_include_directories(<target> [SYSTEM] [AFTER|BEFORE]<INTERFACE|PUBLIC|PRIVATE> [items1...][<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])

指定编译给定目标(例如可执行文件、库等)时要使用的包含目录。命名的 <target> 必须由 add_executable()add_library() 等命令创建,并且不能是 ALIAS 目标。

  • target:目标名称,可以是一个可执行文件、静态库或动态库的名称。
  • SYSTEM:可选参数,指定包含目录是否应被视为系统目录。表示编译器不会产生警告。
  • [AFTER|BEFORE]:可选参数:
    • BEFORE:参数用于将包含目录添加到已有的包含目录之前,即在搜索其他包含目录之前搜索指定的目录。
    • AFTER:参数用于将包含目录添加到已有的包含目录之后,即在搜索其他包含目录之后搜索指定的目录。
  • <INTERFACE|PUBLIC|PRIVATE>:可选参数,指定添加的包含目录的属性。
    • INTERFACE:目标的接口包含目录,这意味着只有依赖该目标的其他目标才能看到这个包含目录。对于依赖该目标的目标来说,这个包含目录会像是它自己的接口一样可见。
    • PUBLIC:目标的公共包含目录,这意味着该目标及依赖它的其他目标都可以看到这个包含目录。
    • PRIVATE:目标的私有包含目录,只有该目标自身才可见这个包含目录。
  • item1...:需要添加的包含目录。

2.2 target_link_libraries()

target_link_libraries(<target> ... <item>... ...)

target_link_libraries() 命令用于为目标添加链接的库。

  • <target>:表示要添加库的目标,可以是一个目标名称或者一个目标别名。
  • <item>:表示要链接的库的名称,可以是一个目标名称、一个目标别名、一个链接库或者一个链接库的路径。

target_link_libraries 命令将目标与指定的库进行链接。链接库可以是静态库(.a.lib 等)或者动态库(.so.dll 等)。这个命令还可以用于链接其他目标,将目标与目标进行依赖关系的建立。

CMake 会自动获取库的路径和链接依赖关系,因此在使用 target_link_libraries() 命令时,不需要完整的库文件路径。

3、实例操作

接下来,我们尝试向项目中添加一个库,库中包含我们自己实现的用于计算平方的的实现。然后,让可执行文件可以使用这个库,而不是使用编译器提供的标准库函数。

我们把将要实现的库放在 lib 目录下的 my_sqrt.cmy_sqrt.h,并实现一个简单的平方函数:

// my_sqrt.h
#ifndef __MY_SQRT_H
#define __MY_SQRT_Hint my_sqrt(int a);#endif /* __MY_SQRT_H */// my_sqrt.c
#include <stdio.h>
#include "my_sqrt.h"int my_sqrt(int a)
{return (a * a);
}

然后在 math_func.cmath_func.h 文件中封装一下:

// math_func.c
#include <stdio.h>
#include "math_func.h"
#include "my_sqrt.h"int m_sqrt(int a)
{return my_sqrt(a);
}// math_func.h
#ifndef __MATH_FUNC_H
#define __MATH_FUNC_Hint m_func(int a);#endif

然后实现这个子目录下的 CMakeLists.txt 文件:

cmake_minimum_required(VERSION 3.16)project(my_lib)add_library(MYSQRT math_func.c my_sqrt.c)

然后执行命令 cmake .

子目录的工作就完成了。然后是主目录:

main.c 文件中简单地调用刚才我们实现的函数:

// main.c
#include <stdio.h>
#include <stdlib.h>
#include "my_sqrt.h"int main(int argc, char *argv[])
{if (argc < 1 || argc > 3) {perror("argument err!");exit(-1);}int a = atoi(argv[1]);int b = m_sqrt(a);printf("result is %d\n", b);return 0;
}

然后完成 CMakeLists.txt 文件:

cmake_minimum_required(VERSION 3.16)add_executable(test02 main.c)project(test02 VERSION 1.1)add_subdirectory(lib)target_link_libraries(test02 PUBLIC MYSQRT)target_include_directories(test02 PUBLIC"${PROJECT_BINARY_DIR}""${PROJECT_SOURCE_DIR}/lib")

注意,对应的库名和目录名一定要对应,否则会找不到库

然后执行 cmake --build .

大功告成:

二、实例二——添加选项

现在让我们在 MYSQRT 库中添加一个选项,允许开发人员选择自定义平方根实现或内置标准实现。虽然对于本教程来说,确实没有必要这样做,但对于较大的项目来说,这种情况很常见。

1、option()

CMake 可以使用 option() 命令来做到这一点。这为用户提供了一个变量,他们可以在配置 cmake 版本时更改该变量。此设置将存储在缓存中,因此用户无需在每次在 build 目录上运行 CMake 时都设置该值。

option(<variable> "<help_text>" [value])

作用:提供用户可以选择选择的布尔选项。

如果未提供初始 <value>,则布尔值 OFF 为默认值。如果 <variable> 已设置为普通变量或缓存变量,则该命令不执行任何操作。

2、实例操作

首先修改 lib 子目录下的 CMakeLists.txt 文件:

cmake_minimum_required(VERSION 3.16)project(my_lib)LINK_LIBRARIES(m)add_library(MYSQRT math_func.c)option(USE_MYMATH "Use projectsauron provided math implementation" ON)if (USE_MYMATH)target_compile_definitions(MYSQRT PRIVATE "USE_MYMATH")add_library(SqrtLibrary STATICmy_sqrt.c)target_link_libraries(MYSQRT PRIVATE SqrtLibrary)
endif()

注意,因为待会儿的 C 文件中要使用到 C 标准库中的 math.h 头文件,所以要连接 math 库:LINK_LIBRARIES(m)

option 添加一个选项 USE_MYMATH。此选项将显示在 cmake-guiccmake 中,默认值为 ON,用户可以更改该默认值。

至于下面的语句,请看:如果 USE_MYMATH 为 OFF,则不会使用 mysqrt.c,但仍会对其进行编译,因为 MYSQRT 目标在源下列出了 mysqrt.c

有几种方法可以解决这个问题。第一个选项是使用 target_sources()USE_MYMATH 块中添加 mysqrt.c。另一种选择是在 USE_MYMATH 块中创建一个额外的库,该库负责编译 mysqrt.c。在这里中,我们采取的是后面那种方法。

math_func.c 文件修改如下:

#include <stdio.h>
#include "math_func.h"#ifdef USE_MYMATH#include "my_sqrt.h"
#else#include "math.h"
#endifint m_sqrt(int a)
{
#ifdef USE_MYMATHprintf("use my sqrt!\n");return my_sqrt(a);
#elseprintf("use std sqrt!\n");return sqrt(a);
#endif
}

这里通过 printf,可以验证我们的结果是否正确。

因为 USE_MYMATH 默认是 ON,所以编译好后,使用的仍是我们自己实现的函数:

重新执行下面的语句即可:

cmake ../test02 -DUSE_MYMATH=OFF
cmake --build .


现在使用的是标准库。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/447916.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

fastadmin 列表页表格实现动态列

记录&#xff1a;fastadmin 列表页表格实现动态列 后端代码 /*** 商品库存余额表*/public function kucunbalance(){$houseList (new House)->where([shop_id>SHOP_ID])->order(id desc)->field(name,id)->select();//设置过滤方法$this->request->filte…

LeetCode209.长度最小的子数组

题目链接&#xff1a;209. 长度最小的子数组 - 力扣&#xff08;LeetCode&#xff09; 1.常规解法&#xff08;会超时&#xff09; 可以先将数组的所有子数组求出来&#xff0c;计算其中元素的值&#xff0c;判断与目标值的大小关系&#xff0c;代码如下&#xff1a; public …

Ubuntu里彻底卸载UHD

查看已经安装的UHD版本uhd_find_devices&#xff0c;展示的是当前安装的 UHD 库版本所支持的设备信息&#xff0c;下载了多个版本的uhd但是又记不住安装的位置&#xff0c;想要把所有的uhd相关环境全都删掉&#xff0c;用下边这个命令看一下所有的uhd信息&#xff1a; apt lis…

在 Spring 中使用 @EhCache 注解作为缓存

文章目录 项目概况项目设置一个简单的 RESTful Web 服务Spring 整合 EhCache第 1 步&#xff1a;更新依赖项以使用 EhCache Spring 注解第 2 步&#xff1a;设置自定义缓存管理器第 3 步&#xff1a;配置 EhCache第 4 步&#xff1a;测试缓存 刷新缓存总结推荐阅读文章 EhCache…

Visual Studio的实用调试技巧总结

对于很多学习编程的老铁们来说&#xff0c;是不是也像下面这张图一样写代码呢&#xff1f; 那当我们这样编写代码的时候遇到了问题&#xff1f;大家又是怎么排查问题的呢&#xff1f;是不是也像下面这张图一样&#xff0c;毫无目的的一遍遍尝试呢&#xff1f; 这篇文章我就以 V…

k8s的微服务

ipvs模式 Service 是由 kube-proxy 组件&#xff0c;加上 iptables 来共同实现的 kube-proxy 通过 iptables 处理 Service 的过程&#xff0c;需要在宿主机上设置相当多的 iptables 规则&#xff0c;如果宿主机有大量的Pod&#xff0c;不断刷新iptables规则&#xff0c;会消耗…

QT:计算点到线段的垂线段的距离

描述 在Qt中&#xff0c;要计算一个点到一条线段的垂线段的长度&#xff08;即点到线段上最近点的距离&#xff0c;且这个点是垂直于线段的&#xff09;&#xff0c;你不能直接使用QVector2D::distanceToLine&#xff0c;因为这个方法计算的是点到直线的垂直距离&#xff0c;而…

2024-09-22 进程优先级,进程切换

一、僵尸状态 & 孤儿进程 进程退出&#xff1a;内核数据结构&#xff08;task_struct 维护&#xff09; 代码和数据&#xff08;直接释放&#xff09; 代码不会执行了首先可以立即释放的就是进程对应的程序信息数据。进程退出要有退出信息&#xff08;进程的退出码&#…

六西格玛设计DFSS方法论在消费级无人机设计中的应用——张驰咨询

本文基于六西格玛设计方法论&#xff0c;对消费级无人机的设计流程进行系统化研究&#xff0c;探讨如何通过六西格玛设计的理念、工具和方法提升无人机产品的设计质量和市场竞争力。文章从市场定位、客户需求分析出发&#xff0c;深入到关键KPI指标的制定&#xff0c;并逐步阐述…

【网络安全】漏洞案例:提升 Self-XSS 危害

未经许可,不得转载。 文章目录 Self-XSS-1Self-XSS-2Self-XSS-1 目标应用程序为某在线商店,在其注册页面的First Name字段中注入XSS Payload: 注册成功,但当我尝试登录我的帐户时,我得到了403 Forbidden,即无法登录我的帐户。 我很好奇为什么我无法登录我的帐户,所以我…

前端高频面试题2024/9/22(偏项目问题--通用后台管理系统)

文章目录 一.前端项目概述1.系统登录注册模块1.对注册的密码进行加密 &#xff08;使用加密中间件bcrypt.js&#xff09;2.登录成功后返回token3.前端登录页面有用到弹性布局&#xff0c;ref和reactive4.登录头像&#xff1a;文件上传 2.系统设置模块2.系统首页模块&#xff08…

使用electron+vue开发桌面应用

electron是什么 electron由Node.jsChromiumNative APIs构成。你可以理解成&#xff0c;它是一个得到了Node.js和基于不同平台的Native APIs加强的Chromium浏览器&#xff0c;可以用来开发跨平台的桌面级应用。 它的开发主要涉及到两个进程的协作——Main&#xff08;主&#x…

Java通过RAG构建专属知识问答机器人_超详细

RAG&#xff1a;融合检索与生成的文本精准生成技术 检索增强生成&#xff08;RAG&#xff09;是一种技术&#xff0c;它通过结合检索模型和生成模型来提高文本生成的准确性。具体来说&#xff0c;RAG首先利用检索模型从私有或专有的数据源中搜索相关信息&#xff0c;然后将这些…

编程练习7 5G网络建设

需要用到并查集的相关知识&#xff1a;可以参考如下链接 并查集详解&#xff08;原理代码实现应用优化&#xff09;-CSDN博客 #include<iostream> #include<algorithm> #include<vector>using namespace std;vector<int> split(string params_str) {…

ICT产业新征程:深度融合与高质量发展

在信息时代的浪潮中&#xff0c;每一场关于技术革新与产业融合的盛会都闪耀着智慧的光芒&#xff0c;引领着未来的方向。9月25日&#xff0c;北京国家会议中心内&#xff0c;一场聚焦全球信息通信业的顶级盛事——第32届“国际信息通信展”&#xff08;PT展&#xff09;隆重拉开…

【LwIP源码学习3】TCP协议栈分析——数据接收流程

前言 本文介绍代码在lwip的tcp_in.c文件中&#xff0c;主要介绍TCP协议栈中数据的接收流程。 正文 1、一个正常的TCP数据&#xff0c;首先会传入到 tcp_input(struct pbuf *p, struct netif *inp)函数&#xff0c;其中指针p指向传入的数据流。 2、从数据流中获取TCP头部 …

通过Express + Vue3从零构建一个用户认证与授权系统(二)数据库与后端项目搭建与实现

前言 上一篇完成了系统的相关设计文档的编写&#xff0c;本文将详细介绍如何一步步使用 TypeScript 和 Express 搭建一个模块化、类型安全的用户认证与授权系统&#xff0c;包括数据库设计、后端项目搭建、用户认证、角色与权限管理、错误处理以及 Swagger 文档集成。 项目准…

【ubuntu】ubuntu20.04安装cuda12.6与显卡驱动

目录 1.安装cuda12.6 2.安装显卡驱动 1.安装cuda12.6 https://developer.nvidia.com/cuda-toolkit-archive https://developer.nvidia.com/cuda-12-6-0-download-archive?target_osLinux&target_archx86_64&DistributionUbuntu&target_version20.04&target_…

DART: Implicit Doppler Tomography for Radar Novel View Synthesis 笔记

Link&#xff1a;https://wiselabcmu.github.io/dart/ Publish&#xff1a; 2024CVPR Abstract DART主要任务就是用来合成雷达距离多普勒图像range-droppler&#xff0c;可用于生成高质量的断层扫描图像。 Related Work 1 Radar Simulation 基于模型的方法 任务&#xff…

XGBoost回归预测 | MATLAB实现XGBoost极限梯度提升树多输入单输出

回归预测 | MATLAB实现XGBoost极限梯度提升树多输入单输出 目录 回归预测 | MATLAB实现XGBoost极限梯度提升树多输入单输出预测效果基本介绍模型描述程序设计参考资料预测效果 基本介绍 XGBoost的全称是eXtreme Gradient Boosting,它是经过优化的分布式梯度提升库,旨在高效、…