關于源碼包的基本知識
§·什么是程序
程序(Program)是為實現特定目標或解決特定問題而用計算機語言編寫的命令序列的集合。為實現預期目的而進行操作的一系列語句和指令。
一般分為系統程序和應用程序兩大類。
程序就是為使電子計算機執行一個或多個操作,或執行某一任務,按序設計的計算機指令的集合。
§·程序包的編譯安裝
※·為什么需要源碼安裝
1.最新的軟件沒有rpm包;
2.有的rpm包沒有我們需要的功能;
3.程序最新版通常會發布源代碼。
※·源碼的rpm包:
一般為 .src.rpm結尾的包,例如:testapp-VERSION-release.src.rmp
使用rpmbuild命令制作二進制格式的rpm包,而后再安裝
※·linux源代碼生成二進制程序
·源代碼 —> 預處理 —> 編譯 —> 匯編 —> 連接 —> 可執行 —>二進制程序
源代碼的組織格式:
·多文件:文件中的代碼之間很可能存在跨文件依賴關系。手工的處理依賴關系很麻煩,我們可以通過工具來管理多文件的依賴關系:
·項目管理器:mask maven
C C++ : make java : maven
·那make程序如何知道多文件的依賴關系,或其他的相關多文件之間的關系呢
源代碼提供一個東西指示make合適的編譯:
Make (makefile)
( config —-> makefile.in(模板) —-> nakefile )
§·Linux程序源代碼
·源代碼:人類可以看懂的文本信息
·windows程序不開放源代碼,如果我需要減少該軟件的某些功能時,只有依賴軟件供應商。
·Linux提供源代碼,通過源代碼我們知道開源軟件到底做了哪些事情,我們還可以自行修 改程序代碼,以符合個人的需求。
§·Linux中可執行文件
·一個文件能不能執行,看有沒有執行權限。不過linux系統上真正認識可執行文件其實是二進制文件( binary program );
file /bin/bash
/bin/bash: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, stripped
·shell scripts 只是利用shell這個程序的功能進行一些判斷,腳本在執行的過程中仍然會使用系統中已經編譯好了的二進制程序。
file /root/bin/fact.sh
/root/bin/fact.sh: Bourne-Again shell script text executable
※·源代碼編譯為可執行二進制圖解
思考問題:
1.何為源代碼?源代碼使用的什么語法?
通常源代碼就是程序代碼,寫給人類看的程序語言,但是機器不認識,所以無法執行;
源代碼一般文本文件就可以編輯,需要符合特定的語法格式。
例如:C 有c的語法格式,java有java的語法格式,
2.何為編譯器?
編譯器也是叫編譯程序,將程序代碼轉譯為機器看得懂的語言,就類似翻譯者的角色。
3.何為函數庫?
函數庫:就是把函數放到庫里面,供別人使用的一種方式。方法是把一些常用到的函數編完放到一個文件里供不同的人進行調用。調用的時候把它所在的文件名用#include<>加到里面就可以。
函數:完成某特定功能的代碼片段
Linux中有許多的函數:三角函數,PAM模塊
函數庫分為動態庫和靜態函數庫
4.何為二進制程序?
可執行文件,經過編譯程序編程二進制程序后,機器看的懂所以可以執行的文件。
§·Linux中簡單的C程序編譯
※·單一程序:打印 hello world
◎·編輯程序代碼,也就是源代碼
使用vim編輯一個文件 hello.c
#include<stdio.h> int main(void) { printf("Hello World\n"); }
◎·開始編譯與執行
[root@Centos7 c_dir]# gcc hello.c #gcc不帶任何參數編譯hello.c源代碼 [root@Centos7 c_dir]# ls #生成的文件名默認為 a.out a.out hello.c [root@Centos7 c_dir]# ./a.out #執行a.out可執行文件 Hello World
◎·小結:
我們現在知道 hello.c為源代碼(人類可讀的), a.out為二進制程序(人類很難讀的)
※·主 子程序鏈接:子程序的編譯
◎·準備兩個C語言的源代碼
實現:thanks.c 主程序調用thanks_2.c這個子程序。代碼如下:
[root@Centos7 c_dir]# cat thanks.c #include<stdio.h> int main(void){ printf("Hello World\n") thanks_2(); #調用thanks_2.c 子程序 } [root@Centos7 c_dir]# cat thanks_2.c #include<stdio.h> void thanks_2(void) { printf("Thank you!\n") }
◎·進行程序的編譯與鏈接
[root@Centos7 c_dir]# ls a.out hello.c thanks_2.c thanks.c [root@Centos7 c_dir]# gcc -c thanks.c thanks_2.c #使用參數-c使生成的文件為源代碼文件名 [root@Centos7 c_dir]# ls a.out hello.c thanks_2.c thanks_2.o thanks.c thanks.o #gcc -c生成的 .o文件后綴名 [root@Centos7 c_dir]# gcc -o thanks thanks.o thanks_2.o #鏈接兩個.o文件生成程序名為 thanks [root@Centos7 c_dir]# ls a.out hello.c thanks thanks_2.c thanks_2.o thanks.c thanks.o #生成的二進制文件 thanks [root@Centos7 c_dir]# ./thanks #直接運行生成的二進制文件 thanks ,顯示結果 Hello World Thank you!
◎·小結
簡單的把兩個文件鏈接成一個文件,并且制作成一個可執行的二進制文件
※·調用外部函數庫的小程序
◎·準備源代碼文件
申明一個變量,讓變量的值為 sin90度,顯示變量的數值
[root@Centos7 c_dir]# cat sin.c #include<stdio.h> int main(void) { float value; #申明變量 value = sin(3.14/2); #變量的值為 sin90度,函數中 90度表示為:3.14(180度)除以2 printf("%f\n",value); }
◎·編譯源代碼
[root@Centos7 c_dir]# gcc sin.c #使用默認編譯 sin.c: In function ‘main’: sin.c:5:10: warning: incompatible implicit declaration of built-in function ‘sin’ [enabled by default] value = sin(3.14/2); ^ #編譯報錯了,提示:sin有問題,代表編譯沒有成功
分析錯誤原因:英文的大概意思是 提示沒有sin相關定義的參考值。這個問題是因為C語言里面的sin函數是寫在libm.so這個函數庫中的,我們并沒有在源代碼中將這個函數庫調用,導致我們編譯時出錯。
◎·編譯時加入額外函數庫鏈接的方式
root@Centos7 c_dir]# gcc sin.c -lm -L/lib -L/usr/lib -L/usr/lib64 #重點在于 -lm sin.c: In function ‘main’: sin.c:5:10: warning: incompatible implicit declaration of built-in function ‘sin’ [enabled by default] value = sin(3.14/2); ^ [root@Centos7 c_dir]# ls #雖然在編譯時報錯了,不過還是生成了默認的程序 a.out a.out hello.c sin.c thanks thanks_2.c thanks_2.o thanks.c thanks.o [root@Centos7 c_dir]# ./a.out #直接運行a.out得到我們需要的結果 1.000000
·特別注意:
使用gcc編譯時所加入的那個-lm意義在于:
· -l :是加入某個函數庫的意思,就是你需要調用函數庫的時候就得使用 -l參數
· m : 表示libm.so這個函數庫,libm.so 中lib 和。so后綴名是不需要寫的,所以剩下的就為 m
· -L : 參數的意義為:libm.so在哪些目錄下去找。
◎·編譯時加入額外頭文件
除了連接函數庫之外,我們第一行在一句:【 #include<stdio.h> 】,這行說的是要將一些定義數據由 stdio.h這個檔案讀入,這包括printf的相關設定,這個文件在 /usr/include/stdio.h.
如果我們stdio.h不在默認路徑下我們如何指定呢:
[root@Centos7 include]# gcc sin.c -lm -I/usr/include
◎·小結
·通過編譯多個文件,編譯時加入函數庫,編譯時加入額外的頭文件,我們可以了解到,不同系統的函數庫存放路徑可能不同,不同系統的頭文件路徑不同,就會導致我們編譯環境不同。
·不同的編譯環境就會導致我們如果在不同機器上編譯編譯指定的 函數庫 頭文件的路徑不同,導致編譯后的程序只能在相同編譯環境下的機器運行。
·也就是為什么有的開源軟件只提供源代碼,而不提供rpm包的原因。
·rpm包在對應的平臺上直接安裝即可,不需要編譯,由于別人已經編譯好了。
·源代碼在理論上可以在不同平臺上運行,只需要你編譯指定需要相關庫文件 頭文件等等路徑即可。
※·gcc編譯與make編譯
◎·gcc編譯于make編譯
·我們舉一個案例:我們源代碼有四個原始文件,比如: main.c haha.c sin_value.c cos_value.c
·main.c主要功能是讓用戶輸入角度數據,調用其他的三個子程序計算;
·haha.c 輸出一堆沒有的信息;
·sin_value.c : 計算使用者輸入的角度sin值;
·cos_value.c :計算使用者輸入的角度cos值;
*·使用gcc編譯
·如果我們使用gcc來編譯,我們需要做一下步驟
1. 先迚行目標文件的編譯,最終會有四個 *.o 的檔名出現:
[root@www ~]# gcc -c main.c [root@www ~]# gcc -c haha.c [root@www ~]# gcc -c sin_value.c [root@www ~]# gcc -c cos_value.c
2. 再迚行連結成為執行檔,并加入 libm 的數學凼式,以產生 main 執行檔:
[root@www ~]# gcc -o main main.o haha.o sin_value.o cos_value.o \ > -lm -L/usr/lib -L/lib
小結:gcc需要編輯很多步,如果文件有修改,我們又得需要編譯。如果源代碼文件特別對,幾百個,我們編譯就會需要大量的時間,這時候make這個工具就出現了。
*·使用make編譯
1. 先編輯 makefile 這個文件,內容只要寫出 main 這個執行檔案
[root@www ~]# vim makefile main: main.o haha.o sin_value.o cos_value.o gcc -o main main.o haha.o sin_value.o cos_value.o -lm
# 注意:第二行的 gcc 需要 <tab> 按鍵產生的空格。
2. 嘗試使用 makefile 編寫的規則進行編譯的:
[root@www ~]# make cc -c -o main.o main.c cc -c -o haha.o haha.c cc -c -o sin_value.o sin_value.c cc -c -o cos_value.o cos_value.c gcc -o main main.o haha.o sin_value.o cos_value.o -lm
# 此時 make 會去讀取 makefile 的內容,并根據內容直接去開始編譯文件!
3. 在不刪除任何文件,只修改文件的內容后,重新編譯
[root@www ~]# make make: `main' is up to date.
# 提示程序更新成功
◎·小結:
Make編譯好處:
·簡化編譯時所需要的下達的指令;
·若在編譯完成之后,修改了某個源代碼文件,則make僅會針對被修改了的文件進行編譯,其它的文件 不會被改動;
·最后可以依照相依性來更新程序
※·make的具體使用
◎·makefile基本語法
既然make可以直接讀取makefile文件的內容,按照規則執行,那我們來了解下 makefile的基本語法。
··在 makefile 當中的 # 代表批注;
·· <tab> 需要在命令行 (例如 gcc 這個編譯程序指令) 的第一個字符;
·· 目標 (target) 與相依文件(就是目標文件)之間需以『:』隔開。
# 1. 先編輯 makefile 來建立新的規則,此規則的標的名稱為 clean :
[root@www ~]# vi makefile main: main.o haha.o sin_value.o cos_value.o gcc -o main main.o haha.o sin_value.o cos_value.o -lm clean: rm -f main main.o haha.o sin_value.o cos_value.o
# 2. 以新的標的 (clean) 測試看看執行 make 的結果:
[root@www ~]# make clean <==就是這里!使用 make 以 clean 為標的 rm -rf main main.o haha.o sin_value.o cos_value.o
#3.我們先清理,在編譯源碼包
[root@www ~]# make clean main rm -rf main main.o haha.o sin_value.o cos_value.o cc -c -o main.o main.c cc -c -o haha.o haha.c cc -c -o sin_value.o sin_value.c cc -c -o cos_value.o cos_value.c gcc -o main main.o haha.o sin_value.o cos_value.o -lm
#4.使用腳本使得makefile文件更加簡便
[root@www ~]# vi makefile LIBS = -lm OBJS = main.o haha.o sin_value.o cos_value.o main: ${OBJS} gcc -o main ${OBJS} ${LIBS} clean: rm -f main ${OBJS}
◎·makefile生成工具 configure程序
make會在當前目錄下查找makefile或Makefile這個文本文件,通常情況下軟件開發商會寫一個軟件來偵測程序來測試用戶的作業環境,以及作業環境是否有軟件開發商所需要的其他功能,該軟件偵測完畢后蠻久會主動建立這個makefile的規則文件,通常這樣的偵測軟件名為 configure或者是config。
Configure軟件偵測系統環境有一下幾個方面:
·是否有合適的編譯程序可以編譯本軟件的程序代碼;
·是否已經存在本軟件所需要的函數庫,或其他需要的想依賴軟件
·操作系統平臺是否適合本軟件,包括linux的內核版本;
·內核的表頭定義當(header include)是否存在(驅動程序必須要的偵測)
◎·make編譯工作圖解
原創文章,作者:linux_root,如若轉載,請注明出處:http://www.www58058.com/39335