😈「CSDN主页」:传送门
😈「Bilibil首页」:传送门
😈「本文的内容」:CMake入门教程
😈「动动你的小手」:点赞👍收藏??评论📝
在CMake中,
add_library
命令是用于定义库(library)的关键命令。库可以是静态的(static),动态的(shared),或者是模块库。本节教程将深入探讨如何在CMake中使用add_library
命令来创建不同类型的库。
add_library
命令用于创建一个库。基本语法如下:
add_library(<name> [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] source1 [source2 ...])
<name>
:库的名称。STATIC
、SHARED
、MODULE
:指定库的类型。如果不指定,默认创建的是静态库(STATIC)。EXCLUDE_FROM_ALL
:如果设置,这个库不会被默认构建,除非有其他目标依赖它。source1 [source2 ...]
:库的源文件。静态库(.a
或.lib
文件)在编译时被完全复制到最终的可执行文件中。
add_library(my_static_lib STATIC source1.cpp source2.cpp)
共享库(.so
、.dll
或.dylib
)在运行时被动态加载。
add_library(my_shared_lib SHARED source1.cpp source2.cpp)
模块库(通常用于插件)在运行时可以被动态加载,但不会被链接到其他目标中。
add_library(my_module_lib MODULE source1.cpp source2.cpp)
使用target_*
命令设置库的属性,例如包含目录、编译定义等。
target_include_directories(my_shared_lib PUBLIC include)
target_compile_definitions(my_shared_lib PRIVATE MY_SHARED_LIB_BUILD)
使用install
命令来指定库安装的规则。
install(TARGETS my_shared_lib DESTINATION lib)
使用target_link_libraries
将其他库链接到您创建的库。
target_link_libraries(my_shared_lib another_library)
为库创建别名,使其可以在项目中以一致的方式被引用。
add_library(my_lib_alias ALIAS my_shared_lib)
对于大型项目,合理组织多个库文件可以提高项目的模块化和可维护性。考虑将功能相关的类和函数分组到不同的库中。
了创建一个跨平台的示例,我们需要编写一个可以在Windows和类Unix系统(如Linux和macOS)上运行的程序。为此,我们将使用预处理器指令来区分平台并使用相应的动态加载库API。下面的示例展示了如何在CMake中创建一个模块库,并在主程序中根据操作系统动态加载这个库。
cssCopy codeMyProject/
├── CMakeLists.txt
└── src/
├── Plugin.cpp
└── main.cpp
模块库的实现文件,位于
src/
目录下。
cppCopy code// Plugin.cpp
#include <iostream>
extern "C" void loadPlugin() {
std::cout << "Plugin Loaded!" << std::endl;
}
主程序的实现文件,用于动态加载模块库。
// 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;
}
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系统上动态加载和使用这种类型的库
设想我们的项目结构如下:
cssCopy codeMyProject/
├── CMakeLists.txt
├── include/
│ └── MySharedLib.h
└── src/
├── MySharedLib.cpp
└── main.cpp
这是共享库的头文件,位于include/
目录下。
cppCopy code// MySharedLib.h
#ifndef MYSHAREDLIB_H
#define MYSHAREDLIB_H
void printHelloShared();
#endif // MYSHAREDLIB_H
这是共享库的实现文件,位于
src/
目录下。
cppCopy code// MySharedLib.cpp
#include "MySharedLib.h"
#include <iostream>
void printHelloShared() {
std::cout << "Hello from MySharedLib!" << std::endl;
}
这是主程序的实现文件,也位于
src/
目录下。
cppCopy code// main.cpp
#include "MySharedLib.h"
int main() {
printHelloShared();
return 0;
}
这是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中创建和使用共享库,以及如何在应用程序中链接和使用这种类型的库。
MyProject/
├── CMakeLists.txt
├── include/
│ └── MyStaticLib.h
└── src/
├── MyStaticLib.cpp
└── main.cpp
这是静态库的头文件,位于include/
目录下。
cppCopy code// MyStaticLib.h
#ifndef MYSTATICLIB_H
#define MYSTATICLIB_H
void printHelloStatic();
#endif // MYSTATICLIB_H
这是静态库的实现文件,位于src/
目录下。
cppCopy code// MyStaticLib.cpp
#include "MyStaticLib.h"
#include <iostream>
void printHelloStatic() {
std::cout << "Hello from MyStaticLib!" << std::endl;
}
这是主程序的实现文件,也位于src/
目录下。
cppCopy code// main.cpp
#include "MyStaticLib.h"
int main() {
printHelloStatic();
return 0;
}
这是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中创建和使用静态库,以及如何在应用程序中链接和使用这种类型的库。
创建和使用不同类型的库(静态库、共享库、模块库)是CMake中的一个核心概念。以下是对之前提到的三种类型库的创建和使用的总结:
1. 静态库(STATIC)
2. 共享库(SHARED)
3. 模块库(MODULE)
在实际项目中,选择哪种类型的库取决于项目的需求和设计目标。静态库适合内部紧密耦合的组件,共享库适合于需要跨多个应用共享的代码,而模块库则是为动态拓展性而设计。理解这些不同类型的库以及它们的用途和优势,可以帮助开发者更有效地构建和管理CMake项目
通过有效地使用add_library
,您可以在CMake项目中灵活地创建和管理各种类型的库。这不仅有助于提高项目的结构清晰度,还可以在不同的场景下为您的应用或库提供适当的链接和加载机制。