天天看点

VSCode开发C、C++环境搭建系列(二)——GCC/G++编译器对头文件、静态库、动态库的搜索路径详解

VSCode开发C、C++环境搭建系列(二)——GCC/G++编译器对头文件、静态库、动态库的搜索路径详解

前言:前面说了C/C++编译的四大过程,本文继续前面的文章来说明编译过程中的注意事项,前面的系列文章请参考:

g++安装配置以及C++的四个编译处理过程(对比C#编译执行过程)

VSCode开发C、C++环境搭建系列(一)——基于Mingw-w64搭建

一、GCC编译的四大过程回顾

VSCode开发C、C++环境搭建系列(二)——GCC/G++编译器对头文件、静态库、动态库的搜索路径详解
  1. 预处理(Pre-Processing):主要包括宏定义,文件包含,条件编译,注释消除四部分。预处理过程读入源代码,检查包含预处理指令的语句和宏定义,并对其进行响应和替换。预处理过程还会删除程序中的注释和多余空白字符。最后会生成 

    .i

     文件。
  2. 编译器(Compiling):编译器会将预处理完的 

    .i

     文件进行一些列的语法分析,并优化后生成对应的汇编代码。会生成 

    .s

     文件。
  3. 汇编器(Assembling):汇编器会将编译器生成的 

    .s

     汇编程序汇编为机器语言或指令,也就是可以机器可以执行的二进制程序。会生成 

    .o

     文件(MSVC是生成.obj文件)。
  4. 链接器(Linking):链接器会来链接程序运行的所需要的目标文件,以及依赖的库文件,最后生成可执行文件,以二进制形式存储在磁盘中

从上面的四个过程可以得出,有两个地方是需要用到外部资源的,第一个是头文件,第二个是库文件,包括静态库和动态库。那么编译器在哪里寻找这些文件显得很重要了,编译器默认情况下都会有自己的查找规则和查找顺序,当然我们也可以手动指定编译器去哪里查找。

注意事项:

虽然我们在编译的时候只使用了gcc这一个可执行程序,但是实际在执行的时候并不是只有着一个可执行程序在执行,就像上面这幅图所展示的,编译过程是通过ccl.exe来完成的,而C++是通过cclplus.exe来完成的,汇编过程是通过as.exe来完成的,链接过程是通过ld.exe来完成的,其实在整个GCC套件里面还有很多的可执行程序,这些可执行程序每一个都有自己的作用,都在不同的文件夹中,GCC正是通过协调他们之间的工作与协作来实现完整的编译过程的。

二、如何查看GCC编译器的默认搜索路径

我们可以通过制定GCC命令的参数来查看,但是GCC现在的命令参数实在是太多了,现在有上千个命令参数,不可能每一个都记住,而且光是GCC的说明文档有900多页,也很多,我们掌握一些常见的即可,后面会专门出一篇关于GCC编译器几个重要的参数详解。注意,本文的操作系统是 CentOS 7.4 和 Windows平台之下的Mingw-w64。

首先查看一下帮助:

gcc --help
           

得到如下结果:

... ...省略了前面的
--version                     Display compiler version information
-dumpspecs                    Display all of the built in spec strings
-dumpversion                  Display the version of the compiler
-dumpmachine                  Display the compiler's target processor
-print-search-dirs            Display the directories in the compiler's search path
-print-libgcc-file-name       Display the name of the compiler's companion library
-print-file-name=<lib>        Display the full path to library <lib>
-print-prog-name=<prog>       Display the full path to compiler component <prog>
-print-multiarch              Display the target's normalized GNU triplet, used as
                                      a component in the library path
-print-multi-directory        Display the root directory for versions of libgcc
-print-multi-lib              Display the mapping between command line options and
                                      multiple library search directories
-print-multi-os-directory     Display the relative path to OS libraries
-print-sysroot                Display the target libraries directory
-print-sysroot-headers-suffix Display the sysroot suffix used to find headers

... ...省略了后面的
           

2.1 关于GCC版本以及计算机的版本查看

下面列举三个最简单的

(1)centos之下

[[email protected] ~]$ gcc --version     # 查看GCC编译器的版本信息
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

[[email protected] ~]$ gcc -dumpversion  # 查看版本信息简化版
4.8.5

[zoe@localhost ~]$ gcc -dumpmachine  #查看这台机器的信息
x86_64-redhat-linux
           

(2)Mingw-w64之下

C:\Users\Administrator>gcc --version
gcc (x86_64-win32-seh-rev0, Built by MinGW-W64 project) 8.1.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


C:\Users\Administrator>gcc -dumpversion
8.1.0

C:\Users\Administrator>gcc -dumpmachine
x86_64-w64-mingw32       # 这是Windows平台之下
           

2.2 查看默认的搜索路径

gcc -print-search-dirs  或者是
g++ -print-search-dirs
           

执行这个命令会返回三个结果:

(1)install: 路径。即所谓的gcc安装到哪一个位置的

(2)programs: 一系列路径。这个指的是需要用到的一系列的可执行文件的路径,比如ccl.exe,cclplus.exe,as.exe,ld.exe等可执行程序在哪里的路径

(3)libraries: 一系列路径。这里指的就是头文件,静态库,动态库的路径所在位置

(1)CentOS 下查看默认的搜索路径

我的电脑中GCC的可执行文件在 /usr/bin/gcc ,而库文件在  /usr/lib/gcc/x86_64-redhat-linux/4.8.5/  目录之下,有以下一些文件以及文件夹:

VSCode开发C、C++环境搭建系列(二)——GCC/G++编译器对头文件、静态库、动态库的搜索路径详解

得到如下结果

install: /usr/lib/gcc/x86_64-redhat-linux/4.8.5/
programs: =/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/:
/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/:
/usr/libexec/gcc/x86_64-redhat-linux/:
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/:
/usr/lib/gcc/x86_64-redhat-linux/:
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../x86_64-redhat-linux/bin/x86_64-redhat-linux/4.8.5/:
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../x86_64-redhat-linux/bin/

libraries: =/usr/lib/gcc/x86_64-redhat-linux/4.8.5/:
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../x86_64-redhat-linux/lib/x86_64-redhat-linux/4.8.5/:
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../x86_64-redhat-linux/lib/../lib64/:
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../x86_64-redhat-linux/4.8.5/:
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/:/lib/x86_64-redhat-linux/4.8.5/:
/lib/../lib64/:
/usr/lib/x86_64-redhat-linux/4.8.5/:
/usr/lib/../lib64/:
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../x86_64-redhat-linux/lib/:
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../:/lib/:
/usr/lib/
           

总结:

/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../x86_64-redhat-linux/lib/x86_64-redhat-linux/4.8.5/:
# 其实要分成两个来看
# /usr/lib/gcc/x86_64-redhat-linux/4.8.5/
# ../../../../x86_64-redhat-linux/lib/x86_64-redhat-linux/4.8.5/:
# 所以这两个点表示的就是前面那个路径之下的的 “上上” 一级目录
# 后面的同样的道理, ../../../ 表示的是多个上一级目录
           

为什么前面用一个路径,然后后面有用一个路径接着呢?

个人理解应该是前面的这个相当于是一个总的归纳,告诉后面的路径到底是在哪一个基础之上进行查找的。个人理解。

Linux下的搜索路径主要是在以下几个地方进行查找的:

/usr/libexec/gcc/x86_64-redhat-linux/
/usr/lib/gcc/x86_64-redhat-linux/
/usr/lib/
/lib/

           

(2)Windows之下查看

我的Windows平台上,Mingw-w64所安装的目录在 D:\Program Files\mingw64 目录之下,包含了下面的内容

VSCode开发C、C++环境搭建系列(二)——GCC/G++编译器对头文件、静态库、动态库的搜索路径详解

运行上面的命令之后的结果为: 

install: D:/Program Files/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/

programs: =D:/Program Files/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/;
D:/Program Files/mingw64/bin/../libexec/gcc/;
D:/Program Files/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/x86_64-w64-mingw32/8.1.0/;
D:/Program Files/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/

libraries: =D:/Program Files/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/;
D:/Program Files/mingw64/bin/../lib/gcc/;
D:/Program Files/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/x86_64-w64-mingw32/8.1.0/;
D:/Program Files/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/;
D:/Program Files/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../x86_64-w64-mingw32/8.1.0/;
D:/Program Files/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib/;
C:/mingw810/x86_64-810-win32-seh-rt_v6-rev0/mingw64/mingw/lib/x86_64-w64-mingw32/8.1.0/;
C:/mingw810/x86_64-810-win32-seh-rt_v6-rev0/mingw64/mingw/lib/../lib/;
D:/Program Files/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/;
D:/Program Files/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../;
C:/mingw810/x86_64-810-win32-seh-rt_v6-rev0/mingw64/mingw/lib/
           

含义解释:我们看到有这么多的点,是一脸的迷茫,什么意思呢?其实很简单,以第一句话为例子:

D:/Program Files/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/;
# 其实要分成两个来看
# D:/Program Files/mingw64/bin/
# D:/Program Files/mingw64/libexec/gcc/x86_64-w64-mingw32/8.1.0/;
# 所以这两个点表示的就是前面那个路径之下的的 “上上” 一级目录
# 后面的同样的道理, ../../../ 表示的是多个上一级目录
           

我们发现主要是来自于两个文件夹之下:

即所谓的:
  • lib文件夹
  • libexec文件夹
  • x86_64-w64-mingw32文件夹之下

注意:上面的过程其实都是我的个人想法,不一定都是正确的,望有大佬告知,感激不尽。

2.3 GCC其他几个命令的用法

-print-file-name=<lib>        Display the full path to library <lib>
-print-prog-name=<prog>       Display the full path to compiler component <prog>
           

(1)-print-prog-name参数的用法

这个参数实际上就是查看GCC套件中的可执行程序(ccl.exe,cclplus.exe,ax.exe等可执行程序)的相关信息的,使用方法如下

gcc -print-prog-name=<prog>        //显示可执行程序的名称
gcc -print-prog-name=<prog> -v     //显示这个可执行程序的详细信息
`gcc -print-prog-name=<prog>` -v   //显示这个可执行程序的详细信息
           

前面介绍了,在GCC套件中,编译的过程实际上是由ccl可执行程序来完成的,通过它ccl或者是cclplus我们可以查看头文件在哪里,在centos中,如下所示:

[[email protected] ~]$ `gcc -print-prog-name=cc1` -v
ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../x86_64-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-redhat-linux/4.8.5/include  // C语言的头文件路径
 /usr/local/include
 /usr/include
End of search list.
           

如果是执行cclplus得到:

[[email protected] ~]$ `gcc -print-prog-name=cc1plus` -v
ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../x86_64-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here:   // C++的头文件路径
 /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5
 /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/x86_64-redhat-linux
 /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/backward
 /usr/lib/gcc/x86_64-redhat-linux/4.8.5/include
 /usr/local/include
 /usr/include
End of search list.
           

三、手动指定GCC套件的搜索路径

手动指定头文件和库文件(静态库和动态库)是通过指定gcc的两个参数来完成的,如下:

  • -Idir:将dir目录加入搜索头文件的目录路径(简写为-I)
  • -Ldir:将dir目录加入搜索库的目录路径(静态库和动态库)(简写为-L)

下面是在gcc命令中手动设置搜索路径:

#添加头文件搜索路径

# gcc foo.c -I /home/xiaowp/include -o foo
           

 #添加动态库搜索路径

# gcc foo.c -L /home/xiaowp/lib -lfoo -o foo
           

 注意:这里的 -lfoo是什么意思呢?它实际上是 动态库 foo.so 的简写,我们给其添加一个前缀 -l ,然后就不能在添加后缀 .so了,所以实际上等价于:

# gcc foo.c -L /home/xiaowp/lib foo.so -o foo
           

#添加静态库搜索路径

# gcc foo.c -L /home/xiaowp/lib -static -lfoo -o foo
           

注意:这里的 -lfoo是什么意思呢?它实际上是 动态库 foo.a 的简写,我们给其添加一个前缀 -l ,然后就不能在添加后缀 .a了,所以实际上等价于:

# gcc foo.c -L /home/xiaowp/lib -static foo.a -o foo
           

四、头文件、库文件搜索顺序总结

4.1 include头文件的搜索路径

  1. 当前目录
  2. 在编译的时候使用 -I参数 手动指定的路径
  3. gcc环境变量设置CPATH ,C_INCLUDE_PATH ,CPLUS_INCLUDE_PATH ,OBJC_INCLUDE_PATH 
  4. 系统标准include路径。安装GCC套件的时候可以通过--prefix参数手动指定安装位置。

4.2 静态库(.a,.lib)

  1. gcc在编译的时候通过  -L参数  手动指定的搜索路径
  2. 再找gcc的环境变量LIBRARY_PATH
  3. 再找内定目录/lib:/usr/lib:/usr/local/lib这是这些安装GCC套件的时候所安装的那些目录

4.3 动态库(.so ,.dll )

  1. gcc在编译的时候通过  -L参数  手动指定的搜索路径
  2. 环境变量LD_LIBRARY_PATH指定的动态库搜索路径;
  3. 配置文件/etc/ld.so.conf中指定的动态库搜索路径;
  4. 再找内定目录/lib:/usr/lib:/usr/local/lib这是这些安装GCC套件的时候所安装的那些目录

参考文献:

https://blog.51cto.com/13913090/2155979

https://www.linuxidc.com/Linux/2018-01/150640.htm

https://blog.csdn.net/seekkevin/article/details/50285495

http://blog.chinaunix.net/uid-26527046-id-4927986.html

https://www.linuxidc.com/Linux/2012-06/62552.htm