1. 爲何會出現undefined reference to 'xxxxx'錯誤?html
首先這是連接錯誤,不是編譯錯誤,也就是說若是隻有這個錯誤,說明你的程序源碼本身沒有問題,是你用編譯器編譯時參數用得不對,你沒有指定連接程序要用到得庫,好比你的程序裏用到了一些數學函數,那麼你就要在編譯參數裏指定程序要連接數學庫,方法是在編譯命令行里加入-lm。數據庫
2.-l參數和-L參數編程
-l參數就是用來指定程序要連接的庫,-l參數緊接着就是庫名,那麼庫名跟真正的庫文件名有什麼關係呢?就拿數學庫來講,他的庫名是m,他的庫文件名是libm.so,很容易看出,把庫文件名的頭lib和尾.so去掉就是庫名了。編程語言
-L參數跟着的是庫文件所在的目錄名。再好比咱們把libtest.so放在/aaa/bbb/ccc目錄下,那連接參數就是-L/aaa/bbb/ccc -ltest另外,大部分libxxxx.so只是一個連接函數
3. -include和-I參數測試
-include用來包含頭文件,但通常狀況下包含頭文件都在源碼裏用#include xxxxxx實現,-include參數不多用。-I參數是用來指定頭文件目錄,/usr/include目錄通常是不用指定的,gcc知道去那裏找,可是若是頭文件不在/usr/include裏咱們就要用-I參數指定了,好比頭文件放在/myinclude目錄裏,那編譯命令行就要加上-I/myinclude參數了,若是不加你會獲得一個"xxxx.h: No such file or directory"的錯誤。-I參數能夠用相對路徑,好比頭文件在當前目錄,能夠用-I.來指定ui
4.幾個相關的環境變量spa
PKG_CONFIG_PATH:用來指定pkg-config用到的pc文件的路徑,默認是 /usr/lib/pkgconfig,pc文件是文本文件,擴展名是.pc,裏面定義開發包的安裝路徑,Libs參數和Cflags參數等等。.net
CC:用來指定c編譯器。命令行
CXX:用來指定cxx編譯器。
LIBS:跟上面的--libs做用差很少。
CFLAGS:跟上面的--cflags做用差很少。
CC,CXX,LIBS,CFLAGS手動編譯時通常用不上,在作configure時有時用到,通常狀況下不用管。
環境變量設定方法:export ENV_NAME=xxxxxxxxxxxxxxxxx
==============================================================================
[相關介紹]
應用程序(Applications)
應用程序一般都有固定的文件夾,系統通用程序放在/usr/bin,往後系統管理 員在本地計算機安裝的程序一般放在/usr/local/bin或者/opt文件夾下。除了系統程序外,大部分我的用到的程序都放在/usr /local下,因此保持/usr的整潔十分重要。當升級或者重裝系統的時候,只要把/usr/local的程序備份一下就能夠了。
一些其餘的程序有本身特定的文件夾,好比X Window系統,一般安裝在/usr/X11中,或者/usr/X11R6。GNU的編譯器GCC,一般放置在/usr/bin或者/usr/local/bin中,不一樣的Linux版本可能位置稍有不一樣。
頭文件(Head Files)
在C語言和其餘語言中,頭文件聲明瞭系統函數和庫函數,而且定義了一些常量。對於 C語言,頭文件基本上散落於/usr/include和它的子文件夾下。其餘的編程語言的庫函數分佈在編譯器定義的地方,好比在一些Linux版本中,X Window系統庫函數分佈在/usr/include/X11,GNU C++的庫函數分佈在/usr/include/g++。這些系統庫函數的位置對於編譯器來講都是「標準位置」,即編譯器可以自動搜尋這些位置。
若是想引用位於標準位置以外的頭文件,咱們須要在調用編譯器的時候加上-I標誌,來顯式的說明頭文件所在文件夾。好比,
$ gcc -I/usr/openwin/include hello.c會告訴編譯器除了標準位置外,還要去/usr/openwin/include看看有沒有所需的頭文件。詳細狀況見編譯器的使用手冊(man gcc)。
庫函數(Library Files)
庫函數就是函數的倉庫,它們都通過編譯,重用性不錯。一般,庫函數相互合做,來完成特定的任務。好比操控屏幕的庫函數(cursers和ncursers庫函數),數據庫讀取庫函數(dbm庫函數)等。
系統調用的標準庫函數通常位於/lib以及/usr/lib。C編譯器(精確點說,鏈接器)須要知道庫函數的位置。默認狀況下,它只搜索標準C庫函數。
庫函數文件一般開頭字母是lib。後面的部分標示庫函數的用途(好比C庫函數用c標識, 數學庫函數用m標示),小數點後的後綴代表庫函數的類型:
去/usr/lib看一下,你會發現,庫函數都有動態和靜態兩個版本。
與頭文件同樣,庫函數一般放在標準位置,但咱們也能夠經過-L標識符,來添加新的搜索文件夾,-l指定特定的庫函數文件。好比
$ gcc -o x11fred -L/usr/openwin/lib x11fred.c -lX11
上述命令就會在編譯期間,連接位於/usr/openwin/lib文件夾下的libX11函數庫,編譯生成x11fred。
靜態連接庫(Static Libraries)
最簡單的函數庫就是一些函數的簡單集合。調用庫函數中的函數時,須要在調用函數中include定義庫函數的頭文件。咱們用-l選項添加標準函數庫以外的函數庫。
靜態函數庫,也稱爲archives ,一般之後綴.a結尾。
咱們也能夠建立維護本身的靜態連接庫函數。下面就介紹一下:
咱們建立的庫函數包括兩個函數,而後在後面的實例中調用其中之一。兩個庫函數名字分別是fred和bill,僅僅是輸出字符串。
2. 接下來,咱們將這兩個源文件編譯爲兩個獨立的目標文件。這裏要用到GCC的-c選項。命令以下所示:
$ gcc -c fred.c bill.c
$ ls *.o
bill.o fred.o
3. 而後,寫一個調用bill的測試函數,在此以前,最好爲庫函數創建一個頭文件。頭文件中有對庫函數的聲明。若是其餘函數要調用庫函數,必須在其代碼中包含 頭文件。也能夠在fred.c 和bill.c中包含該頭文件,有利於編譯器發現錯誤。頭文件lib.h的內容以下所示:
4. 測試函數program.c比較簡單,代碼以下:
5. 如今咱們能夠編譯測試一下程序了:
$ gcc -c program.c
$ gcc -o program program.o bill.o
$ ./program
bill: we passed Hello World
6. 接下來,咱們要建立一個函數庫。利用ar函數創建歸檔文件(archive),而後將目標文件加入其中。$ ar crv libfoo.a bill.o fred.o
a - bill.o
a - fred.o
7. 如今可使用函數庫中的函數了。咱們用-l指定函數庫的名字。由於該函數庫沒有在標準文件夾中,咱們還須要用-L將當前文件夾"."添加到搜索路徑中。編譯命令以下所示:
$ gcc -o program program.o -L. -lfoo
共享連接庫(Shared Libraries)
靜態連接庫的一個缺點是,若是咱們同時運行了許多程序,而且它們使用了同一個庫函數,這樣,在內存中會大量拷貝同一庫函數。這樣,就會浪費不少珍貴的內存和存儲空間。使用了共享連接庫的Linux就能夠避免這個問題。
共享函數庫和靜態函數在同一個地方,只是後綴有所不一樣。好比,在一個典型的Linux系統,標準的共享數序函數庫是/usr/lib/libm.so。
當一個程序使用共享函數庫時,在鏈接階段並不把函數代碼鏈接進來,而只是連接函數的一個引用。當最終的函數導入內存開始真正執行時,函數引用被解 析,共享函數庫的代碼才真正導入到內存中。這樣,共享連接庫的函數就能夠被許多程序同時共享,而且只需存儲一次就能夠了。共享函數庫的另外一個優勢是,它可 以獨立更新,與調用它的函數絕不影響。
原文出處:http://blog.chinaunix.net/uid-26959037-id-3542739.html