使用gcc時頭文件路徑和動態連接庫路徑

    在使用gcc編譯鏈接生成可執行文件時,常常會碰到變量未定義、連接時或者運行可執行文件時找不到相應的動態庫等問題,本文首先介紹了gcc在編譯時頭文件路徑相關選項以及搜索路徑順序,而後討論了編譯成可執行文件時動態庫的搜索路徑順序,最後說明了生成可執行文件後,運行文件時動態庫的搜索路徑順序。搞清楚這三個搜索路徑,在用gcc碰到的未定義變量或搜索不到動態庫的問題,基本上均可以解決了。html

頭文件路徑編譯時相關選項
    gcc可使用選項-I(注意是大寫)來指定頭文件搜索路徑,即頭文件所在的文件夾。指定的路徑便可以是絕對路徑也能夠是相對路徑。好比當前路徑下有文件hello.c和include/testhead.h,則有兩種方法訪問這個頭文件:
   hello.c中#include "include/testhead.h"直接指定頭文件的路徑,而後能夠直接編譯不須要選項-I了,即gcc hello.c。
   hello.c中#include "testhead.h",在編譯時使用:gcc -I include hello.c或者gcc -I ./include hello.c,在編譯選項中指定頭文件的路徑。
另外選項-nostdinc使編譯器再也不繫統缺省的頭文件目錄裏面找頭文件,通常和-I聯合使用,明確限定頭文件的位置。
linux

兩種不類型的頭文件#include<>和#include""搜索規則
  1)使用<>包含的頭文件通常會先搜索-I選項後的路徑(即用gcc編譯時的-I選項,注意是大寫),以後就是標準的系統頭文件路徑。
  2)而用""號包含的頭文件會首先搜索當前的工做目錄,以後的搜索路徑纔是和<>號包含的頭文件所搜索的路徑同樣的路徑。
c++

頭文件搜索順序
  頭文件的搜索順序,能夠在編譯時使用選項-v查看編譯詳情裏會列出,好比使用gcc -v -I ./include hello.c相關部分以下:
git

      
  頭文件搜索順序是不會遞歸在目錄下搜索的,搜索順序規則以下(這裏是指<>類型頭文件搜索規則,由於」」類型頭文件首先搜索當前的工做目錄,以後的搜索路徑是和<>號包含的頭文件所搜索的路徑同樣):
  首先由參數-I指定的路徑(指定路徑有多個路徑時,按指定路徑的順序搜索)。
  而後找gcc的環境變量 C_INCLUDE_PATH(這個變量是搜索C語言的頭文件使用)和CPLUS_INCLUDE_PATH(針對C++的頭文件),設置環境變量的方法與一般是同樣的,好比在.bashrc或.profile中添加,好比:
github

  export C_INCLUDE_PATH="$HOME/github"

  最後找默認的目錄bash

  /usr/local/include
  libdir/gcc/target/version/include
  /usr/target/include
  /usr/include

 
 
 
對於C++程序,還會在libdir/../include/c++/version中查找這裏的target是指GCC的編譯配置的標準名字,version是GCC在用的版本。好比用gcc -v hello.cpp獲得的相關路徑查找信息是:   

動態庫相關選項  app

    假如咱們有兩個源文件,一個是dltest.c代碼以下:spa

  #include <stdio.h>
  void test_dl()
  {
      printf("Test DL\n");                                                                               
  }
另一個源文件代碼hello.c以下:

  void test_dl();
  int main(void)
  {
  test_dl();
  return 0;
  }

經過執行命令gcc -shared -fpic -o libdltest.so dltest.c來建立動態庫文件libdltest.so。這裏選項-shared告訴鏈接器源碼是生成一個共享庫,而不是可執行文件。選項-fpic參數聲明連接庫的代碼段是能夠共享的,使生成的對象模塊採用浮動的(可重定位的)地址,pic 表明「位置無關代碼」(position independent code)。請注意此次咱們編譯的共享庫的名字叫作libdltest.so,這也是Linux共享庫的一個命名的慣例了:後綴使用so,而名稱使用libxxxx格式。建立好共享庫後,就可使用命令gcc -L./ -ldltest hello.c來鏈接動態庫生成可執行文件。選項-L是把其後路徑加入到搜索庫文件的路徑列表中;選項-l指定搜索指定名的庫。注意使用的名字是dltest,而連接的是libdltest.so,這種方式是linux一般作法。.net

動態庫搜索路徑code

    動態庫搜索路徑分兩種狀況,一種是編譯生成可執行文件時,另一種是運行可執行文件時。編譯生成可執行文件時,動態庫的搜索路徑順序以下:
  首先gcc會找-L選項;
  而後再找gcc的環境變量LIBRARY_PATH,能夠在.profile設置這個環境變量,而且能夠經過選項-v查看gcc最終編譯時LIBRARY_PATH的值;
  再找內定目錄 /lib:/usr/lib: /usr/local/lib,這些都是當初compile gcc時寫在程序內的。
注意上面索順序是不會遞歸在目錄下搜索的。生成可執行文件後,運行文件時,動態庫的搜索路徑順序以下:
  首先編譯目標代碼時指定的動態庫搜索路徑,就是用選項-Wl,rpath指定程序在運行時動態庫的搜索路徑,好比gcc -Wl,-rpath,include -L. -ldltest hello.c,在執行文件時會搜索路徑./include;
  環境變量LD_LIBRARY_PATH指定的動態庫搜索路徑;
  配置文件/etc/ld.so.conf中指定的動態庫搜索路徑,即在配置文件中添加動態庫的絕對路徑,而後運行指令ldconfig是配置文件生效;
  默認的動態庫搜索路徑/lib;
  默認的動態庫搜索路徑/usr/lib。
一樣上面索順序是不會遞歸在目錄下搜索的。一般使用動態庫簡單作法是:把生成的so文件拷貝到/usr/lib中,這樣無論是生成能夠執行文件時,仍是執行程序時,都能找到須要的so文件。

參考資料

https://gcc.gnu.org/onlinedocs/cpp/Search-Path.html http://www.network-theory.co.uk/docs/gccintro/gccintro_23.html https://gcc.gnu.org/onlinedocs/gcc-4.9.1/cpp/Search-Path.html#Search-Path   https://erex.sinaapp.com/?p=126