转载:CMake I 编译静态库、动态库和对象库(http://t.csdn.cn/iEf7a)
目录
上一篇入门文章只有一个文件,今天搞稍微复杂一点,增加一个类Message,将其编译为一个静态库或动态库。
一、源文件
1.Message.h
2.Message.cpp
查看代码
#include "Message.h"
#include <iostream>
#include <string>
std::ostream &Message::printObject(std::ostream &os)
{
os<<"This is message:"<<std::endl;
os<<_message;
return os;
}
3.helloworld.cpp
查看代码
#include "Message.h"
#include <iostream>
#include <string>
int main()
{
Message sayHello("Hello C++");
std::cout<<sayHello<<std::endl;
Message sayBye("Bye C++");
std::cout<<sayBye<<std::endl;
return EXIT_SUCCESS;
}
二、CMakeLists.txt
1.源文件
查看代码
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(buildLib LANGUAGES CXX)
#生成必要的构建指令,将指定的源码编译到库中。
add_library(message
STATIC
Message.cpp
Message.h
)
add_executable(helloworldexe helloworld.cpp)
#将库链接到可执行文件。
target_link_libraries(helloworldexe message)
2.CMake语言说明
(1)cmake_minimum_required
设置CMake所需的最低版本。如果使用的CMake版本低于该版本,则会发出致命错误。
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
(2)project
声明了项目的名称(buildLib)和支持的编程语言(CXX代表C++)。
project(buildLib LANGUAGES CXX)
(3)add_library
创建目标——静态库。库的名称(message)和源码文件名相同。
add_library(message STATIC Message.cpp Message.h)
CMake接受其他值作为 add_library 的第二个参数的有效值:
- STATIC:用于创建静态库,即编译文件的打包存档,以便在链接其他目标时使用,例如:可执行文件。
- SHARED:用于创建动态库,即可以动态链接,并在运行时加载的库。
- OBJECT:用于创建对象库,可将给定 add_library 的列表中的源码编译到目标文件,不将它们归档到静态库中, 也不能将它们链接到共享对象中。如果需要一次性创建静态库和动态库,那么使用对象库尤其有用。
- MODULE:又为DSO组。与 SHARED 库不同,它们不链接到项目中的任何目标,不过可以进行动态加载。该参数可以用于构建运行时插件。
CMake还能够生成特殊类型的库,这不会在构建系统中产生输出,但是对于组织目标之间的依赖关系, 和构建需求非常有用:
- IMPORTED:此类库目标表示位于项目外部的库。此类库的主要用途是,对现有依赖项进行构建。 因此, IMPORTED 库将被视为不可变的。我们将在本书的其他章节演示使用 IMPORTED 库的示例。
- INTERFACE:与 IMPORTED 库类似。不过,该类型库可变,没有位置信息。它主要用于项目之外的目标构建使用。我们将在本章第5节中演示 INTERFACE 库的示例。
- ALIAS:顾名思义,这种库为项目中已存在的库目标定义别名。不过,不能为 IMPORTED 库选择别名。
(4)add_executable
指示CMake创建一个新目标:可执行文件(helloworldexe)。
add_executable(helloworldexe helloworld.cpp)
(5)target_link_libraries
将目标库(message)链接到可执行目标(helloworldexe)。
target_link_libraries(helloworldexe message)
三、cmake配置及编译
1.cmake配置
使用cmake ..来进行配置,生成buildLib.sln项目:
2.构建/编译
使用cmake --build . 来进行构建,生成静态库及可执行文件:
【扩展】编译动态库
在 Windows 平台中生成动态库的源码和静态库是不同的。
在 Windows 平台中,我们导出动态库时,除了会生成
.dll
动态库之外还会生成一个.lib
文件。这个.lib
文件和静态库的.lib
文件不同,它里面并不保存代码生成的二进制文件,而是所有需要导出符号的符号表。因此这个.lib
文件和编译静态库生成的.lib
文件相比会小很多。这个导出的符号表是需要我们在源码中进行指定的。如果我们希望将将一个符号(symbol)导出(这里的符号可以指类、函数等各种类型):
- 方法一:需要在其前面加上
__declspec(dllexport)
标志。这样这个符号的相关信息就会导出的.lib
中的符号表中了。- 方法二:在CMakeLists.txt里添加set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
如果我们的源码中没有任何
__declspec(dllexport)
,并且没有在CMakeLists.txt里设置"导出所有符号"的话,我们依然可以成功的编译出动态库,但是并不会生成保存符号表的.lib
文件。这也是在 Windows 平台下编译动态库经常出现的问题。
(1)修改CMakeLists.txt
-
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
-
add_library(message SHARED Message.cpp Message.h)
(2)进行配置及构建
【扩展】编译对象库
(1)修改CMakeLists.txt
查看代码
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(buildLib LANGUAGES CXX)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
add_library(message-objs
OBJECT
Message.cpp
Message.h
)
set_target_properties(message-objs
PROPERTIES
POSITION_INDEPENDENT_CODE 1
)
#获取动态库
add_library(message-shared
SHARED
$<TARGET_OBJECTS:message-objs>
)
#获取静态库
add_library(message-static
STATIC
$<TARGET_OBJECTS:message-objs>
)
add_executable(helloworldexe helloworld.cpp)
target_link_libraries(helloworldexe message-static)
1.需要保证编译的目标文件与生成位置无关, 可以通过使用 set_target_properties 命令,设 置 message-objs 目标的相应属性来实现。(可能在某些平台和/或使用较老的编译器上,需要显式地为目标设置 POSITION_INDEPENDENT_CODE 属性。)
2.引用对象库的生成器表达式语法: $<TARGET_OBJECTS:message-objs>
(2)构建及编译
(3)修改库名称
查看代码
#修改动态库名称
set_target_properties(message-shared
PROPERTIES
OUTPUT_NAME "shared-message"
)
#修改静态库名称
set_target_properties(message-static
PROPERTIES
OUTPUT_NAME "static-message"
)