【CMake】构建和链接静态库和动态库
C++源码:
1 /** 2 * @file Message.hpp 3 */ 4 #ifndef MESSAGE_H 5 #define MESSAGE_H 6 7 #include <iosfwd> 8 #include <string> 9 class Message 10 { 11 public: 12 Message(const std::string &m) : message_(m) {} 13 friend std::ostream &operator<<(std::ostream &os, Message &obj) 14 { 15 return obj.printObject(os); 16 } 17 18 private: 19 std::string message_; 20 std::ostream &printObject(std::ostream &os); 21 }; 22 23 #endif // !MESSAGE_H
1 /** 2 * @file Message.cpp 3 */ 4 #include "Message.hpp" 5 #include <iostream> 6 #include <string> 7 std::ostream &Message::printObject(std::ostream &os) 8 { 9 os << "This is my very nice message: " << std::endl; 10 os << message_; 11 return os; 12 }
1 /** 2 * @file main.cpp 3 */ 4 #include "Message.hpp" 5 #include <cstdlib> 6 #include <iostream> 7 int main() 8 { 9 Message say_hello("Hello, CMake World!"); 10 std::cout << say_hello << std::endl; 11 Message say_goodbye("Goodbye, CMake World"); 12 std::cout << say_goodbye << std::endl; 13 return EXIT_SUCCESS; 14 }
CMakeLists.txt
1 # 设置cmake所需的最低版本 2 cmake_minimum_required(VERSION 3.21) 3 # 声明工程名称和工程支持的编程语言 4 project(CmakeTest LANGUAGES CXX) 5 # 创建静态库目标,生成目标libmessage.<扩展后缀> 6 add_library(message 7 STATIC 8 Message.hpp 9 Message.cpp 10 ) 11 12 # 指示cmake生成一个可执行程序,该程序通过编译、连接源文件main.cpp生成 13 add_executable(${PROJECT_NAME} main.cpp) 14 15 # 链接静态库 16 target_link_libraries(${PROJECT_NAME} message)
add_library
的第一个参数是目标名。整个CMakeLists.txt
中,可使用相同的名称来引用库。生成的库的实际名称将由CMake通过在前面添加前缀lib
和适当的扩展名作为后缀来形成。生成库是根据第二个参数(STATIC
或SHARED
)和操作系统确定的。
CMake接受其他值作为add_library
的第二个参数的有效值:
- STATIC:用于创建静态库,即编译文件的打包存档,以便在链接其他目标时使用,例如:可执行文件。
- SHARED:用于创建动态库,即可以动态链接,并在运行时加载的库。可以在
CMakeLists.txt
中使用add_library(message SHARED Message.hpp Message.cpp)
从静态库切换到动态共享对象(DSO)。 - OBJECT:可将给定
add_library
的列表中的源码编译到目标文件,不将它们归档到静态库中,也不能将它们链接到共享对象中。如果需要一次性创建静态库和动态库,那么使用对象库尤其有用。我们将在本示例中演示。 - MODULE:又为DSO组。与
SHARED
库不同,它们不链接到项目中的任何目标,不过可以进行动态加载。该参数可以用于构建运行时插件。
CMake还能够生成特殊类型的库,这不会在构建系统中产生输出,但是对于组织目标之间的依赖关系,和构建需求非常有用:
- IMPORTED:此类库目标表示位于项目外部的库。此类库的主要用途是,对现有依赖项进行构建。因此,
IMPORTED
库将被视为不可变的。 - INTERFACE:与
IMPORTED
库类似。不过,该类型库可变,没有位置信息。它主要用于项目之外的目标构建使用。我们将在本章第5节中演示INTERFACE
库的示例。 - ALIAS:顾名思义,这种库为项目中已存在的库目标定义别名。不过,不能为
IMPORTED
库选择别名。
target_link_libraries(hello-world message)
: 将库链接到可执行文件。此命令还确保hello-world
可执行文件可以正确地依赖于消息库。因此,在消息库链接到hello-world
可执行文件之前,需要完成消息库的构建。