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