静态库生成
假设你的项目结构如下:
css
MyProject/
├── CMakeLists.txt
├── include/
│ └── head.h
└── src/
├── add.cpp
├── div.cpp
├── mult.cpp
└── sub.cpp
你想要将src
目录下的源文件编译成一个名为calc
的静态库,并将该库的头文件放在include
目录下。
c
#ifndef _HEAD_H_
#define _HEAD_H_
// 加法
int add(int a, int b);
// 减法
int subtract(int a, int b);
// 乘法
int multiply(int a, int b);
// 除法
double divide(int a, int b);
#endif // _HEAD_H_
CMakeLists.txt文件配置
为了生成静态库,你需要在CMakeLists.txt
文件中指定库的名称、类型(静态或动态),以及包含在库中的源文件。
cmake
cmake_minimum_required(VERSION 3.0)
project(CALC)
# 包含头文件目录
include_directories(${PROJECT_SOURCE_DIR}/include)
# 搜索当前目录下的所有源文件,并将名称保存到 SRC_LIST 变量
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
# 添加静态库目标
add_library(calc STATIC ${SRC_LIST})
这里的add_library
命令用于生成静态库。calc
是库的名称,STATIC
指明这是一个静态库,${SRC_LIST}
包含了要编译进库的所有源文件。
静态库命名约定
- 在Linux 上,静态库的命名约定是
lib
前缀加上库的名称,然后是.a
后缀。例如,上述示例中的库将会被命名为libcalc.a
。 - 在Windows 上,静态库通常有
.lib
后缀,但没有lib
前缀,因此上述库可能会被命名为calc.lib
。
使用静态库
一旦静态库被创建,它就可以被其他项目通过target_link_libraries
命令链接使用了。如果静态库和主项目在同一个CMake项目中,可以直接链接;如果不在,可能需要使用find_library
或者手动设置静态库的路径。
vs使用方法
1. 将静态库添加到项目中
首先,你需要将静态库文件(.lib)复制到你的项目目录中,或者至少保证Visual Studio能够找到它。 ![[1707799640675.jpg]]
2. 配置项目以链接静态库
接下来,需要配置项目来链接这个静态库。方法如下:
- 打开Visual Studio,右键点击解决方案资源管理器中的项目名,选择"属性"。
- 点击"C/C++"->"常规",在"附加包含目录"字段添加头文件的地址。 ![[Pasted image 20240213125305.png]]
- 在弹出的属性页中,选择"链接器"->"输入",在"附加依赖项"字段中输入你的静态库文件名,比如
calc.lib
。如果有多个库,用分号隔开。 ![[Pasted image 20240213125356.png]] - 如果你的静态库不在项目目录中,还需要在"链接器"->"常规"下的"附加库目录"中添加静态库所在的目录路径。 ![[Pasted image 20240213125425.png]]
3. 包含头文件并调用
c
#include <stdio.h>
#include "head.h"
int main()
{
int a = 20;
int b = 12;
printf("a = %d, b = %d\n", a, b);
printf("a + b = %d\n", add(a, b));
printf("a - b = %d\n", subtract(a, b));
printf("a * b = %d\n", multiply(a, b));
printf("a / b = %f\n", divide(a, b));
return 0;
}
注意
- 确保在Release和Debug模式下都配置了静态库,有时你可能需要为不同的编译模式链接不同版本的库。
- 如果在链接时出现找不到符号的错误,可能是因为没有正确配置静态库,或者静态库和你的项目使用了不同的运行时库设置(比如,一个使用了多线程DLL,另一个没有)。确保库和你的项目使用了相同的设置。
动态库生成
动态库在程序运行时被加载,可以被多个程序共享,这样可以节省内存,同时也便于更新和维护。
步骤 1: 准备源代码
首先,你需要有源代码文件。假设你的项目结构如下所示,其中包括多个.c
文件(或.c
)和头文件:
css
MyProject/
├── include/
│ └── head.h
└── src/
├── add.c
├── div.c
├── mult.c
└── sub.c
head.h
文件可能看起来像这样:
c
#ifndef _HEAD_H_
#define _HEAD_H_
#ifdef _WIN32
#ifdef CALC_EXPORTING
#define CALC_API __declspec(dllexport)
#else
#define CALC_API __declspec(dllimport)
#endif
#else
#define CALC_API
#endif
#ifdef __cplusplus
extern "C" {
#endif
// 加法
CALC_API int add(int a, int b);
// 减法
CALC_API int subtract(int a, int b);
// 乘法
CALC_API int multiply(int a, int b);
// 除法
CALC_API double divide(int a, int b);
#ifdef __cplusplus
}
#endif
#endif // _HEAD_H_
步骤 2: 编写CMake配置
在项目的根目录下创建一个CMakeLists.txt
文件,并填写以下内容:
cmake
cmake_minimum_required(VERSION 3.0)
project(CALC)
# 设置C++标准
set(CMAKE_CXX_STANDARD 11)
# 设置可执行文件的输出路径
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin/)
# 添加头文件搜索路径
include_directories(${PROJECT_SOURCE_DIR}/include)
# 查找当前目录下的所有源文件,并将名称保存到 SRC_LIST 变量
file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/src/*.c)
# 添加一个可执行文件
#add_executable(app ${SRC_LIST})
# 添加静态库目标
add_library(calc SHARED ${SRC_LIST})
target_compile_definitions(calc PRIVATE CALC_EXPORTING)
步骤 3: 构建动态库
在项目根目录下,打开终端或命令提示符,运行以下命令来创建构建目录(如果还没有)并使用CMake配置项目:
bash
mkdir build
cmake -S . -B build
cmake --build build
这会在指定的库输出路径(这里是项目根目录下的lib
文件夹)生成动态库文件libcalc.so
(在Linux上)或calc.dll
(在Windows上)和对应平台的静态库文件,这两个文件都是需要的。
- 动态库的名字和格式取决于你的操作系统。在Linux和UNIX系统上,动态库通常有
.so
扩展名,在Windows上则是.dll
。 - 使用动态库时,确保在运行时库路径可找到,否则程序可能无法启动。在Linux上,你可以使用
LD_LIBRARY_PATH
环境变量来指定动态库的搜索路径。 - 动态库的一个优点是可以在不重新编译程序的情况下更新库。然而,要确保新版本的库是向后兼容的,以避免运行时错误。
使用动态库
vs使用方法
同静态库基本一致,lib和dll文件都需要,而且注意默认情况下要将dll文件放置到项目根目录。
输出路径
可以通过设置特定的变量来指定库文件(无论是动态库还是静态库)和可执行文件的输出路径。
方式1 - 主要适用于动态库和可执行文件
通过设置EXECUTABLE_OUTPUT_PATH
变量,你可以指定可执行文件和具有执行权限的动态库文件的输出路径。这种方式主要适用于动态库和可执行文件。
cmake
cmake_minimum_required(VERSION 3.0)
project(CALC)
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
# 设置动态库和可执行文件生成路径
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
# 生成动态库
add_library(calc SHARED ${SRC_LIST})
方式2 - 适用于动态库和静态库
使用LIBRARY_OUTPUT_PATH
变量,可以同时指定动态库和静态库的输出路径。这个变量对于动态库和静态库都适用,但不影响可执行文件的输出路径。
cmake
cmake_minimum_required(VERSION 3.0)
project(CALC)
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
# 设置动态库/静态库生成路径
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
# 生成动态库
# add_library(calc SHARED ${SRC_LIST})
# 生成静态库
add_library(calc STATIC ${SRC_LIST})
注意事项
EXECUTABLE_OUTPUT_PATH
和LIBRARY_OUTPUT_PATH
变量指定的是目标文件生成时的路径,而不影响安装(make install
)时的路径。安装路径需要通过INSTALL(TARGETS ...)
命令单独指定。- 如果不指定输出路径,CMake默认会将目标文件放置在构建目录的某个子目录下,这个子目录的结构通常会反映源代码目录的结构。
- 在多目标项目中,也可以对每个目标单独设置输出路径,通过为目标设置
RUNTIME_OUTPUT_DIRECTORY
,LIBRARY_OUTPUT_DIRECTORY
,ARCHIVE_OUTPUT_DIRECTORY
属性实现。