CMake入门教程【核心篇】添加库(add_library)

news2025/5/26 11:08:00

在这里插入图片描述

😈「CSDN主页」:传送门
😈「Bilibil首页」:传送门
😈「本文的内容」:CMake入门教程
😈「动动你的小手」点赞👍收藏⭐️评论📝


文章目录

  • 1. 基本用法
  • 2.STATIC 、SHARED 、 MODULE基本用法
    • 2.1 创建静态库
    • 2.2 创建共享库
    • 2.3 创建模块库
  • 3. 设置库的属性
    • 4. 安装库
    • 5. 链接其他库
    • 6. 使用别名
    • 7. 管理大型项目
  • 8.代码示例
    • 8.1完整示例MODULE
    • 8.2完整示例SHARED
    • 8.3完整示例STATIC
    • 8.4例子分析STATIC 、SHARED、MODULE分析
  • 9. 结论

在CMake中,add_library命令是用于定义库(library)的关键命令。库可以是静态的(static),动态的(shared),或者是模块库。本节教程将深入探讨如何在CMake中使用add_library命令来创建不同类型的库。

1. 基本用法

add_library命令用于创建一个库。基本语法如下:

add_library(<name> [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] source1 [source2 ...])
  • <name>:库的名称。
  • STATICSHAREDMODULE:指定库的类型。如果不指定,默认创建的是静态库(STATIC)。
  • EXCLUDE_FROM_ALL:如果设置,这个库不会被默认构建,除非有其他目标依赖它。
  • source1 [source2 ...]:库的源文件。

2.STATIC 、SHARED 、 MODULE基本用法

2.1 创建静态库

静态库(.a.lib文件)在编译时被完全复制到最终的可执行文件中。

add_library(my_static_lib STATIC source1.cpp source2.cpp)

2.2 创建共享库

共享库(.so.dll.dylib)在运行时被动态加载。

add_library(my_shared_lib SHARED source1.cpp source2.cpp)

2.3 创建模块库

模块库(通常用于插件)在运行时可以被动态加载,但不会被链接到其他目标中。

add_library(my_module_lib MODULE source1.cpp source2.cpp)

3. 设置库的属性

使用target_*命令设置库的属性,例如包含目录、编译定义等。

target_include_directories(my_shared_lib PUBLIC include)
target_compile_definitions(my_shared_lib PRIVATE MY_SHARED_LIB_BUILD)

4. 安装库

使用install命令来指定库安装的规则。

install(TARGETS my_shared_lib DESTINATION lib)

5. 链接其他库

使用target_link_libraries将其他库链接到您创建的库。

target_link_libraries(my_shared_lib another_library)

6. 使用别名

为库创建别名,使其可以在项目中以一致的方式被引用。

add_library(my_lib_alias ALIAS my_shared_lib)

7. 管理大型项目

对于大型项目,合理组织多个库文件可以提高项目的模块化和可维护性。考虑将功能相关的类和函数分组到不同的库中。

8.代码示例

8.1完整示例MODULE

了创建一个跨平台的示例,我们需要编写一个可以在Windows和类Unix系统(如Linux和macOS)上运行的程序。为此,我们将使用预处理器指令来区分平台并使用相应的动态加载库API。下面的示例展示了如何在CMake中创建一个模块库,并在主程序中根据操作系统动态加载这个库。

  • 项目结构
cssCopy codeMyProject/
├── CMakeLists.txt
└── src/
    ├── Plugin.cpp
    └── main.cpp
  • Plugin.cpp

模块库的实现文件,位于src/目录下。

cppCopy code// Plugin.cpp
#include <iostream>

extern "C" void loadPlugin() {
    std::cout << "Plugin Loaded!" << std::endl;
}
  • main.cpp

主程序的实现文件,用于动态加载模块库。

// main.cpp
#include <iostream>

#if defined(_WIN32)
    #include <windows.h>
#else
    #include <dlfcn.h>
#endif

int main() {
    #if defined(_WIN32)
        HMODULE hModule = LoadLibrary(TEXT("MyPlugin.dll"));
        if (!hModule) {
            std::cerr << "Cannot load library: " << GetLastError() << '\n';
            return 1;
        }
        typedef void (*Func)();
        Func loadPlugin = (Func) GetProcAddress(hModule, "loadPlugin");
    #else
        void* handle = dlopen("./libMyPlugin.so", RTLD_LAZY);
        if (!handle) {
            std::cerr << "Cannot load library: " << dlerror() << '\n';
            return 1;
        }
        typedef void (*Func)();
        dlerror(); // 清除现有的错误
        Func loadPlugin = (Func) dlsym(handle, "loadPlugin");
        const char* dlsym_error = dlerror();
        if (dlsym_error) {
            std::cerr << "Cannot load symbol 'loadPlugin': " << dlsym_error << '\n';
            dlclose(handle);
            return 1;
        }
    #endif

    // 使用库
    loadPlugin();

    // 关闭库
    #if defined(_WIN32)
        FreeLibrary(hModule);
    #else
        dlclose(handle);
    #endif
    return 0;
}
  • CMakeLists.txt

CMake的配置文件,用于构建整个项目。

cmake_minimum_required(VERSION 3.10)

project(MyPluginProject)

# 创建模块库
add_library(MyPlugin MODULE src/Plugin.cpp)

# 创建可执行文件
add_executable(MyExecutable src/main.cpp)

# 设置输出目录(可选)
set_target_properties(MyPlugin PROPERTIES
    LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/plugins"
)

在这个示例中,我们首先创建了一个名为MyPlugin的模块库,然后创建了一个名为MyExecutable的可执行文件。main.cpp中的代码根据编译平台选择正确的动态加载方法。

这个跨平台的示例演示了如何在CMake中创建和使用模块库,并展示了如何在Windows和类Unix系统上动态加载和使用这种类型的库

8.2完整示例SHARED

  • 项目结构

设想我们的项目结构如下:

cssCopy codeMyProject/
├── CMakeLists.txt
├── include/
│   └── MySharedLib.h
└── src/
    ├── MySharedLib.cpp
    └── main.cpp
  • MySharedLib.h

这是共享库的头文件,位于include/目录下。

cppCopy code// MySharedLib.h
#ifndef MYSHAREDLIB_H
#define MYSHAREDLIB_H

void printHelloShared();

#endif // MYSHAREDLIB_H
  • MySharedLib.cpp

这是共享库的实现文件,位于src/目录下。

cppCopy code// MySharedLib.cpp
#include "MySharedLib.h"
#include <iostream>

void printHelloShared() {
    std::cout << "Hello from MySharedLib!" << std::endl;
}
  • main.cpp

这是主程序的实现文件,也位于src/目录下。

cppCopy code// main.cpp
#include "MySharedLib.h"

int main() {
    printHelloShared();
    return 0;
}
  • CMakeLists.txt

这是CMake的配置文件,用于构建整个项目。

cmakeCopy codecmake_minimum_required(VERSION 3.10)

# 设置项目名称
project(MyProject)

# 指定包含目录
include_directories(include)

# 添加共享库"MySharedLib"
add_library(MySharedLib SHARED src/MySharedLib.cpp)

# 创建可执行文件
add_executable(MyExecutable src/main.cpp)

# 链接共享库到可执行文件
target_link_libraries(MyExecutable MySharedLib)

在这个例子中,我们首先设置了项目名称和包含目录。接着,我们使用add_library命令添加了一个名为MySharedLib的共享库,并指定了它的源文件。然后,我们用add_executable命令创建了一个名为MyExecutable的可执行文件,并使用target_link_libraries命令将MySharedLib共享库链接到这个可执行文件上。

这个完整的示例展示了如何在CMake中创建和使用共享库,以及如何在应用程序中链接和使用这种类型的库。

8.3完整示例STATIC

  • 项目结构
MyProject/
├── CMakeLists.txt
├── include/
│   └── MyStaticLib.h
└── src/
    ├── MyStaticLib.cpp
    └── main.cpp
  • MyStaticLib.h

这是静态库的头文件,位于include/目录下。

cppCopy code// MyStaticLib.h
#ifndef MYSTATICLIB_H
#define MYSTATICLIB_H

void printHelloStatic();

#endif // MYSTATICLIB_H
  • MyStaticLib.cpp

这是静态库的实现文件,位于src/目录下。

cppCopy code// MyStaticLib.cpp
#include "MyStaticLib.h"
#include <iostream>

void printHelloStatic() {
    std::cout << "Hello from MyStaticLib!" << std::endl;
}
  • main.cpp

这是主程序的实现文件,也位于src/目录下。

cppCopy code// main.cpp
#include "MyStaticLib.h"

int main() {
    printHelloStatic();
    return 0;
}
  • CMakeLists.txt

这是CMake的配置文件,用于构建整个项目。

 codecmake_minimum_required(VERSION 3.10)

# 设置项目名称
project(MyProject)

# 指定包含目录
include_directories(include)

# 添加静态库"MyStaticLib"
add_library(MyStaticLib STATIC src/MyStaticLib.cpp)

# 创建可执行文件
add_executable(MyExecutable src/main.cpp)

# 链接静态库到可执行文件
target_link_libraries(MyExecutable MyStaticLib)

在这个示例中,我们首先设置了项目名称和包含目录。接着,我们使用add_library命令添加了一个名为MyStaticLib的静态库,并指定了它的源文件。然后,我们用add_executable命令创建了一个名为MyExecutable的可执行文件,并使用target_link_libraries命令将MyStaticLib静态库链接到这个可执行文件上。

这个完整的示例展示了如何在CMake中创建和使用静态库,以及如何在应用程序中链接和使用这种类型的库。

8.4例子分析STATIC 、SHARED、MODULE分析

创建和使用不同类型的库(静态库、共享库、模块库)是CMake中的一个核心概念。以下是对之前提到的三种类型库的创建和使用的总结:

1. 静态库(STATIC)

  • 定义:静态库是编译时链接到可执行文件中的库,不需要在运行时动态加载。
  • 优点:简化部署(不需要确保共享库在运行时可用),提高运行时性能(减少动态链接的开销)。
  • 使用场景:适用于不需要共享代码的情况,以及对性能有较高要求的场景。

2. 共享库(SHARED)

  • 定义:共享库是在运行时被动态加载的库,允许代码在多个程序之间共享。
  • 优点:节省内存(同一共享库的单个副本可被多个程序使用),易于更新(更新共享库而无需重新编译使用它的程序)。
  • 使用场景:适用于需要跨多个程序共享代码的场景。

3. 模块库(MODULE)

  • 定义:模块库通常用于实现插件或动态加载模块,它们在构建时不链接到其他目标,但可以在运行时动态加载。
  • 优点:灵活性高(可随需加载或卸载),有助于减小应用程序的初始内存占用。
  • 使用场景:适用于插件系统或需要可拓展性的应用程序。

在实际项目中,选择哪种类型的库取决于项目的需求和设计目标。静态库适合内部紧密耦合的组件,共享库适合于需要跨多个应用共享的代码,而模块库则是为动态拓展性而设计。理解这些不同类型的库以及它们的用途和优势,可以帮助开发者更有效地构建和管理CMake项目

9. 结论

通过有效地使用add_library,您可以在CMake项目中灵活地创建和管理各种类型的库。这不仅有助于提高项目的结构清晰度,还可以在不同的场景下为您的应用或库提供适当的链接和加载机制。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DevOps(3)

目录 11.描述root账户&#xff1f; 12.如何在发出命令时打开命令提示符&#xff1f; 14.Linux系统下交换分区的典型大小是多少&#xff1f; 15.什么是符号链接&#xff1f; 11.描述root账户&#xff1f; root账户就像一个系统管理员账户&#xff0c;允许你完全控制系统。 …

[DevOps-03] Build阶段-Maven安装配置

一、简要说明 下载安装JDK8下载安装Maven二、复制准备一台虚拟机 1、VM虚拟复制克隆一台机器 2、启动刚克隆的虚拟机,修改IP地址 刚刚克隆的虚拟机 ,IP地址和原虚拟的IP地址是一样的,需要修改克隆后的虚拟机IP地址,以免IP地址冲突。 # 编辑修改IP地址 $ vi /etc/sysconfig…

6. Mybatis 缓存

6. Mybatis 缓存 MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。缓存可以极大的提升查询效率MyBatis系统中默认定义了两级缓存 一级缓存二级缓存 默认情况下&#xff0c;只有一级缓存&#xff08;SqlSession级别的缓存&#xff0c;也称为本地缓存&…

OpenGL如何基于glfw库 进行 点线面 已解决

GLFW是现在较流行、使用广泛的OpenGL的界面库&#xff0c;而glut库已经比较老了。GLEW是和管理OpenGL函数指针有关的库&#xff0c;因为OpenGL只是一个标准/规范&#xff0c;具体的实现是由驱动开发商针对特定显卡实现的。由于OpenGL驱动版本众多&#xff0c;它大多数函数的位置…

国内CRM系统哪个品牌比较好?

国内CRM系统哪个品牌比较好? 作为简道云第一个以“独立套件”开发出来的业务系统&#xff0c;对于简道云CRM我从来都是“昂首挺胸”的骄傲和自豪的&#xff01; 下面就从功能、价格、自定义3大块儿来介绍下简道云CRM管理系统&#xff01; CRM管理系统&#xff0c;即开即用​…

一加 Buds 3正式发布:普及旗舰音质 一加用户首选

1月4日&#xff0c;一加新品发布会正式推出旗下新款耳机一加 Buds 3。延续一加经典美学&#xff0c;秉承音质完美主义追求&#xff0c;一加 Buds 3全面普及一加旗舰耳机体验&#xff0c;其搭载旗舰同款“超清晰同轴双单元”&#xff0c;配备49dB 4000Hz超宽频主动降噪&#xff…

进程和计划任务

一、程序进程 1.1 什么是程序 是一组计算机能识别和执行的指令&#xff0c;运行于电子计算机上&#xff0c;满足人们某种需求的信息化工具 用于描述进程要完成的功能&#xff0c;是控制进程执行的指令集 二、进程 2.1 什么是进程&#xff1f; 记载到内存中运行&#xff…

Visual Saliency Transformer (VST) 源代码实现

1.论文信息 1.1论文标题&#xff1a;Visual Saliency Transformer (VST) Nian Liu, Ni Zhang, Kaiyuan Wan, Junwei Han, and Ling Shao 1.2 Github源代码地址&#xff1a;https://github.com/nnizhang/VST 1.3论文下载链接&#xff1a;http://openaccess.thecvf.com/conte…

vue+elementUI+XLSX.utils.sheet_to_json实现复杂表头的导入功能

导入表excel 问题 XLSX.utils.sheet_to_json方法不带参数的调用&#xff0c;无法解析我们的复杂表头的excel表格&#xff0c;因此&#xff0c;我们需要通过传参数&#xff0c;来指定表头的真实起始位置。 关键代码分析&#xff1a;XLSX.utils.sheet_to_json XLSX.utils.shee…

Linux驱动开发笔记(六):用户层与内核层进行数据传递的原理和Demo

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/135384355 红胖子网络科技博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬…

【管理篇 / 恢复】❀ 07. macOS下用命令刷新固件 ❀ FortiGate 防火墙

【简介】随着苹果电脑的普及&#xff0c;很多管理员都会通过苹果电脑对飞塔防火墙进行管理。当防火墙需要命令状态下刷新固件时&#xff0c;在macOS下用命令刷新固件&#xff0c;将会是一个小小的挑战。 首先是硬件的连接&#xff0c;USB配置线的USB一头&#xff0c;接入MAC的U…

【springboot+mybatis实现CURD模版项目-Jesus】

springbootmybatis实现CURD模版项目-Jesus STEP 1 项目创建 1.1 新建Spring Initializr项目   1.2 选择需要的依赖 springboot有2.7.2直接选272STEP 2 配置更改 2.1更改maven配置   2.2 检查项目配置jdk、sdk、jre版本一致   2.3 检查pom文件&#xff0c;Maven-Reload pr…

线程池的shutdown和shutdownnow的区别

1、先说结论 shutdown ---- 不再接收新的任务&#xff0c;但是已经在执行中和队列中的任务会等待执行完成&#xff0c; 对workers中空闲的线程执行interrupt shutdownnow ---- 不再接收新的任务&#xff0c;清空队列的任务&#xff0c;对works中所有的线程执行interrupt&…

Vue3 自定义Hooks大全:一站式解决你的疑惑!

前言 不知道喜欢 vue3 的小伙伴和我是不是一样&#xff0c;刚上手vue3 的时候 对自定义hooks 一脸懵逼&#xff0c;在一些视频网站学习的时候老师讲解到自定义hooks 最喜欢用 加减乘除来描述 自定义hooks 是咋用的&#xff0c;可能是我理解能力比较差吧&#xff0c;我看了这个…

C 练习实例19

题目&#xff1a;一个数如果恰好等于它的因子之和&#xff0c;这个数就称为"完数"。例如61&#xff0b;2&#xff0b;3.编程找出1000以内的所有完数。 程序分析&#xff1a;请参照&#xff1a;C 练习实例14。 步骤分析&#xff1a; 写一个函数判断是否是完数 找出…

2.4G无线收发芯片XL2407P产品特征介绍,专为多组PWM的应用设计。

XL2407P 芯片是工作在 2.400~2.483GHz 世界通用 ISM 频段&#xff0c;集成微控制器的的 SOC 无线收发芯片。该芯片集成射频收发机、频率收生器、晶体振荡器、调制解调器等功能模块&#xff0c;并且支持一对多组网和带 ACK的通信模式。发射输出功率、工作频道以及通信数据率均可…

SpingBoot的项目实战--模拟电商【5.沙箱支付】

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于SpringBoot电商项目的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一. 沙箱支付是什么 二.Sp…

vscode安装Prettier插件,对vue3项目进行格式化

之前vscode因为安装了Vue Language Features (Volar)插件&#xff0c;导致Prettier格式化失效&#xff0c;今天有空&#xff0c;又重新设置了一下 1. 插件要先安装上 2. 打开settings.json {"editor.defaultFormatter": "esbenp.prettier-vscode","…

Springcloud 微服务实战笔记 Feign

优点 基于Netflix Feign实现&#xff0c;整合了Spring cloud Ribbon 和 Spring cloud Hystrix 提供了声明式的WEB服务客户端定义方式 扩展了Spring MVC的注解支持 使用 1、pom导入包&#xff1a; <dependency><groupId>org.springframework.cloud</groupId…

系统崩溃无U盘重装Win10系统的方法

用户反映自己电脑上的操作系统出现了崩溃问题&#xff0c;无法通过简单的操作解决问题&#xff0c;想重新安装正常的操作系统&#xff0c;但是没有U盘不知道要怎么操作才能安装好系统&#xff1f;接下来小编带来系统崩溃无U盘重装Win10系统的方法步骤介绍&#xff0c;用户们可以…