一、库的概念理解
-
概念
我们知道C++工程在编译时,含有main()函数的文件会被生成可执行程序。而那些不含main()函数的代码,编译后一般是被其他程序调用,因此我们可以把他们打包成一个“东西”,即为库(Library)。
库一般是许多程序和算法的集合,例如openCV库包含了很多计算机视觉相关算法,Eigen库提供了很多矩阵代数计算的算法。 -
库的编写
在该文件夹中新建如下的libHelloWorld.cpp文件://不含main()函数的库文件 #include <iostream> using namespace std; void printHello() { cout << "Hello world!"<< endl; } void printHelloSLAM() { cout << "Hello SLAM!"<< endl; }
-
库的分类:
- 静态库的代码在编译过程中已经被载入可执行程序,因此生成的可执行程序体积较大。静态用.a为后缀,
- 例如生成静态库:add_library( hello libHelloWorld.cpp )
- 输出: hello.a
- 共享库(动态库)的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此生成的可执行程序代码体积较小。
-
- 例如生成静态库:add_library( hello_shared SHARED libHelloWorld.cpp )
- 输出: hello_shared.so
二、编写头文件
为什么要编写头文件?
库文件是一个压缩包,里面有编译好的二进制函数,如果仅有.a或者.so库文件,那么我们并不知道里面的函数是什么,调用的形式三怎样的。为了让别人使用这个库,我们需要一个头文件,说明这个库里都包含了什么。因此只要拿到了头文件和库文件,就可以调用这个库。
举例
-
编写头文件,libHelloWorld.h头文件
#ifndef LIBHELLOWORLD_H_ #define LIBHELLOWORLD_H_ //进行宏定义时为了防止重复引用头文件而引起重定义错误 void printHello(); //声明包含的库函数 void printHelloSLAM(); #endif
-
编写主函数,useHello.cpp主文件
#include "libHelloWorld.h" //声明头文件 int main() { printHello(); return 0; }
-
主函数和库文件链接起来,cmake
# 生成动态库hello_shared add_library( hello_shared SHARED libHelloWorld.cpp ) #正常对useHello.cpp文件进行编译 add_executable( useHello useHello.cpp ) #建立与库文件的链接(注意!添加的是库文件的名称,不是头文件的名称) target_link_libraries( useHello hello_shared )
理解:
-
在编写主函数useHello.cpp的时候,调用了libHelloWorld.h头文件,相当于把头文件里
void printHello();
和void printHelloSLAM();
两个函数定义都包含进去了,相当于提前做了声明(即在主文件中对这两个函数做了定义),如:主函数void printHello(); //声明包含的库函数 void printHelloSLAM(); int main() { printHello(); return 0; }
那么在主函数中调用其中函数
printHello();
的时候,则会去共享库文件中搜索这些函数,而由于在cmake文件中通过target_link_libraries( useHello hello_shared )
将useHello.cpp主函数和libHelloWorld.h头文件链接起来了,因此主函数在头文件中搜索,则会找到函数定义。 -
头文件是把打包好的库文件所有的函数做了一个说明、罗列、展示、介绍,包含哪些函数。因此当我们调用库的时候,相当于把所有的函数都在开头声明了一下,在真正调用的时候则会在库中对这些函数进行搜索。
!!!头文件与其说是库文件的说明文件,不如说是提前定义好了一些函数声明,而具体定义在库文件中
参考:
C++个人学习笔记——5. 编写库文件及头文件 - yikang的文章 - 知乎
c++库文件头文件链接原理(全)_黑猫爱小鹿的博客-CSDN博客_c++库文件