歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux技術

【Linux 學習筆記】gcc初體驗

大部分內容轉自:
http://www.linuxidc.com/Linux/2014-08/105302.htm
用VMware裝了個Ubuntu的虛擬機嗎,前坑未填,又增新坑。
在這裡學了一下,基本的目錄結構:
http://www.linuxidc.com/Linux/2015-07/120815p4.htm
目錄管理的生存向命令:
http://www.linuxidc.com/Linux/2015-07/120815p6.htm
Vim的基本操作:(。。。)

好了!開始填坑!
ctrl + alt + T 打開終端
pwd 顯示當前目錄
cd 切換目錄


更多命令,如刪除rmdir, rm 等在鏈接中均有說明。
接下來主要說明gcc的用法:
1. 單個文件的編譯
首先通過vim建立一個c文檔 口令如下:
vi hello.c
假設程序為:
#include <stdio.h>
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 -c main.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