一、静态库创建
1. 准备
首先创建目录和文件结构如下:
文件内容如下:
class Hello
{
public:
void print();
};
#include "hello.h"
#include <iostream>
void Hello::print() {
std::cout << "hello world!" << std::endl;
}
project(hello_static)
file(GLOB SOURCES "src/*.*")
add_library(${PROJECT_NAME} STATIC ${SOURCES})
2. 构建&编译
首先在CMakeLists.txt同目录下打开命令行工具,通过
cmake -S . -B build
命令生成项目信息。
然后通过
cmake --build build
命令执行构建。
执行完成后可以看到在build/Debug目录下生成静态库hello_static.lib文件。
3. 说明
1.首先这里通过project命令声明项目名为hello_static,然后通过file(GLOB )命令设置源文件到SOURCES变量中,这两者在上一节已经描述过。
2.最后使用add_library()命令生成库。
add_library()命令原型如下:
add_library(<name> [STATIC | SHARED | MODULE]
[EXCLUDE_FROM_ALL]
[source1] [source2 ...])
- 参数<name>为逻辑目标名称,项目内唯一。实际产物名基于平台而变化(lib<name>.so或者<name>.lib)
- STATIC | SHARED | MODULE。表示库类型,分别表示静态,动态和插件库()。默认值与变量BUILD_SHARED_LIBS是否开启有关(开启为动态否则为静态)。
- EXCLUDE_FROM_ALL。表示EXCLUDE_FROM_ALL属性,默认true,此属性表示将当前目标排除在外,即如果设置了此参数,则在其当前项目以及父类以上的项目使用类似于make之类的操作都不响应(试了vs的生成是响应的。)。使用方式为add_library(<name> [STATIC | SHARED | MODULE] EXCLUDE_FROM_ALL [source1] [source2 ...])
- 最后是源码列表。
此处只用到了其中的三个参数。
- ${PROJECT_NAME}。表示使用PROJECT_NAME变量值。
- STATIC。表示为一个静态库
- ${SOURCES}。表示使用file创建的源文件集合变量。
二、动态库创建
1.准备
准备与静态库相同的目录结构与文件内容。
并修改CMakeLists.txt为:
project(hello_shared)
file(GLOB SOURCES "src/*.*")
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
add_library(${PROJECT_NAME} SHARED ${SOURCES})
2.构建&编译
与静态库相同。区别是产物为hello_shared.dll和hello_shared.lib.
3.说明
首先这里开启了CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS变量,保证能够生成lib文件,方便下一节链接使用。
实际上在windows下,如果没有导出任何内容(而linux下默认导出),则生成的动态库产物不包含lib文件,也就无法使用。(这里也可以通过添加导出的方式触发生成lib文件)
三、使用动/静态库
因为动/静态库的使用方式类似,所以这里使用同一个例子演示。
1.准备
首先创建如下目录:
其中hello.h,hello_shared.lib,hello_static.lib,hello_shared.dll则是前面编译的动/静态库产物。然后CMakeLists.txt和main.cpp内容如下:
project(static_use)
file(GLOB SOURCES "src/*.*")
add_executable(${PROJECT_NAME} ${SOURCES})
target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/externals/include)
target_link_libraries(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/externals/lib/hello_shared.lib)
#target_link_libraries(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/externals/lib/hello_static.lib)
#include "hello.h"
int main()
{
Hello hello;
hello.print();
return 0;
}
2.构建&编译
与之前一样通过cmake -S . -B build和cmake --build build命令进行构建和编译。
可以看到build/Debug目录下生成static_use.exe产物。
3.说明
首先,当前生效的内容为动态库,最后一句注释为静态库调用方式,将第7行替换则表示调用静态库。
前三句命令之前都有讲到,这里不再赘述。
链接动/静态库主要有两个命令:
- target_include_directories
- target_link_libraries
3.1 target_include_directories
完整语法为:
target_include_directories(<target> [SYSTEM] [BEFORE]
<INTERFACE|PUBLIC|PRIVATE> [items1...]
[<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
添加头文件目录。可以用在链接三方库,也可以用在项目内。最直观的表现为使用#include的时候,相对路径起始位置为items1,items2...
比如对于如下目录结构:
如果没有使用target_include_directories命令指定,则在引用hello.h头文件时,需要:
#include "inc/hello.h"
而添加了
target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/src/inc)
命令后,则可以变为
#include "hello.h"
命令说明:
- <target>为目标名,且不能是别名
- BEFORE。表示将目录追加还是前置到已有目录
- INTERFACE|PUBLIC|PRIVATE。表示指定目录的作用域,PRIVATE和PUBLIC项将填充<target>的INCLUDE_DIRECTORIES属性。PUBLIC和INTERFACE项将填充<target>的INTERFACE_INCLUDE_DIRECTORIES属性。
3.2 target_link_libraries
此命令比较复杂,这里只介绍本案例使用的场景(A full path to a library file)。
完整语法为:
target_link_libraries(<target>
<PRIVATE|PUBLIC|INTERFACE> <item>...
[<PRIVATE|PUBLIC|INTERFACE> <item>...]...)
指定链接的库或者依赖文件。这里使用的item为库的完成路径。
- <target>为目标名,且不能是别名
- INTERFACE|PUBLIC|PRIVATE。PUBLIC表示会链接到库,并成为接口的一部分(可以被外部使用)。PRIVATE则表示链接到库,但不作为接口(不能被外部引用)。INTERFACE表示链接到接口,但是不链接到库。