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

发布时间:2024年01月04日

在这里插入图片描述

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


在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项目中灵活地创建和管理各种类型的库。这不仅有助于提高项目的结构清晰度,还可以在不同的场景下为您的应用或库提供适当的链接和加载机制。

文章来源:https://blog.csdn.net/hiwoshixiaoyu/article/details/134864794
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。