歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> 關於Linux >> 【Linux 學習筆記】gcc初體驗

【Linux 學習筆記】gcc初體驗

日期:2017/3/1 11:58:51   编辑:關於Linux

用VMware裝了個Ubuntu的虛擬機嗎,前坑未填,又增新坑。

Vim的基本操作:(。。。)

\

好了!開始填坑!

ctrl + alt + T 打開終端

pwd 顯示當前目錄

cd 切換目錄

\

\ 更多命令,如刪除rmdir, rm 等在鏈接中均有說明。

接下來主要說明gcc的用法:

1. 單個文件的編譯

首先通過vim建立一個c文檔 口令如下:

vi hello.c

假設程序為:

#include 
int main()
{
printf(“Hello World!\n”);
return 0;
}

:wq 保存並退出

hello.c文件保存在當前目錄下

此時輸入口令:

gcc hello.c

運行後,看上去並沒有什麼效果,此時鍵入:ls -al (顯示當前目錄下所有的文件及文件夾,包括隱藏文件,以及它們的詳細信息)

會發現當前目錄中多出一個 a.out 的文件。

試著運行一下 a.out

./a.out

這時終端輸出了“hello world”字樣

如果不想每個生成的可執行文件都叫一個名字——a.out

則用如下口令:

gcc hello.c -o run

-o 代表 output

run 輸出的文件的文件名

這時,輸入:

./run

可以獲得相同的效果

2.多個文件的編譯

假設我一個項目裡由多個c文件組成,main.c , add.c

這時如何編譯

首先:

gcc -Wall -cmain.c

gcc -Wall -c add.c

這時,目錄下會多出main.o , add.o 兩個目標文件

-c 的作用是只編譯不鏈接 不生成可執行文件

接下來就要將這些目標文件進行鏈接,生成可執行文件。

gcc -Wall main.o add.o -o result

此時,當前目錄多處一個名為result的可執行文件

./result

運行後即可得到結果。

上述過程看起來十分繁瑣,可以用一句話來概括

gcc -wall main.c add.c -o result

效果一樣,但是前者更好的體現了gcc編譯和鏈接的過程:

編譯之後產生目標文件,將目標文件進行鏈接產生可執行文件。

3. 靜態鏈接和動態鏈接

http://www.linuxidc.com/Linux/2014-08/105302p4.htm

此頁說的很詳細,我也就似懂非懂的復制粘貼一兩句

“庫說白了其實就是一個個目標文件的集合。linux上一共有兩種庫文件類型,一種是以.a格式的靜態鏈接庫,另一種是以.so格式的動態鏈接庫。下面我們來講講靜態鏈接庫。”

ar的使用格式:

ar cr libName.a file1.o file2.o file3.o …...

注釋:libName.a中前綴lib和後綴.a固定,Name是靜態鏈接庫的名稱。

ar cr libtest.a add.o、minus.o、divide.o、multiply.o // 將幾個.o的目標文件整合到一個庫中

執行命令後,我們查看當前目錄下的文件,就多出了一個libtest.a文件。接著,我們就直接使用libtest.a來重新編譯源程序:

gcc -Wall main.c libtest.a -o result2

程序結果和之前的一樣。我們也可以使用下面這種方法:

gcc -Wall main.c -L. -ltest -o result2// 猜測原文這裡的“.”加的位置可能有問題,經測試發現 -L後面接地址,"."表示當前目錄,因此"."應當夾在-L後面

注意,上面的”-L.”不能缺少,因為,使用”-l“,編譯器查找的是系統默認的庫文件地址,而不是當前目錄,故需要使用-L來說明庫文件地址,由於我們的libtest.a在當前目錄下,故直接使用“.”表示當前目錄。以後,我們向別人提供第三方函數庫時,如果不想讓別人看到源代碼,那麼就可以只提供.a靜態鏈接庫和包含所有函數聲明的頭文件即可。

a.靜態鏈接
在之前所有的教程裡,我們都是把生成的目標文件、靜態鏈接庫以及頭文件放在同一個文件夾下,這樣不僅顯得很雜亂,也不便管理源文件,一旦程序的文件數目龐大後,問題就愈加突出。下面我們就對程序文件整理一下,一般來說,頭文件放在include 文件夾下,靜態鏈接庫lib文件夾下。下面先創建兩個文件夾,並把相應的文件移動到對應文件夾下。

mkdir include
mkdir lib
mv libtest.a lib
mv math.h include

由於我們已經將四個目標文件(add.o、minus.o、divide.o、multiply.o)打包成靜態鏈接哭libtest.a,那麼就可以刪除這四個文件:

rm add.o minus.o divide.o multiply.o

這是當前目錄就只剩下main.c、add.c、minus.c、divide.c、multiply.c這五個源文件。



首先,我們用比較麻煩的方法一步步地來編譯源文件,首先是生成目標文件,由於add.c、minus.c、divide.c、multiply.c這四個源代碼的目標文件的已經生成並被打包到靜態鏈接庫中,故我們只需生成main.c的目標文件即可:

gcc -Wall -Iinclude -c main.c // 我在測試的時候 include 文件夾是放在 programming 文件夾中,因此可寫為 -lprogramming/include ,注意“相對地址”概念

這裡-Iinclude中-I後面接的是main.c中所引用頭文件(math.h)的地址,這裡使用的是相對地址,其實也可以使用絕對地址,當由於不同的linux系統,他們的文件位置可能有寫差異,這就造成我們程序的移植性很差,所以還是建議大家使用相對地址。



接下就鏈接目標文件即可。

gcc -Wall main.o -Llib -ltest -o result3

這裡-Llib是-L後面接的是靜態鏈接庫的地址,由於我們的libtest.a在lib中,故接lib。

可以看到,多個.c文件編譯後生成的目標文件,.o文件,可以整合為一個庫文件,即.a文件,存放到工程文件目錄中,在鏈接時從目錄中調用此庫,即可達到多個.o文件同時作用的效果。

b.動態鏈接

動態鏈接的一個好處是,同一個庫文件資源,可以供多個程序共享使用,可以省下許多內存空間。但是,在移植到另一個操作系統環境時,如果該系統沒有相應的動態鏈接庫或設置相應的路徑,那麼程序就無法運行,這在移植性方面,相對靜態鏈接方式就差一些。下面開始進入主題:

動態鏈接庫的後綴是.so(在linux上,windows上是.dll)。其命名方式為:libxxx.so,

創建方法:

gcc -c -fpic A.c B.c .............

gcc -shared A.o B.o .... -o libxxx.so

這裡-fpic:由於共動態鏈接庫不同,他們在運行時加載,因而地址是很隨機的,加上-fpic選項,可以保證編譯生成的東西是地址無關的。

我們這次創建一個libtest.so動態鏈接庫。

gcc -c -fpic add.c minus.c divide.c multiply.c

gcc -shared add.o minus.o divide.o multiply.o -o libtest.so

現在,我們已經生成了一個libtest.so動態鏈接庫。

編譯鏈接:

gcc -Wall main.c -L. -ltest -o run

-L.表示庫文件在當前目錄下,-ltest就是libtest.so文件,注意,這裡不是運行時,而是編譯鏈接過程。。。

現在我們運行run執行文件,這時,會報錯,說找不到libtest.so文件。

這是因為,程序運行時,查找動態鏈接庫文件是到默認的系統目錄下找的。解決辦法有兩個:

一、將libtest.so復制到/usr/lib目錄下

二、修改路徑:export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH,在路徑下添加當前路徑。

// 缺少權限未調試成功,不過概念大概就是這樣

個人臆測動態與靜態的區別:

靜態庫封裝在軟件目錄中,與軟件本體共生,使用靜態庫是為了管理軟件本身。

動態庫則需要隨著軟件的移植,在當前系統中的庫中進行配置。在程序編譯的時候,檢索的是當前系統的庫,是否有對應的動態庫文件。因此,同一個庫文件資源,可以供多個程序共享使用,可以省下許多內存空間。

本章內容,操作簡單,偏向基礎原理,主要是為了下一步學習makefile做准備。

Copyright © Linux教程網 All Rights Reserved