Linux安裝軟件必學(xué)之一make編譯
最近幾天一直在沒(méi)網(wǎng)的情況下往服務(wù)器上安裝軟件,針對(duì)一些軟件,簡(jiǎn)單的解壓一下或者make編譯完就可以運(yùn)行,復(fù)雜一點(diǎn)的配置下環(huán)境變量也還可以,但有一些軟件,依賴比較多時(shí),就連編譯過(guò)程就要去對(duì)編譯文件進(jìn)行一些改動(dòng),之前都是靠著點(diǎn)一些經(jīng)驗(yàn)根據(jù)報(bào)錯(cuò)信息進(jìn)行改動(dòng),昨天遇見(jiàn)一個(gè)軟件,Augustus,再編譯過(guò)程中,遇見(jiàn)下圖這個(gè)問(wèn)題,/usr/bin/ld: cannot find -lhts ,第一次遇見(jiàn),反復(fù)修改了下編譯文件始終沒(méi)有解決,昨晚睡覺(jué)前拿起《鳥哥的Linux私房菜-基礎(chǔ)篇》翻了翻,發(fā)現(xiàn)我這個(gè)軟件基于c語(yǔ)言編譯來(lái)進(jìn)行的,有必要好好學(xué)習(xí)一下,其它概念也溫故而知新。

一.什么是開放源碼、編譯程序
Linux系統(tǒng)真正認(rèn)識(shí)的可執(zhí)行文件其實(shí)是二進(jìn)制文件 ( binary program)。那么這些binary 的程序咋來(lái)的呢?之前我都是用vim/vi來(lái)寫一些小程序,寫完的程序都是純文本文檔,對(duì)于軟件開發(fā)者,這些文本文檔就是源代碼。完成源代碼工作后,就需要將這個(gè)文件[編譯]成為操作系統(tǒng)看的懂得binary program。這個(gè)編譯過(guò)程就需要『編譯程序』來(lái)完成,經(jīng)過(guò)編譯程序的編譯與連結(jié)之后,就會(huì)產(chǎn)生一支可以執(zhí)行的 binary program 了。很多軟件會(huì)提供我們編譯好的binary program,這類軟件,通常我們解壓后就可以使用了。
二.GCC編譯程序進(jìn)行程序編譯
Linux 上面最標(biāo)準(zhǔn)的程序語(yǔ)言為C,標(biāo)準(zhǔn)的 C 語(yǔ)言編譯程序是 gcc 這支程序來(lái)編譯,整個(gè)的流程借助鳥哥的圖片如下圖:

C 語(yǔ)言的原始碼文件通常以 *.c 作為擴(kuò)展名,而在編譯的過(guò)程當(dāng)中還會(huì)產(chǎn)生所謂的目標(biāo)文件 (Object file),這些文件是以 *.o 的擴(kuò)展名樣式存在的。此外,有的時(shí)候,我們會(huì)在程序當(dāng)中『引用、呼叫』 其他的外部子程序,或者是利用其他軟件提供的『函數(shù)功能』,這個(gè)時(shí)候,我們就必須要在編譯的過(guò)程當(dāng)中, 將該函式庫(kù)給他加進(jìn)去,如此一來(lái),編譯程序就可以將所有的程序代碼與函式庫(kù)作一個(gè)連結(jié) (Link) 以產(chǎn)生正確的執(zhí)行檔。
小結(jié):
開放源碼:就是程序代碼,寫給人類看的程序語(yǔ)言,但機(jī)器并不認(rèn)識(shí),所以無(wú)法執(zhí)行;
編譯程序:將程序代碼轉(zhuǎn)譯成為機(jī)器看的懂得語(yǔ)言,就類似翻譯者的角色;
可執(zhí)行文件:經(jīng)過(guò)編譯程序變成二進(jìn)制程序后,機(jī)器看的懂的可以執(zhí)行的文件。
三.函式庫(kù)
什么叫函式庫(kù)呢,舉個(gè)例子,Linux 系統(tǒng)有一個(gè)可以進(jìn)行身份驗(yàn)證的模塊,PAM 模塊。這個(gè) PAM 提供的功能可以讓很多的程序在被執(zhí)行的時(shí)候,除了可以驗(yàn)證用戶登入的信息外, 還可以將身份確認(rèn)的數(shù)據(jù)記錄在登錄檔里面,以方便系統(tǒng)管理員的追蹤!那么其它人在編寫具有身份認(rèn)證功能的程序時(shí),直接引用該 PAM 的功能就可以了,不需要再重新設(shè)計(jì)認(rèn)證機(jī)制,也就是說(shuō),只要在寫的程序代碼里面,設(shè)定去呼叫 PAM 的函式功能,這個(gè)程序就可以利用 Linux 原本就有的身份認(rèn)證的程序!除此之外,Linux 核心也提供了很多的函式庫(kù)來(lái)給硬件開發(fā)者利用。
函式庫(kù)在Linux中是一個(gè)非常重要的項(xiàng)目,因?yàn)楹芏嘬浖紩?huì)調(diào)用彼此的函式庫(kù)來(lái)進(jìn)行特殊功能的運(yùn)作,函式庫(kù)依據(jù)是否被編譯到程序內(nèi)部而分為動(dòng)態(tài)和靜態(tài)函式庫(kù) ,后面再進(jìn)行講述,函式庫(kù)的調(diào)用用個(gè)簡(jiǎn)單的流程圖來(lái)示意:

如果程序里面加入引用的函式庫(kù),就需要如圖 21.1.1 所示,在編譯的過(guò)程當(dāng)中,加入函式庫(kù)的相關(guān)設(shè)定。Linux 的核心提供很多的核心相關(guān)函式庫(kù)與外部參數(shù),這些核心功能在設(shè)計(jì)硬件的驅(qū)動(dòng)程序的時(shí)候是相當(dāng)有用的信息,這些核心相關(guān)信息大多放置/usr/include, /usr/lib, /usr/lib64 目錄下。
小結(jié):
函式庫(kù):就類似子程序的角色,可以被呼叫來(lái)執(zhí)行的一段功能函數(shù)。
四.make 與configure
估計(jì)很多人和我之前一樣,會(huì)有疑問(wèn),為啥有的軟件解壓就能用,有的直接make,還有的先configure然后再make,看完這段我才理解了。
有一些比較復(fù)雜的軟件,不僅有一支程序,而是一堆的程序代碼文件,在編譯過(guò)程中,除了每個(gè)主程序與子程序均需要寫上一筆編譯過(guò)程的指令外,還需要寫上最終的鏈接程序,這個(gè)時(shí)候就可以使用 make 這個(gè)指令的相關(guān)功能來(lái)進(jìn)行編譯過(guò)程的指令簡(jiǎn)化了!
當(dāng)執(zhí)行 make 時(shí),make 會(huì)在當(dāng)時(shí)的目錄下搜尋 Makefile (or makefile) 這個(gè)文本文件,而 Makefile 里面則記錄了原始碼如何編譯的詳細(xì)信息!make 會(huì)自動(dòng)的判別原始碼是否經(jīng)過(guò)變動(dòng)了,而自動(dòng)更新執(zhí)行檔。
make 就是一支程序,會(huì)去找 Makefile,那 Makefile 怎么寫?通常軟件開發(fā)商都會(huì)寫一支偵測(cè)程序來(lái)偵測(cè)用戶的作業(yè)環(huán)境,以及該作業(yè)環(huán)境是否有軟件開發(fā)商所需要的其他功能,該偵測(cè)程序偵測(cè)完畢后,就會(huì)主動(dòng)的建立這個(gè) Makefile 的規(guī)則文件啦!通常這支偵測(cè)程序的文件名為 configure 或者是 config。
那為什么要偵測(cè)作業(yè)環(huán)境呢?不同環(huán)境使用的系統(tǒng)呼叫可能不相同,而且每個(gè)軟件所需要的相依的函式庫(kù)也不相同,同時(shí),軟件開發(fā)商不會(huì)僅針對(duì) Linux 開發(fā),而是會(huì)針對(duì)整個(gè) Unix-Like做開發(fā)。所以他也必須要偵測(cè)該操作系統(tǒng)平臺(tái)有沒(méi)有提供合適的編譯程序才行!所以需要要偵測(cè)環(huán)境。一般來(lái)說(shuō),偵測(cè)程序會(huì)偵測(cè)的數(shù)據(jù)大約有底下這些:
? 1.是否有適合的編譯程序可以編譯本軟件的程序代碼;
? 2.是否已經(jīng)存在本軟件所需要的函式庫(kù),或其他需要的相依軟件;
? 3.操作系統(tǒng)平臺(tái)是否適合本軟件,包括 Linux 的核心版本;
? 4.核心的表頭定義檔 (header include) 是否存在 (驅(qū)動(dòng)程序必須要的偵測(cè))。
make 與 configure 運(yùn)作流程的可以使用底下的圖示來(lái)示意,下圖中,先是執(zhí)行 configure 來(lái)建立 Makefile,成功之后再以 make 來(lái)呼叫所需要的數(shù)據(jù)來(lái)編譯即可。

五.Tarball 的軟件
Tarball 文件,就是將軟件的所有原始碼文件先以 tar 打包,然后再以壓縮技術(shù)來(lái)壓縮,通常最常見(jiàn)的就是以 gzip 來(lái)壓縮了。因?yàn)槔昧?tar 與 gzip 的功能,所以 tarball 文件一般的擴(kuò)展名就會(huì)寫成 *.tar.gz 或者是簡(jiǎn)寫為 *.tgz!不過(guò),近來(lái)由于 bzip2 與 xz 的壓縮率較佳,所以 Tarball漸漸的以 bzip2 及 xz 的壓縮技術(shù)來(lái)取代 gzip。因此檔名也會(huì)變成 *.tar.bz2, *.tar.xz 之類的哩。所以說(shuō), Tarball 是一個(gè)軟件包,解壓縮之后,里面的文件通常就會(huì)有:
? 1.源代碼文件;
? 2.偵測(cè)程序文件 (可能是 configure 或 config);
? 3.本軟件的簡(jiǎn)易說(shuō)明與安裝說(shuō)明 (INSTALL 或 README)。
其中最重要的是那個(gè) INSTALL 或者是 README 這兩個(gè)文件,通常參考這兩個(gè)文件來(lái)進(jìn)行Tarball 軟件的安裝(以前都忽視了,都是報(bào)錯(cuò)提醒啥解決啥)。那么,一個(gè)正確的tar.gz軟件安裝過(guò)程是啥樣呢,參考下圖:

然后我就是在第4步出錯(cuò)了,學(xué)一下咋加入外部函式庫(kù)。
六.呼叫外部函式庫(kù):加入連結(jié)的函式庫(kù)
我們編譯一個(gè)計(jì)算三角函數(shù)里面的 sin (90 度角)的函數(shù),先看一下程序:

編譯時(shí)加入額外函式庫(kù)連結(jié)的方式:

-lm 表示使用 libm.so (或 libm.a) ,這個(gè)函式庫(kù)的意思:到 /lib 或 /lib64 里面搜尋函式庫(kù) libm.so。
到這里,總算知道我的報(bào)錯(cuò)原因了,沒(méi)有在/usr/lib目錄下找到-lhts庫(kù),需要我在makefile文件中通過(guò)-L給他指定路徑。
再接著往下學(xué)習(xí),
sin.c第一行的[#include],這行說(shuō)的是要將一些定義數(shù)據(jù)由 stdio.h 這個(gè)文件讀入,這包括 printf 的相關(guān)設(shè)定。這個(gè)文件其實(shí)是放置在 /usr/include/stdio.h 的!那么萬(wàn)一這個(gè)文件并非放置在這里呢?那么我們就可以使用底下的方式來(lái)定義出要讀取的 include 文件放置的目錄:

-I/path 后面接的路徑( Path )就是設(shè)定要去搜尋相關(guān)的 include 文件的目錄!不過(guò),默認(rèn)值是放置在 /usr/include 底下。
七.gcc 的簡(jiǎn)易用法 (編譯、參數(shù)與鏈結(jié))
gcc 為 Linux 上面最標(biāo)準(zhǔn)的編譯程序,是由 GNU 計(jì)劃所維護(hù)的,列舉幾個(gè) gcc 常見(jiàn)的參數(shù),


比較重要的大概就是這一些。另外,通常稱 -Wall 或者 -O 這些非必要的參數(shù)為旗標(biāo) (FLAGS),因?yàn)槲覀兪褂玫氖?C 程序語(yǔ)言,所以有時(shí)候也會(huì)簡(jiǎn)稱這些旗標(biāo)為 CFLAGS ,這些變量偶爾會(huì)被使用!尤其是在后頭會(huì)介紹的 make 相關(guān)的用法時(shí),更是重要。
附:大部分內(nèi)容來(lái)自《鳥哥的Linux私房菜-基礎(chǔ)篇》,電子版材料可以關(guān)注我微信公眾號(hào),發(fā)送書名,免費(fèi)提供電子版。
本文使用 文章同步助手 同步