語言編譯器了。如今,它已支持了許多不同的語言,包括
C、C++、Ada、Fortran、Objective C,甚至還有Java。事實上,現代 Linux
系統除了可以自豪地炫耀那些由 GNU
工具直接支持的語言以外,它還支持大量其他語言。日益流行的腳本語言
Perl、Python 和 Ruby,以及正在不斷發展的mono
可移植C#實現的確有助于沖淡人們對 Linux
編程的傳統看法,但這完全是另外一個問題了。
Linux 內核和許多其他自由軟件以及開放源碼應用程序都是用 C 語言編寫并使用
GCC 編譯的。
1. 編譯單個源文件
為了進行測試,你可以創建"Hello World"程序:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
printf("Hello world!\n");
exit(0);
}
使用如下命令編譯并測試這個代碼:
# gcc -o hello hello.c
# ./hello
Hello wordl!
在默認情況下產生的可執行程序名為a.out,但你通常可以通過 gcc
的"-o"選項來指定自己的可執行程序名稱。
2. 編譯多個源文件
源文件message.c包含一個簡單的消息打印函數:
#include <stdio.h>
void goodbye_world(void)
{
printf("Goodbye, world!\n");
}
使用gcc的"-c"標記來編譯支持庫代碼:
# gcc -c message.c
這一過程的輸出結果是一個名為message.o的文件,它包含適合連接到一個較大程序的已編譯目標代碼。
創建一個簡單的示例程序,它包含一個調用goodbye_world的main函數
#include <stdlib.h>
void goodbye_world(void):
int main(int argc, char **argv)
{
goodbye_world();
exit(0);
}
使用GCC編譯這個程序:
# gcc -c main.c
現在有了兩個目標文件: message.o 和 main.o 。它們包含能夠被 Linux
執行的目標代碼。要從這個目標代碼創建Linux可執行程序,需要再一次調用 GCC
來執行連接階段的工作:
# gcc -o goodbye message.o main.o
運行編譯結果:
# ./goodbye
Goodbye, world!
前面這些單獨的步驟也可以簡化為一個命令,這是因為 GCC
對如何將多個源文件編譯為一個可執行程序有內置的規則。
# gcc -o goodbye message.c main.c
# ./goodbye
Goodbye, world!
3. 使用外部函數庫
GCC 常常與包含標準例程的外部軟件庫結合使用,幾乎每一個 Linux
應用程序都依賴于由 GNU C 函數庫 GLIBC。
應用外部函數庫的例子:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define MAX_INPUT 25
int main(int agrc, char **argv)
{
char input[MAX_INPUT];
double angle;
printf("Give me an angle (in radians) ==>");
if(!fgets(input, MAX_INPUT, stdin)){
perror("an error occurred.\n");
}
angle = strtod(input, NULL);
printf("sin(%e) = %e\n", angle, sin(angle));
return 0;
}
編譯命令:
# gcc -o trig -lm trig.c
GCC 的"-lm"選項,它告訴 GCC
查看系統提供的數學庫(libm)。因為Linux和UNIX的系統函數庫通常以"lib"為前綴,所以我們假設它存在。真正的函數庫位置隨系統的不同而
不同,但它一般會位于目錄/lib或/usr/lib中,在這些目錄中還有數以百計的其他必需的系統函數庫。
4. 共享函數庫與靜態函數庫
Linux系統上的函數庫分為兩種不同的類型:共享的和靜態的
靜態函數庫:每次當應用程序和靜態連接的函數庫一起編譯時,任何引用的庫函數中的代碼都會被直接包含進最終的二進制程序。
共享函數庫:包含每個庫函數的單一全局版本,它在所有應用程序之間共享。這一過程背后所涉及的機制相當復雜,但主要依靠的是現代計算機的虛擬內存能力,它允許包含庫函數的物理內存安全地在多個獨立用戶程序之間共享。
使用共享函數庫不僅減少了文件的容量和 Linux
應用程序在內存中覆蓋的區域,而且它還提高了系統的安全性。一個被許多不同程序同時調用的共享函數庫很可能會駐留在內存中,以在需要使用它時被立即使用,
而不是位于磁盤的交換分區中。這有助于進一步減少一些大型 Linux
應用程序的裝載時間。
將上面的 message.c 作為共享庫函數使用的例子:
# gcc -fPIC -c message.c
"PIC"命令行標記告訴 GCC
產生的代碼不要包含對函數和變量具體內存位置的引用,這是因為現在還無法知道使用該消息代碼的應用程序會將它連接到哪一段內存地址空間。這樣編譯輸出的文
件 message.o 可以被用于建立共享函數庫,我們只需使用gcc的"-shared"標記即可:
# gcc -shared -o libmessage.so message.o
將上面的
mian.c使用共享庫函數ligmessage.so
編譯:
# gcc -o goodbye -lmessage -L. message.o
"-lmessage"標記來告訴 GCC 在連接階段引用共享函數庫 libmessage.so
。"-L."標記告訴 GCC 函數庫可能位于當前目錄中,否則 GNU
的連接器會查找標準系統函數庫目錄,在本例的情況下,就找不到可用的函數庫了。
此時運行編譯好的goodbye會提示找不到共享函數庫:
#./goodbye
./goodbye: error while loading shared libraries: libmessage.so: cannot
open shared object file: No such file or directory
可以使用命令 ldd
來發現一個特定應用程序需要使用的函數庫。ldd搜索標準系統函數庫路徑并顯示一個特定程序使用的函數庫版本。
#ldd goodbye
linux-gate.so.1 => (0×00493000)
libmessage.so => not found
libc.so.6 => /lib/libc.so.6 (0×0097c000)
/lib/ld-linux.so.2 (0×0095a000)
庫文件 libmessage.so
不能在任何一個標準搜索路徑中找到,而且系統提供的配置文件 /etc/ld.so.conf
也沒有包含一個額外的條目來指定包含該庫文件的目錄。
需要設置一個環境變量LD_LIBRARY_PATH來制定額外的共享函數庫搜索路徑,
# export LD_LIBRARY_PATH=`pwd`
# ldd goodbye
linux-gate.so.1 => (0x002ce000)
libmessage.so => /tmp/cpro/libmessage.so (0x00b0f000)
libc.so.6 => /lib/libc.so.6 (0x0097c000)
/lib/ld-linux.so.2 (0x0095a000)
運行程序
# ./goodbye
Goodbye, world!
gcc在命令行上經常使用的幾個選項是:
-c
只預處理、編譯和匯編源程序,不進行連接。編譯器對每一個源程序產生一個目標文件。
-o file 確定輸出文件為file。如果沒有用-o選項,缺省的可執行文件的輸出是
a.out,目標文件和匯編文件的輸出對source.suffix分別是source.o和source.s,預處理的C源程序的輸出是標準輸出stdout。
-Dmacro或-Dmacro=defn 其作用類似于源程序里的#define。例如:% gcc -c
-DHAVE_GDBM -DHELP_FILE=\"help\" cdict.c其中第一個-
D選項定義宏HAVE_GDBM,在程序里可以用#ifdef去檢查它是否被設置。第二個-D選項將宏HELP_FILE定義為字符串"help"(由于
反斜線的作用,引號實際上已成為該宏定義的一部分),這對于控制程序打開哪個文件是很有用的。
-Umacro
某些宏是被編譯程序自動定義的。這些宏通常可以指定在其中進行編譯的計算機系統類型的符號,用戶可以在編譯某程序時加上
-v選項以查看gcc缺省定義了哪些宏。如果用戶想取消其中某個宏定義,用-Umacro選項,這相當于把#undef
macro放在要編譯的源文件的開頭。
-Idir
將dir目錄加到搜尋頭文件的目錄列表中去,并優先于在gcc缺省的搜索目錄。在有多個-I選項的情況下,按命令行上-I選項的前后順序搜索。dir可使用相對路徑,如-I../inc等。
-O
對程序編譯進行優化,編譯程序試圖減少被編譯程序的長度和執行時間,但其編譯速度比不做優化慢,而且要求較多的內存。
-O2 允許比-O更好的優化,編譯速度較慢,但結果程序的執行速度較快。
-g
產生一張用于調試和排錯的擴展符號表。-g選項使程序可以用GNU的調試程序GDB進行調試。優化和調試通常不兼容,同時使用-g和-O(-O2)選項經常會使程序產生奇怪的運行結果。所以不要同時使用-g和-O(-O2)選項。
-fpic或-fPIC 產生位置無關的目標代碼,可用于構造共享函數庫。
以上是gcc的編譯選項。gcc的命令行上還可以使用連接選項。事實上,gcc將所有不能識別的選項傳遞給連接程序ld。連接程序ld將幾個目標文件和庫
程序組合成一個可執行文件,它要解決對外部變量、外部過程、庫程序等的引用。但我們永遠不必要顯式地調用ld。利用gcc命令去連接各個文件是很簡單的,
即使在命令行里沒有列出庫程序,gcc也能保證某些庫程序以正確的次序出現。
gcc的常用連接選項有下列幾個:
-Ldir
將dir目錄加到搜尋-l選項指定的函數庫文件的目錄列表中去,并優先于gcc缺省的搜索目錄。在有多個-L選項的情況下,按命令行上-L選項的前后順序搜索。dir可使用相對路徑。如-L../lib等。
-lname
在連接時使用函數庫libname.a,連接程序在-Ldir選項指定的目錄下和/lib,/usr/lib目錄下尋找該庫文件。在沒有使用-static選項時,如果發現共享函數庫libname.so,則使用libname.so進行動態連接。
-static 禁止與共享函數庫連接。
-shared 盡量與共享函數庫連接。
這是Linux上連接程序的缺省選項。下面是一個使用gcc進行連接的例子:
% gcc -o prog main.o subr.o -L../lib -lany -lm
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
