我之所以要写这个,是因为我分不清 GCC 中的 -I 和 -L 参数。我常常觉得他们的功能是相同的。比如我希望使用一个名为 math 的库,为什么我既需要用 -I 来让构建程序去搜索 math.h,又要用 -L 来让构建程序去搜索 libmath.so 。为什么我不能像 Python 一样,只是用一个关键词 import 就可以完成上面这两件事情呢?
一个项目在逻辑上是一个整体,但是在实现上,是一个个独立的模块。编译的过程,就是将源码模块转成二进制模块(Object file)的过程;链接的过程,就是将二进制模块组合成一个整体的过程。
在这两个过程中,其实都面临“未知的整体与已知的局部”的矛盾,而不是只在链接的过程中有。在编译过程中,源文件可能使用了没有在本文件中定义的函数,进而导致无法编译,所以我们需要头文件来“安慰”编译过程。而在链接过程中,我们需要真的找到那些被定义好的函数,所以我们需要库来“安慰”链接过程。这两个相似但不同的“安慰”,就分别是 -I 和 -L 的区别。
不过在编译型语言中出现的这个问题,在 CMake 这种高级构建系统中得到了解决。一个库文件可以通过在自己的属性中引入一个 PUBLIC 的头文件,使得这个库的调用者,可以在链接这个库的时候,顺藤摸瓜的找到对应的头文件。