1.////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
linux下c編程起步一:掌握gcc基本用法
初學(xué)時最好從命令行入手,這樣可以熟悉從編寫程序、編譯、調(diào)試和執(zhí)行的整個過程。編寫程序可以用vi或其它編輯器編寫。
編譯則使用gcc命令。要往下學(xué)習(xí)首先就得熟悉gcc命令的用法。
gcc命令提供了非常多的命令選項,但并不是所有都要熟悉,初學(xué)時掌握幾個常用的就可以了,到后面再慢慢學(xué)習(xí)其它選項,免得因選項太多而打擊了學(xué)習(xí)的信心。
一.常用編譯命令選項
假設(shè)源程序文件名為test.c。
1.無選項編譯鏈接
用法:#gcctest.c
作用:將test.c預(yù)處理、匯編、編譯并鏈接形成可執(zhí)行文件。這里未指定輸出文件,默認輸出為a.out。
2.選項-o
用法:#gcctest.c -o test
作用:將test.c預(yù)處理、匯編、編譯并鏈接形成可執(zhí)行文件test。-o選項用來指定輸出文件的文件名。
3.選項-E
用法:#gcc-E test.c -o test.i
作用:將test.c預(yù)處理輸出test.i文件。
4.選項-S
用法:#gcc-S test.i
作用:將預(yù)處理輸出文件test.i匯編成test.s文件。
5.選項-c
用法:#gcc-c test.s
作用:將匯編輸出文件test.s編譯輸出test.o文件。
6.無選項鏈接
用法:#gcctest.o -o test
作用:將編譯輸出文件test.o鏈接成最終可執(zhí)行文件test。
7.選項-O
用法:#gcc-O1 test.c -o test
作用:使用編譯優(yōu)化級別1編譯程序。級別為1~3,級別越大優(yōu)化效果越好,但編譯時間越長。
二.多源文件的編譯方法
如果有多個源文件,基本上有兩種編譯方法:
[假設(shè)有兩個源文件為test.c和testfun.c]
1.多個文件一起編譯
用法:#gcctestfun.c test.c -o test
作用:將testfun.c和test.c分別編譯后鏈接成test可執(zhí)行文件。
2.分別編譯各個源文件,之后對編譯后輸出的目標文件鏈接。
用法:
#gcc-c testfun.c //將testfun.c編譯成testfun.o
#gcc-c test.c //將test.c編譯成test.o
#gcc-o testfun.o test.o -o test //將testfun.o和test.o鏈接成test
以上兩種方法相比較,第一中方法編譯時需要所有文件重新編譯,而第二種方法可以只重新編譯修改的文件,未修改的文件不用重新編譯。
gcc編程環(huán)境基礎(chǔ)5--編譯時頭文件和庫文件路徑指定
※預(yù)處理(preprocessing),編譯(compilation),匯編(assembly)和連接(linking)
※include的header文件,連結(jié)數(shù)據(jù)庫,系統(tǒng)定義,總共有下列來源指定gcc去那找.
當初在編譯時指定的(在~gcc/gcc/collect2.c:locatelib()
寫在specs內(nèi)的
后來用-D-I -L指定的
gcc環(huán)境變量設(shè)定(編譯的時候)
ld.so的環(huán)境變量(這是runtime的時候)
=======================================
1
=======================================
1.頭文件
gcc在編譯時怎么去尋找所需要的頭文件:
※所以headerfile的搜尋會從-I開始
※然后找gcc的環(huán)境變量C_INCLUDE_PATH,CPLUS_INCLUDE_PATH,OBJC_INCLUDE_PATH
※再找內(nèi)定目錄
/usr/include
/usr/local/include
/usr/lib/gcc-lib/i386-linux/2.95.2/include
/usr/lib/gcc-lib/i386-linux/2.95.2/../../../../include/g++-3
/usr/lib/gcc-lib/i386-linux/2.95.2/../../../../i386-linux/include
庫文件不過如果裝gcc的時候,是有給定的prefix的話,那么就是
/usr/include
prefix/include
prefix/xxx-xxx-xxx-gnulibc/include
prefix/lib/gcc-lib/xxxx-xxx-xxx-gnulibc/2.8.1/include
2.庫文件
cos()等函式庫的選項要多加-lm
編譯的時候:
※gcc會去找-L
※再找gcc的環(huán)境變量LIBRARY_PATH
※再找內(nèi)定目錄/lib/usr/lib /usr/local/lib這是當初compilegcc時寫在程式內(nèi)的
=======================================
2
=======================================
2.利用Linux系統(tǒng)上已有的研發(fā)庫
(1).查看庫文件提供了哪些調(diào)用
能用nm命令自己查看庫文件提供了哪些調(diào)用
(2).通過頭文件查看函數(shù)的定義
=======================================
3
=======================================
3.gcc選項
總體選項(OverallOption) :(-c(生成目標但不連接)-S(匯編)-E(預(yù)處理) -ofile(生成指定的文件)-pipe-v(顯示過程) -xlanguage(設(shè)定文件所使用的語言,使后綴名無效`c’,可用參數(shù)`objective-c’,`c-header’, `c++’, `cpp-output’, `assembler’, and`assembler-with-cpp’))
語言選項(LANGUAGEOPTIONS) :(-ansi只支持ANSI標準的C語法.這一選項將禁止GNU C的某些特色)
預(yù)處理器選項(PreprocessorOption):(-Aassertion-C -dD -dM -dN -Dmacro[=defn] -E -H -idirafter dir -include file-imacros file -iprefix file -iwithprefix dir -M -MD -MM -MMD-nostdinc -P -Umacro相當于C語言中的#undefmacro -undef -DMACRO以字符串“1”定義MACRO宏, -DMACRO=DEFN以字符串“DEFN”定義MACRO宏)
匯編器選項(ASSEMBLEROPTION) :(-Wa,option)
連接器選項(LINKEROPTION) :(-llibrary-nostartfiles -nostdlib -static -shared -symbolic -Xlinker option-Wl,option -u symbol )
目錄選項(DIRECTORYOPTION) :(-Bprefix-Idir -I- -Ldir)
警告選項(WARNINGOPTION) :(-w不生成所有警告信息,-Wall生成所有警告信息)
調(diào)試選項(DEBUGGINGOPTION) :(-a-dletters -fpretend-float -g -glevel -gcoff -gxcoff -gxcoff+ -gdwarf-gdwarf+ -gstabs -gstabs+ -ggdb -p -pg -save-temps-print-file-name=library -print-libgcc-file-name-print-prog-name=program )
優(yōu)化選項(OPTIMIZATIONOPTION) :(-O0不進行優(yōu)化處理,-O或-O1優(yōu)化生成代碼-O2進一步優(yōu)化 -O3比-O2更進一步優(yōu)化,包括inline函數(shù))
目標機選項(TARGETOPTION) :(-bmachine -V version)
機器相關(guān)選項(MACHINEDEPENDENT OPTION):(-m486針對486進行代碼優(yōu)化)
代碼生成選項(CODEGENERATION OPTION) :(-fpic-fPIC)
2.//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////GCC選項
GCC有超過100個的編譯選項可用.這些選項中的許多你可能永遠都不會用到,但一些主要的選項將會頻繁用到.很多的GCC選項包括一個以上的字符.因此你必須為每個選項指定各自的連字符,并且就象大多數(shù)Linux命令一樣你不能在一個單獨的連字符后跟一組選項.例如,下面的兩個命令是不同的:
gcc -p -g test.c
gcc -pg test.c
第一條命令告訴GCC編譯test.c時為prof命令建立剖析(profile)信息并且把調(diào)試信息加入到可執(zhí)行的文件里.第二條命令只告訴GCC為gprof命令建立剖析信息.
當你不用任何選項編譯一個程序時,GCC將會建立(假定編譯成功)一個名為a.out的可執(zhí)行文件.例如,下面的命令將在當前目錄下產(chǎn)生一個叫a.out的文件:
gcc test.c
你能用-o編譯選項來為將產(chǎn)生的可執(zhí)行文件指定一個文件名來代替a.out.例如,將一個叫count.c的C程序編譯為名叫count的可執(zhí)行文件,你將輸入下面的命令:
gcc -o count count.c
注意:當你使用-o選項時,-o后面必須跟一個文件名.
-c只編譯并生成目標文件。
--------------------------------------------------------------------------------
gcc and g++分別是gnu的c& c++編譯器gcc/g++在執(zhí)行編譯工作的時候,總共需要4步
1.預(yù)處理,生成.i的文件[預(yù)處理器cpp]
2.將預(yù)處理后的文件不轉(zhuǎn)換成匯編語言,生成文件.s[編譯器egcs]
3.有匯編變?yōu)槟繕舜a(機器代碼)生成.o的文件[匯編器as]
4.連接目標代碼,生成可執(zhí)行程序[鏈接器ld]
[參數(shù)詳解]
-x language filename
設(shè)定文件所使用的語言,使后綴名無效,對以后的多個有效.也就是根據(jù)約定C語言的后
綴名稱是.c的,而C++的后綴名是.C或者.cpp,如果你很個性,決定你的C代碼文件的后綴
名是.pig哈哈,那你就要用這個參數(shù),這個參數(shù)對他后面的文件名都起作用,除非到了
下一個參數(shù)的使用。
可以使用的參數(shù)嗎有下面的這些
`c',`objective-c', `c-header', `c++', `cpp-output', `assembler', and `a
ssembler-with-cpp'.
看到英文,應(yīng)該可以理解的。
例子用法:
gcc-x c hello.pig
-xnone filename
關(guān)掉上一個選項,也就是讓gcc根據(jù)文件名后綴,自動識別文件類型
例子用法:
gcc-x c hello.pig -x none hello2.c
-c
只激活預(yù)處理,編譯,和匯編,也就是他只把程序做成obj文件
例子用法:
gcc-c hello.c
他將生成.o的obj文件
-S
只激活預(yù)處理和編譯,就是指把文件編譯成為匯編代碼。
例子用法
gcc-S hello.c
他將生成.s的匯編代碼,你可以用文本編輯器察看
-E
只激活預(yù)處理,這個不生成文件,你需要把它重定向到一個輸出文件里面.
例子用法:
gcc-E hello.c > pianoapan.txt
gcc-E hello.c | more
慢慢看吧,一個helloword也要與處理成800行的代碼
-o
制定目標名稱,缺省的時候,gcc編譯出來的文件是a.out,很難聽,如果你和我有同感
,改掉它,哈哈
例子用法
gcc-o hello.exe hello.c (哦,windows用習(xí)慣了)
gcc-o hello.asm -S hello.c
-pipe
使用管道代替編譯中臨時文件,在使用非gnu匯編工具的時候,可能有些問題
gcc-pipe -o hello.exe hello.c
-ansi
關(guān)閉gnuc中與ansic不兼容的特性,激活ansic的專有特性(包括禁止一些asminl
ine typeof關(guān)鍵字,以及UNIX,vax等預(yù)處理宏,
-fno-asm
此選項實現(xiàn)ansi選項的功能的一部分,它禁止將asm,inline和typeof用作關(guān)鍵字。
-fno-strict-prototype
只對g++起作用,使用這個選項,g++將對不帶參數(shù)的函數(shù),都認為是沒有顯式的對參數(shù)
的個數(shù)和類型說明,而不是沒有參數(shù).
而gcc無論是否使用這個參數(shù),都將對沒有帶參數(shù)的函數(shù),認為城沒有顯式說明的類型
-fthis-is-varialble
就是向傳統(tǒng)c++看齊,可以使用this當一般變量使用.
-fcond-mismatch
允許條件表達式的第二和第三參數(shù)類型不匹配,表達式的值將為void類型
-funsigned-char
-fno-signed-char
-fsigned-char
-fno-unsigned-char
這四個參數(shù)是對char類型進行設(shè)置,決定將char類型設(shè)置成unsignedchar(前兩個參
數(shù))或者signedchar(后兩個參數(shù))
-includefile
包含某個代碼,簡單來說,就是便以某個文件,需要另一個文件的時候,就可以用它設(shè)
定,功能就相當于在代碼中使用#include<filename>
例子用法:
gcchello.c -include /root/pianopan.h
-imacrosfile
將file文件的宏,擴展到gcc/g++的輸入文件,宏定義本身并不出現(xiàn)在輸入文件中
-Dmacro
相當于C語言中的#definemacro
-Dmacro=defn
相當于C語言中的#definemacro=defn
-Umacro
相當于C語言中的#undefmacro
-undef
取消對任何非標準宏的定義
-Idir
在你是用#include"file"的時候,gcc/g++會先在當前目錄查找你所制定的頭文件,如
果沒有找到,他回到缺省的頭文件目錄找,如果使用-I制定了目錄,他
回先在你所制定的目錄查找,然后再按常規(guī)的順序去找.
對于#include<file>,gcc/g++會到-I制定的目錄查找,查找不到,然后將到系統(tǒng)的缺
省的頭文件目錄查找
-I-
就是取消前一個參數(shù)的功能,所以一般在-Idir之后使用
-idirafterdir
在-I的目錄里面查找失敗,講到這個目錄里面查找.
-iprefixprefix
-iwithprefix dir
一般一起使用,當-I的目錄查找失敗,會到prefix+dir下查找
-nostdinc
使編譯器不再系統(tǒng)缺省的頭文件目錄里面找頭文件,一般和-I聯(lián)合使用,明確限定頭
文件的位置
-nostdinC++
規(guī)定不在g++指定的標準路經(jīng)中搜索,但仍在其他路徑中搜索,.此選項在創(chuàng)libg++庫
使用
-C
在預(yù)處理的時候,不刪除注釋信息,一般和-E使用,有時候分析程序,用這個很方便的
-M
生成文件關(guān)聯(lián)的信息。包含目標文件所依賴的所有源代碼你可以用gcc-M hello.c
來測試一下,很簡單。
-MM
和上面的那個一樣,但是它將忽略由#include<file>造成的依賴關(guān)系。
-MD
和-M相同,但是輸出將導(dǎo)入到.d的文件里面
-MMD
和-MM相同,但是輸出將導(dǎo)入到.d的文件里面
-Wa,option
此選項傳遞option給匯編程序;如果option中間有逗號,就將option分成多個選項,然
后傳遞給會匯編程序
-Wl.option
此選項傳遞option給連接程序;如果option中間有逗號,就將option分成多個選項,然
后傳遞給會連接程序.
-llibrary
制定編譯的時候使用的庫
例子用法
gcc-lcurses hello.c
使用ncurses庫編譯程序
-Ldir
制定編譯的時候,搜索庫的路徑。比如你自己的庫,可以用它制定目錄,不然
編譯器將只在標準庫的目錄找。這個dir就是目錄的名稱。
-O0
-O1
-O2
-O3
編譯器的優(yōu)化選項的4個級別,-O0表示沒有優(yōu)化,-O1為缺省值,-O3優(yōu)化級別最高
-g
只是編譯器,在編譯的時候,產(chǎn)生調(diào)試信息。
-gstabs
此選項以stabs格式聲稱調(diào)試信息,但是不包括gdb調(diào)試信息.
-gstabs+
此選項以stabs格式聲稱調(diào)試信息,并且包含僅供gdb使用的額外調(diào)試信息.
-ggdb
此選項將盡可能的生成gdb的可以使用的調(diào)試信息.
-static
此選項將禁止使用動態(tài)庫,所以,編譯出來的東西,一般都很大,也不需要什么
動態(tài)連接庫,就可以運行.
-share
此選項將盡量使用動態(tài)庫,所以生成文件比較小,但是需要系統(tǒng)由動態(tài)庫.
-traditional
試圖讓編譯器支持傳統(tǒng)的C語言特性
[參考資料]
-Linux/UNIX高級編程
中科紅旗軟件技術(shù)有限公司編著.清華大學(xué)出版社出版
-Gccman page
[ChangeLog]
-2002-08-10
ver0.1發(fā)布最初的文檔
-2002-08-11
ver0.11修改文檔格式
-2002-08-12
ver0.12加入了對靜態(tài)庫,動態(tài)庫的參數(shù)
-2002-08-16
ver0.16增加了gcc編譯的4個階段的命令
運行gcc/egcs
**********運行gcc/egcs***********************
GCC是GNU的C和C++編譯器。實際上,GCC能夠編譯三種語言:C、C++和O
bject C(C語言的一種面向?qū)ο髷U展)。利用gcc命令可同時編譯并連接C和C++
源程序。
如果你有兩個或少數(shù)幾個C源文件,也可以方便地利用GCC編譯、連接并生成可
執(zhí)行文件。例如,假設(shè)你有兩個源文件main.c和factorial.c兩個源文件,現(xiàn)在要編
譯生成一個計算階乘的程序。
代碼:
-----------------------
清單factorial.c
-----------------------
int factorial (int n)
{
if(n <= 1)
return1;
else
returnfactorial (n - 1) * n;
}
-----------------------
清單main.c
-----------------------
#include <stdio.h>
#include <unistd.h>
int factorial (int n);
int main (int argc, char **argv)
{
intn;
if(argc < 2)
{
printf("Usage: %s n\n", argv [0]);
return-1;
}
else
{
n= atoi (argv[1]);
printf("Factorial of %d is %d.\n", n, factorial (n));
}
return0;
}
-----------------------
利用如下的命令可編譯生成可執(zhí)行文件,并執(zhí)行程序:
$gcc -o factorial main.c factorial.c
$ ./factorial 5
Factorialof 5 is 120.
GCC可同時用來編譯C程序和C++程序。一般來說,C編譯器通過源文件的后綴
名來判斷是C程序還是C++程序。在Linux中,C源文件的后綴名為.c,而C++源
文件的后綴名為.C或.cpp。但是,gcc命令只能編譯C++源文件,而不能自動和C
++ 程序使用的庫連接。因此,通常使用g++命令來完成C++程序的編譯和連接,該程
序會自動調(diào)用gcc實現(xiàn)編譯。假設(shè)我們有一個如下的C++源文件(hello.C):
#include<iostream>
void main (void)
{
cout<< "Hello, world!" << endl;
}
則可以如下調(diào)用g++命令編譯、連接并生成可執(zhí)行文件:
$g++ -o hello hello.C
$ ./hello
Hello, world!
**********************gcc/egcs 的主要選項*********
gcc 命令的常用選項
選項解釋
-ansi只支持ANSI標準的C語法。這一選項將禁止GNUC的某些特色,
例如asm或typeof關(guān)鍵詞。
-c只編譯并生成目標文件。
-DMACRO以字符串“1”定義MACRO宏。
-DMACRO=DEFN以字符串“DEFN”定義MACRO宏。
-E只運行C預(yù)編譯器。
-g生成調(diào)試信息。GNU調(diào)試器可利用該信息。
-IDIRECTORY指定額外的頭文件搜索路徑DIRECTORY。
-LDIRECTORY指定額外的函數(shù)庫搜索路徑DIRECTORY。
-lLIBRARY連接時搜索指定的函數(shù)庫LIBRARY。
-m486針對486進行代碼優(yōu)化。
-oFILE 生成指定的輸出文件。用在生成可執(zhí)行文件時。
-O0不進行優(yōu)化處理。
-O或-O1優(yōu)化生成代碼。
-O2進一步優(yōu)化。
-O3比-O2更進一步優(yōu)化,包括inline函數(shù)。
-shared生成共享目標文件。通常用在建立共享庫時。
-static禁止使用共享連接。
-UMACRO取消對MACRO宏的定義。
-w不生成任何警告信息。
-Wall生成所有警告信息。
3./////////////////////////////////////////////////動態(tài)靜態(tài)庫制作////////////////////////////////////////////////////////////////
我們通常把一些公用函數(shù)制作成函數(shù)庫,供其它程序使用。函數(shù)庫分為靜態(tài)庫和動態(tài)庫兩種。靜態(tài)庫在程序編譯時會被連接到目標代碼中,程序運行時將不再需要該靜態(tài)庫。動態(tài)庫在程序編譯時并不會被連接到目標代碼中,而是在程序運行是才被載入,因此在程序運行時還需要動態(tài)庫存在。本文主要通過舉例來說明在Linux中如何創(chuàng)建靜態(tài)庫和動態(tài)庫,以及使用它們。
在創(chuàng)建函數(shù)庫前,我們先來準備舉例用的源程序,并將函數(shù)庫的源程序編譯成.o文件。
第1步:編輯得到舉例的程序--hello.h、hello.c和main.c;
hello.c(見程序2)是函數(shù)庫的源程序,其中包含公用函數(shù)hello,該函數(shù)將在屏幕上輸出"HelloXXX!"。hello.h(見程序1)為該函數(shù)庫的頭文件。main.c(見程序3)為測試庫文件的主程序,在主程序中調(diào)用了公用函數(shù)hello。
#ifndefHELLO_H
#defineHELLO_H
voidhello(const char *name);
#endif//HELLO_H
程序1:hello.h
#include
voidhello(const char *name)
{
printf("Hello %s!\n", name);
}
程序2:hello.c
#include"hello.h"
intmain()
{
hello("everyone");
return 0;
}
程序3:main.c
第2步:將hello.c編譯成.o文件;
無論靜態(tài)庫,還是動態(tài)庫,都是由.o文件創(chuàng)建的。因此,我們必須將源程序hello.c通過gcc先編譯成.o文件。
在系統(tǒng)提示符下鍵入以下命令得到hello.o文件。
#gcc -c hello.c
#
(注1:本文不介紹各命令使用和其參數(shù)功能,若希望詳細了解它們,請參考其他文檔。)
(注2:首字符"#"是系統(tǒng)提示符,不需要鍵入,下文相同。)
我們運行ls命令看看是否生存了hello.o文件。
#ls
hello.chello.h hello.o main.c
#
(注3:首字符不是"#"為系統(tǒng)運行結(jié)果,下文相同。)
在ls命令結(jié)果中,我們看到了hello.o文件,本步操作完成。
下面我們先來看看如何創(chuàng)建靜態(tài)庫,以及使用它。
第3步:由.o文件創(chuàng)建靜態(tài)庫;
靜態(tài)庫文件名的命名規(guī)范是以lib為前綴,緊接著跟靜態(tài)庫名,擴展名為.a。例如:我們將創(chuàng)建的靜態(tài)庫名為myhello,則靜態(tài)庫文件名就是libmyhello.a。在創(chuàng)建和使用靜態(tài)庫時,需要注意這點。創(chuàng)建靜態(tài)庫用ar命令。
在系統(tǒng)提示符下鍵入以下命令將創(chuàng)建靜態(tài)庫文件libmyhello.a。
#ar cr libmyhello.a hello.o
#
我們同樣運行ls命令查看結(jié)果:
#ls
hello.chello.h hello.o libmyhello.a main.c
|
#
ls命令結(jié)果中有libmyhello.a。
第4步:在程序中使用靜態(tài)庫;
靜態(tài)庫制作完了,如何使用它內(nèi)部的函數(shù)呢?只需要在使用到這些公用函數(shù)的源程序中包含這些公用函數(shù)的原型聲明,然后在用gcc命令生成目標文件時指明靜態(tài)庫名,gcc將會從靜態(tài)庫中將公用函數(shù)連接到目標文件中。注意,gcc會在靜態(tài)庫名前加上前綴lib,然后追加擴展名.a得到的靜態(tài)庫文件名來查找靜態(tài)庫文件。
在程序3:main.c中,我們包含了靜態(tài)庫的頭文件hello.h,然后在主程序main中直接調(diào)用公用函數(shù)hello。下面先生成目標程序hello,然后運行hello程序看看結(jié)果如何。
#gcc -o hello main.c -L. -lmyhello
#./hello
Helloeveryone!
#
我們刪除靜態(tài)庫文件試試公用函數(shù)hello是否真的連接到目標文件hello中了。
#rm libmyhello.a
rm:remove regular file `libmyhello.a'? y
#./hello
Helloeveryone!
#
程序照常運行,靜態(tài)庫中的公用函數(shù)已經(jīng)連接到目標文件中了。
我們繼續(xù)看看如何在Linux中創(chuàng)建動態(tài)庫。我們還是從.o文件開始。
第5步:由.o文件創(chuàng)建動態(tài)庫文件;
動態(tài)庫文件名命名規(guī)范和靜態(tài)庫文件名命名規(guī)范類似,也是在動態(tài)庫名增加前綴lib,但其文件擴展名為.so。例如:我們將創(chuàng)建的動態(tài)庫名為myhello,則動態(tài)庫文件名就是libmyhello.so。用gcc來創(chuàng)建動態(tài)庫。
在系統(tǒng)提示符下鍵入以下命令得到動態(tài)庫文件libmyhello.so。
#gcc -shared -fPCI -o libmyhello.so hello.o
#
我們照樣使用ls命令看看動態(tài)庫文件是否生成。
#ls
hello.chello.h hello.o libmyhello.so main.c
#
第6步:在程序中使用動態(tài)庫;
在程序中使用動態(tài)庫和使用靜態(tài)庫完全一樣,也是在使用到這些公用函數(shù)的源程序中包含這些公用函數(shù)的原型聲明,然后在用gcc命令生成目標文件時指明動態(tài)庫名進行編譯。我們先運行gcc命令生成目標文件,再運行它看看結(jié)果。
#gcc -o hello main.c -L. -lmyhello
#./hello
./hello:error while loading shared libraries: libmyhello.so: cannot openshared object file: No such file or directory
#
哦!出錯了。快看看錯誤提示,原來是找不到動態(tài)庫文件libmyhello.so。程序在運行時,會在/usr/lib和/lib等目錄中查找需要的動態(tài)庫文件。若找到,則載入動態(tài)庫,否則將提示類似上述錯誤而終止程序運行。我們將文件libmyhello.so復(fù)制到目錄/usr/lib中,再試試?;蛘咴O(shè)置環(huán)境變量LD_LIBRARY_PATH到動態(tài)庫所在目錄
#mv libmyhello.so /usr/lib
#./hello
Helloeveryone!
#
成功了。這也進一步說明了動態(tài)庫在程序運行時是需要的。
我們回過頭看看,發(fā)現(xiàn)使用靜態(tài)庫和使用動態(tài)庫編譯成目標程序使用的gcc命令完全一樣,那當靜態(tài)庫和動態(tài)庫同名時,gcc命令會使用哪個庫文件呢?抱著對問題必究到底的心情,來試試看。
先刪除除.c和.h外的所有文件,恢復(fù)成我們剛剛編輯完舉例程序狀態(tài)。
#rm -f hello hello.o /usr/lib/libmyhello.so
#ls
hello.chello.h main.c
#
在來創(chuàng)建靜態(tài)庫文件libmyhello.a和動態(tài)庫文件libmyhello.so。
#gcc -c hello.c
#ar cr libmyhello.a hello.o
#gcc -shared -fPCI -o libmyhello.so hello.o
#ls
hello.chello.h hello.o libmyhello.a libmyhello.so main.c |
#
通過上述最后一條ls命令,可以發(fā)現(xiàn)靜態(tài)庫文件libmyhello.a和動態(tài)庫文件libmyhello.so都已經(jīng)生成,并都在當前目錄中。然后,我們運行gcc命令來使用函數(shù)庫myhello生成目標文件hello,并運行程序hello。
#gcc -o hello main.c -L. -lmyhello
#./hello
./hello:error while loading shared libraries: libmyhello.so: cannot openshared object file: No such file or directory
#
從程序hello運行的結(jié)果中很容易知道,當靜態(tài)庫和動態(tài)庫同名時,gcc命令將優(yōu)先使用動態(tài)庫。
4.///////////////////////////////////////////////////////////////////////動態(tài)庫編寫
C語言中有一些函數(shù)不需要進行編譯,有一些函數(shù)也可以在多個文件中使用。一般來說,這些函數(shù)都會執(zhí)行一些標準任務(wù),如數(shù)據(jù)庫輸入/輸出操作或屏幕控制等??梢允孪葘@些函數(shù)進行編譯,然后將它們放置在一些特殊的目標代碼文件中,這些目標代碼文件就稱為庫。庫文件中的函數(shù)可以通過連接程序與應(yīng)用程序進行連接。這樣就不必在每次開發(fā)程序時都對這些通用的函數(shù)進行編譯了。
不同類型的應(yīng)用程序?qū)褂貌煌暮瘮?shù)庫。例如:libdbm庫中組包含了對數(shù)據(jù)庫文件進行訪問的dbm函數(shù),需要對數(shù)據(jù)庫進行操作的程序就會與該庫進行連接。數(shù)學(xué)應(yīng)用程序?qū)⑹褂脭?shù)學(xué)庫libm,X-Windows應(yīng)用程序?qū)⑹褂?/SPAN>Xlib庫,libX11。另外,所有的程序都將使用標準的C函數(shù)庫。libc,該庫中包含了諸好內(nèi)存管理或輸入輸出操作的基本函數(shù),這些庫都存放在/usr/lib這些系統(tǒng)公用的目錄中,系統(tǒng)中的任何用戶都可以利用這些庫。當然用戶也可以建立自己專用的庫函數(shù),供自己或其它指定的人員使用。
庫可以有三種使用的形式:靜態(tài)、共享和動態(tài)。靜態(tài)庫的代碼在編譯時就已連接到開發(fā)人員開發(fā)的應(yīng)用程序中,而共享庫只是在程序開始運行時才載入,在編譯時,只是簡單地指定需要使用的庫函數(shù)。動態(tài)庫則是共享庫的另一種變化形式。動態(tài)庫也是在程序運行時載入,但與共享庫不同的是,使用的庫函數(shù)不是在程序運行開始,而是在程序中的語句需要使用該函數(shù)時才載入。動態(tài)庫可以在程序運行期間釋放動態(tài)庫所占用的內(nèi)存,騰出空間供其它程序使用。由于共享庫和動態(tài)庫并沒有在程序中包括庫函數(shù)的內(nèi)容,只是包含了對庫函數(shù)的引用,因此代碼的規(guī)模比較小。
已經(jīng)開發(fā)的大多數(shù)庫都采取共享庫的方式。ELF格式的可執(zhí)行文件使得共享庫能夠比較容易地實現(xiàn),當然使用舊的a.out模式也可以實現(xiàn)庫的共享。Linux系統(tǒng)中目前可執(zhí)行文件的標準格式為ELF格式。
GNU庫的使用必須遵守LibraryGNU PublicLicense(LGPL許可協(xié)議)。該協(xié)議與GNU許可協(xié)議略有不同,開發(fā)人員可以免費使用GNU庫進行軟件開發(fā),但必須保證向用戶提供所用的庫函數(shù)的源代碼。
系統(tǒng)中可用的庫都存放在/usr/lib和/lib目錄中。庫文件名由前綴lib和庫名以及后綴組成。根據(jù)庫的類型不同,后綴名也不一樣。共享庫的后綴名由.so和版本號組成,靜態(tài)庫的后綴名為.a。采用舊的a.out格式的共享庫的后綴名為.sa。
libname.so.major.minor
libname.a
這里的name可以是任何字符串,用來唯一標識某個庫。該字符串可以是一個單字、幾個字符、甚至一個字母。數(shù)學(xué)共享庫的庫名為libm.so.5,這里的標識字符為m,版本號為5。libm.a則是靜態(tài)數(shù)學(xué)庫。X-Windows庫名為libX11.so.6,這里使用X11作為庫的標識,版本號為6。
使用gcc編譯器就可以將庫與自己開發(fā)的程序連接起來,例如:libc.so.5中包含了標準的輸入輸出函數(shù),當連接程序進行目標代碼連接時會自動搜索該程序并將其連接到生成的可執(zhí)行文件中。標準的輸入輸出庫中包含了許多基本的輸入輸出函數(shù),如printf函數(shù)等。也可以連接其它的一些系統(tǒng)函數(shù)庫,如數(shù)學(xué)庫等,但與libc.so.5不同,大部分其它的系統(tǒng)庫需要在命令行中顯式指定所用的庫名。
在/usr/lib和/lib目錄中可以找到絕大多數(shù)的共享庫。連接時將首先搜索這兩個目錄。有一些庫也可能存放在特定的目錄中,在/etc/ld.conf配置文件中給出了這些目錄的列表。連接程序也會對列出的這些目錄進行搜索。在默認情況下,Linux將首先搜索指定庫的共享版本,如果找不到,才會去搜索靜態(tài)版本。在對共享庫進行更新或安裝新庫后,必須運行ldconfig命令更新/etc/ld.conf文件中相應(yīng)的項(如果使用RPM進行安裝,一般會自動進行更新,不過也不能保證這一點)。
在gcc編譯器中引用可搜索到的目錄中的庫文件時,需要使用-l選項和庫名。在gcc命令行上輸入-lm可以在程序中連接標準算術(shù)庫,-l將首先使用libname.so進行搜索,這里是libm.so。下面的例子將使用算術(shù)庫創(chuàng)建bookrecs程序,請注意這里的-lm選項。
$gccmain.c io.c -o bookrecs -lm
系統(tǒng)中還有一些其它可用的庫,常用的是libncurses.a庫,包含了一些簡單的鼠標移動例程。在命令行中使用-lncurses選項引用libncurses.so庫。下面的例子同時調(diào)用了數(shù)學(xué)和光標庫。
$gccmian.c io.c -o bookrecs -lm -lncurses
在引用其它目錄中的庫時,需要使用-ldir選項指定該目錄。該選項指定了搜索庫函數(shù)時其它路徑。在下面的例子中,用戶在連接時使用了mydir目錄中的myio.so庫文件。
$gccmain.c -o bookrecs -lmydir -lmyio
.a的是為了支持較老的a.out格式的可執(zhí)行文件的
.so的是支持elf格式的可執(zhí)行文件的庫。
靜態(tài)庫是指編譯連接時,把庫文件的代碼全部加入到可執(zhí)行文件中,所以生成的文件較大,但運行時,就不再需要庫文件了。動態(tài)庫正好相反,在編譯連接時,沒有把庫文件的代碼加入到可執(zhí)行文件中,所以生成的文件較小,但運行時,仍需要加載庫文件
.a是靜態(tài)庫文件,可以用ar命令生成。
.so是動態(tài)庫文件,編譯時加上指定的選項即可生成,具體選項看相應(yīng)的系統(tǒng)文檔了。。。。
IBMAIX下如下:
$(CC)$(SHOPT)$(SHLIBS)a.o b.o -o lib$@$(DBBUILDTAIL)
假設(shè)你有test1.ctest2.c test3.c ,編寫成動態(tài)鏈接庫
1.先編譯成test1.otest2.o test3.o
2.gcc -shared -W1, -soname,libvTest.so.1 -o libvTest.so.1.0*.o
二、正確編譯與命名動態(tài)鏈接庫: g++ -shared -fPIC -Wall -o libMy.so getdate.cc gettime.cc
########### Makefile ############
obj = libmy.so
CC = g++
all : $(obj)
SRC = getdate.cc gettime.cc
TGT = $(SRC:.cc=.o)
$(SRC) : adatetime.h
@touch $@
%.o : %.c
$(CC) -c $?
$(obj) : $(TGT)
$(CC) -shared -fPIC -Wall -o $@ $(TGT)
gcc -shared -fPIC -o libjcmpp.so JCMPP.c libtssx_cmpp.a -I. -I/opt/jdk142/include/ -I/opt/jdk142/include/linux