库主要分为两种类型:静态库(static library)和动态库(shared library)。
静态库是一个在链接过程中采用静态链接方式链接进可执行文件中的库文件,在静态链接方式中,可执行文件会拷贝静态库中导出的接口并使其成为它的一部分。在Windows
系统中它主要是以.lib
为后缀,而在Linux
系统中,主要以.a
为后缀。
项目结构为:
.
├── CMakeLists.txt
├── library.h
├── library.cpp
CMakeLists.txt
中的内容为:
cmake_minimum_required(VERSION 3.26)
project(library)
set(CMAKE_CXX_STANDARD 11)
add_library(library STATIC library.cpp)
library.h
的内容为:
#ifndef HELLO_LIB_LIBRARY_H
#define HELLO_LIB_LIBRARY_H
#include
class Test {
public:
explicit Test(std::string str);
std::string getStr() ;
static int getNum() ;
private:
std::string str_;
static int num; // count value
};
void print();
#endif //HELLO_LIB_LIBRARY_H
library.cpp
的内容为:
#include "library.h"
#include
int Test::num = 0; // init
Test::Test(std::string str):str_(std::move(str)) {}
std::string Test::getStr() {
++num;
return str_;
}
int Test::getNum(){
return num;
}
采用cmake
进行构建,即可生成对应的静态库文件,在Window
环境下将会生成library.lib
,而在Linux
环境下将会生成liblibrary.a
。
随后可以在另一个项目中使用它,项目结构为:
.
├── build
├── CMakeLists.txt
├── include
│ └── library.h
├── lib
│ └── library.lib
└── src
└── main.cc
CmakeLists.txt
的内容为:
cmake_minimum_required(VERSION 3.10)
project(lib_test)
set(CMAKE_CXX_STANDARD 11)
include_directories(include)
# 增加链接库的搜索路径
link_directories(lib)
# 链接 library库
link_libraries(library)
add_executable(${PROJECT_NAME} src/main.cc)
而随后就可以在main.cc
中使用它们了:
#include
#include"library.h"
int main()
{
Test test("Hello");
std::cout << test.getStr();
std::cout << Test::getNum();
return 0;
}
动态库也叫做共享库,在编译时并不会将所导出的接口拷贝到可执行文件中,而是在运行时才会被程序所引用。在Windows
系统中它主要是以.dll
为后缀,而在Linux
系统中,主要以.so
为后缀。需要特别注意的是,在MSVC
编译器中,Windows
环境下不仅生成dll
后缀文件,还会生成.lib
文件,该文件此刻的作用是作为一个导入库。
项目结构大体上和上述提到的构建的静态库一致,但还需要修改一下CMakeLists
以及library.h
(针对MSVC
编译器,Linux
环境、MinGW-gcc
不用管)。
library.h
文件:
#ifndef HELLO_LIB_LIBRARY_H
#define HELLO_LIB_LIBRARY_H
#ifndef EXPORTTING
#define DECLSPEC __declspec(dllimport)
#else
#define DECLSPEC __declspec(dllexport)
#endif // EXPORTTING
#include
class DECLSPEC Test {
public:
explicit Test(std::string str);
std::string getStr() ;
static int getNum() ;
private:
std::string str_;
static int num; // count value
};
void DECLSPEC print();
#endif //HELLO_LIB_LIBRARY_H
需要额外的添加__declspec(dllexport)
指示这个类/函数是一个可导出类或函数,以便在dll
中导出它的接口同时在lib
中有对应的符号信息(只有添加了它,MSVC
才会生成必需的.lib
导入库)。同时在使用这个库的项目中引用相关的头文件也需要添加__declspec(dllimport)
来导入所需的数据(没有这个扩展的话,在一些场景时会出现无法解析符号的错误,比如静态数据的导出等),所以为了方便使用同一个头文件,在这里采用一个宏来标识这两者的切换时刻。(构建库时导出(__declspec(dllexport)
),使用库时导入(__declspec(dllimport)
))
修改CMakeLists
文件:
cmake_minimum_required(VERSION 3.26)
project(library)
set(CMAKE_CXX_STANDARD 11)
# SHARED 共享库
add_library(library SHARED library.cpp)
# 加入预定义宏 EXPORTTING
add_definitions(-DEXPORTTING )
在对应环境下采用Cmake
工具 构建即可得到对应环境下的动态库文件,比如Windows
环境下会生成.lib
文件和.dll
文件,.lib
直接和静态库的配置方式一样,在CMakeLists
中修改即可,而将.dll
文件直接放置在可执行文件同一路径下,即可隐式链接、调用。而在Linux
环境中,只会生成一个.so
文件,其在其他项目的cmake
使用配置与静态库配置一致。
前面提到的cmake
工具构建,构建涉及的命令可以归纳为以下步骤:
# 在项目根目录下执行
# 创建build目录 并进行构建
cmake -Bbuild
# 执行 make 即可完成构建
# 方式一
cd build
make
# 方式二 build 是构建目录 lib_test 是构建目标名
cmake --build build --target lib_test -j 8