这一篇文章当中我们来讲一下有关于C++当中的库以及怎么使用静态库。对于使用库这件事儿,C++确实是比其他语言更加棘手一些。如果我没用过python和其他语言,会发现直接import,库就进来了,非常的方便。但是对于C++,不同平台,不同configuration,都会导致我们的库没有办法使用,所以C++选手们通常都得被迫自己造轮子了。所以对于C++选手,在自己的解决方案当中保留自己所需要的所有的库非常重要,因为我们需要一下子就可以跑起来。尤其是当我们把项目传到比如GitHub上面的时候,有这种clone下来就能跑的特点也会方便我们的用户。
通常我们如果使用外部库,拿到的会是二进制形式的库文件。但是对于一些严肃项目来说,我们最好是能够拥有这些库的源代码,可以拿着代码先编译然后再作为库链接进来。这样的话更有助于我们调试。但是在这篇文章当中,我们还是拿二进制文件库举例子。
今天被我们拿来举例子的是GLFW库,这是一个专门针对OpenGL的C语言库,可以用来进行一些窗口的创建和操作工作。我们首先可以进入到GLFW官网下载:https://www.glfw.org/download.html
打开然后选择32/64位的适合Windows的预编译库,选择多少位的并不取决于我们目前计算机是多少位的,而是取决于我们要生成的那个目标应用要在多少位的平台上使用。在这里我们先下载一个32位的。然后解压缩看看里面有什么:
我们可以看到,里面有.dll和.lib两类文件。这也意味着库链接所包含的两种形式:静态链接static与动态链接dynamic。静态链接的时候,我们的静态库文件会直接嵌入到exe file当中去,这样我们也可以提前知道库里面包含的所有方法、变量、类等等。如果是动态链接,那么是在我们运行exe file的时候,再把它链接进去的。这需要我们在运行的时候把这个库放在某些合适的位置。我们的exe file对于动态库内部的具体内容通常不是很清楚的,需要用指针去寻找它们的位置。所以一般而言,静态链接会得到一些编译器内部优化的福利,这样会更快一些。这两者的本质区别,就是库里面的内容是否进入到了exe file当中去。
库通常包含两部分,分别是includes与library。include会包含一大堆头文件,而我们头文件里面的方法的定义就放在library当中了。通过包含头文件,我们的编译器就会知道现在我们有多少方法,然后我们在二进制文件当中去寻找这些方法的定义。
如何使用我们的GLFW库:首先我们随便新建一个解决方案,然后我们在解决方案文件夹目录下新建一个dependencies文件夹,然后在这个文件下新建一个GLFW文件夹。随后将我们include和最新的library文件夹都放在GLFW文件夹下面。接下来我们需要把include和library这两个文件路径都添加到我们的解决方案当中去。首先是include,我们在属性中找到additional include directory,然后把我们include文件夹添加进去。为了保证我们移动解决方案的位置,这里不会出错,所以可以使用宏SolutionDir来表示解决方案所在位置,然后添加上相对路径即可。
这样我们就把头文件添加进来了。然后我们可以include对应的头文件。这样就可以使用其中的函数且通过编译了。
cpp
#include<iostream>
#include<glfw3.h>
int main() {
int a = glfwInit();
std::cin.get();
}
这里需要注意的一点是,在include的时候,这里无论是使用<>还是""都是可以的,因为我们的路径已经被添加到解决方案当中了。对于Cherno而言,他通常会选择,如果是自己写的库,有源代码的情况下,使用"";如果是外部解决方案,直接链接了二进制文件,那他通常会选择<>,反正这个只是一个风格问题,怎么用都随大家的便,有自己的习惯就可以了。
但是如果我们想要生成,是会发生错误的,因为我们其实没有告诉编译器我们的函数定义在哪里,那这就需要我们再把函数定义的内容包含进来了。我们需要在设置-链接器-常规-附加库目录当中,把我们的附加库添加进来,添加方式和之前是相同的。随后我们还要告诉编译器,具体我们添加的是哪个库,在这里面我们需要把我们用的库添加进去。
在这里我遇到的一个问题是,我必须要在添加的时候写上.lib才可以,否则的话它好像会选择打开.obj文件以至于找不到文件在哪里。然后我们让控制台打印一下我们输出的值,会发现输出的值是1,我们成功调用了已经写好的库当中的函数。
那么有一个问题,如果我们不include头文件,直接在自己的cpp文件中声明这个函数会发生什么?
cpp
#include<iostream>
int glfwInit();
int main() {
int a = glfwInit();
std::cout << a << std::endl;
std::cin.get();
}
这个时候会看到一个无法解析的外部符号报错,因为我们这个库其实是基于C的,所以我们直接这样写是不合法的,需要把声明函数的方式改成:
cpp
extern "C" int glfwInit();
这样我们运行会发现结果和刚才是一样的。
以上就是有关于加载静态库的全部内容了,希望大家喜欢!