前言:
一直好奇在VS编译器下,一个解决方案里如何进行多项目操作。
专门花时间研究了一下,也搜了很多博客关于使用静态库,但是几乎都是先写一个静态库文件,然后将需要的 .lib文件 和 .h文件 复制到需要调用的项目里。
虽然没啥问题,但是显得不方便,如果静态库要改,那每次都要复制,并且没有很好的利用VS多项目的功能。所以我这里整理一下使用VS2019进行静态库多项目的操作。
静态库
步骤:
创建一个名为 StaticLib 的空项目,或者直接建立静态库项目。因为直接选静态库项目会自动生成一些文件,暂时不需要。
如果选择的是空项目,需要更改项目属性,选择静态库。
现在就可以在 StaticLib 项目写代码。作为测试,我创建了一个lib类,代码如下:
//lib.h
#pragma once
class lib
{
public:
int add(int a, int b);
};
//lib.cpp
#include "lib.h"
int lib::add(int a, int b)
{
return a + b;
}
以上就将库文件写完了,下面再同一个解决方案下创建名为StaticLibCall的可执行文件,也就是一个空项目。
先不着急给StaticLibCall里写东西,先进行配置。
结合静态库文件编译生成的 lib文件 需要复制到可执行项目里,我们直接设置 StaticLib 的输出目录,原本的输出位置默认是在改解决方案下创建一个Debug的文件夹,里面有两个文件,一个lib库文件,一个pdb文件(源代码调试用的)。
这里,我们更改输出目录,改到 StaticLibCall 目录下。
这样每次在编译库文件的时候,就不需要复制lib文件,但是.h头文件的问题没有解决。
其实头文件的问题很好解决,在使用的时候直接在#include 后写相对路径找到对应的.h文件即可。
此时,还需要给 StaticLibCall 设置依赖,保证每次编译先编译 StaticLib 再编译 StaticLibCall。
最后将 StaticLibCall 设置为启动项。就可以在StaticLibCall里调用静态库的函数了,例如,我创建了一个main.cpp,内容如下:
#include <iostream>
#include "../StaticLib/lib.h"
#pragma comment (lib,"StaticLib.lib")//指定与静态库一起连接
int main()
{
lib b;
std::cout << b.add(2, 3) << std::endl;
return 0;
}
其中#pragma comment (lib,"StaticLib.lib")一定要有,不然会报错。
之后直接运行即可。
总结:
虽然上述让每次修改静态库库文件不需要再复制lib和h文件,但是暂时,我总觉得还有有点怪怪的,看博客还有其他人配置依赖项啥的,还没有弄得很清楚,之后还需要看看。
还有动态库的链接配置,我试验下再写。
补充:
经过学习,了解到另一种方法不用修改生成路径,直接进行链接。
具体的步骤类似上文,创建一个静态库文件,一个可执行文件,设置可执行文件的依赖。这里,不修改库文件的输出目录。
点开可执行文件的属性。设置链接器里常规里的附加库目录,就是整个解决方案里生成路径。
接着,设置链接器里输入里的附加依赖项。将库文件生成的lib文件的名字添加进去,注意分号。
设置完成之后就可以在可执行项目里使用,使用方式与上述相同。但是不用再写这句代码。
#pragma comment (lib,"StaticLib.lib")//指定与静态库一起连接
再补充: 第三种方法(最简单)
直接再可执行文件下的资源文件里,添加现有项,将lib文件直接添加,这样就可以直接使用,也不用修改配置。
动态库:
总体思路跟静态库没有区别,只是将项目设置为动态库dll。
主要使用的文件是动态库的 .dll .lib .h 三种文件。
使用方法也与静态库类似,操作的依然是动态库的lib文件,不是dll文件。其实考虑之后静态库的三种方法,第一种并不推荐,因为直接更改了库的输出路径,显得很蠢,并且如果后期有很多的库,会不知道生成的文件在哪里。
值得注意的是,在写动态库的时候,头文件要加__declspec(dllexport),不然会报错。
//lib.h
#pragma once
class lib
{
public:
__declspec(dllexport) int add(int a, int b);
};
补充:对于动态库在配置好环境之后,需要将dll文件放在输出文件夹(Debug/Release)里!!
解释一下:
DLL的函数分两种:
- DLL导出函数,可供调用dll的应用程序调用。
- DLL内部函数,只能在DLL程序使用,调用DLL的应用程序无法调用。
为什么动态库编译后不仅生成dll文件还生成了lib文件?
- 动态库的 lib文件 与静态库的 lib文件 是不同的,动态库的 lib文件 只是dll文件里导出函数的声明和定位信息。没有函数的实现。而静态库的 lib文件 包含了函数的实现。因此静态库的 lib文件 只是作用在编译阶段,不需要对外发布。