天天看點

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