Linux之編譯程序詳細介紹---./configure、make、make install

本節介紹如何通過源代碼生成可執行程序,在博主前期使用NVIDIA Jetson TX2時,由於Arm架構的各個包不完備,經常需要源碼編譯OpenCV等.
爲什麼要編譯軟件呢?

  • 可用性:儘管有些發行版已經包含了版本庫中的一些預編譯程序,但並不會包含用戶所有可能需要的應用程序。此時,用戶只能源碼編譯安裝
  • 及時性:雖然有些發行版本專注於一些前沿的程序版本,但是多數並不會。這意味着要想獲取最新版本的程序,編譯必不可少.

0.參考文獻

《Linux命令行大全》 [美] William E. Shotts. Jr 著 郭光偉 郝記生 譯, 人民郵電出版社

更多有用的Linux知識詳解,可參加博主的Linux學習導航頁.

1.什麼是編譯

編譯就是一個將源代碼(程序員編寫的人類可讀的程序描述–高級語言)翻譯成計算機處理器能識別的語言(機器語言)的過程.
高級語言編寫的程序通過編譯器轉換成機器語言。有些編譯器則將高級語言程序轉換成
彙編語言
,然後再使用一個彙編程序將其轉換成機器語言.
經常與編譯一起使用的步驟是鏈接.提供了通用任務支持,包含了多個例程,每一個實現的都是許多程序能夠共享的通用任務,這些程序通常在/lib和/usr/lib中.鏈接器(linker)程序可以實現編譯器的輸出與編譯程序所需要庫之間的鏈接.該操作的最終結果就是生成一個可供使用的可執行文件.

2.是不是所有程序都需要編譯

答案是否定的.像shell腳本可以直接運行,這些文件都是用腳本或解釋型語言編寫的,例如Perl,Python,PHP等。
腳本語言由一個稱爲解釋器的特殊程序來執行,解釋器負責輸入程序文件並執行其包含的所有指令.通常,解釋型程序要比編譯後的程序執行起來.這是因爲,在解釋型語言中,每條源代碼指令在執行時都要重新翻譯一次該代碼指令.然而編譯後的程序中,每條源代碼指令只翻譯一次,並且該翻譯結果將永久地記錄到最後的可執行文件中.

3.編譯一個C程序

在執行編譯操作之前,需要一些工具,諸如編譯器、鏈接器以及make等. **gcc(GNU C編譯器)**是Linux環境中通用的C編譯器.

$ which gcc
/usr/bin/gcc

表明已經安裝該編譯器.

3.1 獲取源代碼

從一個叫做diction的GNU項目中選擇一個程序進行編譯練習.
使用ftp下載源碼到src/目錄.

$ mkdir src
$ cd src
$ ftp ftp.gnu.org
Connected to ftp.gnu.org.
220 GNU FTP server ready.
Name (ftp.gnu.org:lmj): anonymous
230-NOTICE (Updated October 13 2017):
230-
230-Because of security concerns with plaintext protocols, we still
230-intend to disable the FTP protocol for downloads on this server
230-(downloads would still be available over HTTP and HTTPS), but we
230-will not be doing it on November 1, 2017, as previously announced
230-here. We will be sharing our reasons and offering a chance to
230-comment on this issue soon; watch this space for details.
230-
230-If you maintain scripts used to access ftp.gnu.org over FTP,
230-we strongly encourage you to change them to use HTTPS instead.
230-
230----
230-
230-Due to U.S. Export Regulations, all cryptographic software on this
230-site is subject to the following legal notice:
230-
230-    This site includes publicly available encryption source code
230-    which, together with object code resulting from the compiling of
230-    publicly available source code, may be exported from the United
230-    States under License Exception "TSU" pursuant to 15 C.F.R. Section
230-    740.13(e).
230-
230-This legal notice applies to cryptographic software only. Please see
230-the Bureau of Industry and Security (www.bxa.doc.gov) for more
230-information about current U.S. regulations.
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> cd gnu/diction
250 Directory successfully changed.
ftp> ls
200 EPRT command successful. Consider using EPSV.
150 Here comes the directory listing.
-rw-r--r--    1 3003     65534       68940 Aug 28  1998 diction-0.7.tar.gz
-rw-r--r--    1 3003     65534       90957 Mar 04  2002 diction-1.02.tar.gz
-rw-r--r--    1 3003     65534      141062 Sep 17  2007 diction-1.11.tar.gz
-rw-r--r--    1 3003     65534         189 Sep 17  2007 diction-1.11.tar.gz.sig
226 Directory send OK.
ftp> get diction-1.11.tar.gz
local: diction-1.11.tar.gz remote: diction-1.11.tar.gz
200 EPRT command successful. Consider using EPSV.
150 Opening BINARY mode data connection for diction-1.11.tar.gz (141062 bytes).
226 Transfer complete.
141062 bytes received in 0.74 secs (185.8389 kB/s)
ftp> bye
221 Goodbye.

源碼是以tar壓縮文件形式存在,有時也被成爲tarball,該文件包含了源代碼樹,即構成該源代碼的目錄及文件的組織架構.
對其解壓

$ tar -xzf diction-1.11.tar.gz
$ ls
diction-1.11  diction-1.11.tar.gz

3.2 檢查源代碼樹

解壓後的文件包含了原文件樹,具體內容爲

$ ls
config.guess  configure.in  diction.1.in  diction.spec.in  en_GB.po   getopt_int.h  misc.c  nl.po       style.1.in
config.h.in   COPYING       diction.c     diction.texi.in  getopt1.c  INSTALL       misc.h  README      style.c
config.sub    de            diction.pot   en               getopt.c   install-sh    NEWS    sentence.c  test
configure     de.po         diction.spec  en_GB            getopt.h   Makefile.in   nl      sentence.h

GNU項目的程序也包含了如README、INSTALL、NEWSCOPYING等這些文件,這些文件包含的是程序的描述、安裝步驟說明許可條款.在開始編譯之前,閱讀README和INSTALL是非常有必要的.
其它有趣的文件是以.c.h結尾的文件,軟件包提供的程序便是以.c結尾,並且劃分成了多個模塊.這種將大的程序分成較小的、易於管理的小程序片已經很普遍.這些源碼都是普通文本文件,可以用less查看.
.h文件是頭文件,包含了對源代碼文件或庫中的例程的描述.編譯器在鏈接這些例程模塊時,必須給它提供一個所用到所有模塊的描述.例如,在diction.c的開頭,可以看到如下文本行.

#include "getopt.h"

該文本行會指示編譯器在讀取diction.c中的源代碼內容時先讀取getopt.h中的內容,進而讀取getopt.c中的內容.
在getopt.h的include語句上面,還可以看到其他include語句,例如

#include <regex.h>

這些都是用來引用頭文件,但是它們引用是系統提供的頭文件,路徑在/usr/include.

3.3 生成程序

大多數程序都是使用一個簡單的2行命令來生成的.

./configure
make

configure程序其實是源代碼樹下的一個shell腳本,它的任務就是分析生成環境.多數源碼都設計成可移植的.也就是說,源代碼可以在多種類型的UNIX系統上生成,只是源代碼在生成時可能需要經過細微的調整以適應各系統之間的不同。configure同樣會檢查系統是否已經安裝了必要的外部工具和組件.

$ ./configure
checking build system type... x86_64-unknown-linux-gnu
checking host system type... x86_64-unknown-linux-gnu
checking for gcc... gcc
checking for C compiler default output file name... a.out
checking whether the C compiler works... yes
checking whether we are cross compiling... no
checking for suffix of executables...
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking for a BSD-compatible install... /usr/bin/install -c
checking for strerror... yes
checking for library containing regcomp... none required
checking for broken realloc... no
checking for msgfmt... yes
checking how to run the C preprocessor... gcc -E
checking for grep that handles long lines and -e... /bin/grep
checking for egrep... /bin/grep -E
checking for ANSI C header files... yes
checking for sys/types.h... yes
checking for sys/stat.h... yes
checking for stdlib.h... yes
checking for string.h... yes
checking for memory.h... yes
checking for strings.h... yes
checking for inttypes.h... yes
checking for stdint.h... yes
checking for unistd.h... yes
checking libintl.h usability... yes
checking libintl.h presence... yes
checking for libintl.h... yes
checking for library containing gettext... none required
configure: creating ./config.status
config.status: creating Makefile
config.status: creating diction.1
config.status: creating diction.texi
config.status: creating diction.spec
config.status: creating style.1
config.status: creating test/rundiction
config.status: creating config.h

重點注意的一點是:這裏沒有錯誤信息,如果有的話,該configure操作將以失敗告終,並且不會生成可執行程序,直至糾正錯誤.
可以看到configure在源目錄中創建了幾個新文件,其中最重要的是Makefile,Makefile是指導make命令如何創建可執行程序的配置文件.當然,其也是普通文本文件,可以用less查看.

$ less Makefile

make程序的作用其實就是輸入Makefile,該文件描述了生成最後可執行程序時各部件之間的聯繫及依賴關係.
makefile的第一部分內容定義了一些變量**,這些變量在makefile的後面部分將會被替代掉**,例如

CC=             gcc

該行將C編譯器定義爲gcc,然後在makefile的後面內容,可以看到如下例子

diction:        diction.o sentence.o misc.o getopt.o getopt1.o
                $(CC) -o $@ $(LDFLAGS) diction.o sentence.o misc.o \
                getopt.o getopt1.o $(LIBS)

該例中包含了一個替代操作,在運行時 $(CC)會被替代成gcc.
大多數Makefile文件都有很多行,這些行定義了目標文件(該例中是diction可執行文件),也定義了目標文件所依賴的一些文件,剩下的行則描述的是那些將原文件生成目標文件的命令.本例中,可執行文diction依賴於文件diction.o、sentence.o、misc.o、getopt.o以及getopt1.o,可以看到這些目標文件的定義

#{{{ dependencies
diction.o:      diction.c config.h getopt.h misc.h sentence.h
getopt.o:       getopt.c getopt.h getopt_int.h
getopt1.o:      getopt1.c getopt.h getopt_int.h
misc.o: misc.c config.h misc.h
sentence.o:     sentence.c config.h misc.h sentence.h
style.o:        style.c config.h getopt.h misc.h sentence.h
#}}}

然而,我們並沒有看到爲它們指定的任何命令,其實,它們是由文件前面的總體目標行生成的,該目標行描述了用來將所有.c文件編譯成.o文件的命令.

.c.o:
                $(CC) -c $(CPPFLAGS) $(CFLAGS) $<

接下來就是運行make

$ make 

運行結束後,所有目標文件都出現了

$ ls
config.guess   configure     diction       diction.spec
config.h       configure.in  diction.1     diction.spec.in
config.h.in    COPYING       diction.1.in  diction.texi
config.log     de            diction.c     diction.texi.in
config.status  de.mo         diction.o     en
config.sub     de.po         diction.pot   en_GB

如果再次運行make,則

$ make
make: Nothing to be done for 'all'.

這是因爲**,make並不是簡單地重新生成所有東西,只會生成那些需要生成的文件**。在所有目標文件已經存在的情況下,make會判斷原文件沒有任何改動,就不會進行任何操作.當然,可以刪除其中某個目標文件,然後再次運行make來觀察.

 rm getopt.o
$ make
gcc -c -I. -DSHAREDIR=\"/usr/local/share\" -DLOCALEDIR=\"/usr/local/share/locale\" -g -O2 -pipe -Wno-unused -Wshadow -Wbad-function-cast -Wmissing-prototypes -Wstrict-prototypes -Wcast-align -Wcast-qual -Wpointer-arith -Wcast-align -Wwrite-strings -Wmissing-declarations -Wnested-externs -Wundef -pedantic -fno-common getopt.c
gcc -o diction -g diction.o sentence.o misc.o \
        getopt.o getopt1.o
gcc -o style -g style.o sentence.o misc.o \
        getopt.o getopt1.o -lm

可以看到make重新生成了getopt.o,並重新鏈接diction和style程序,因爲它們都依賴於被刪除的程序.
這種特性說明了make的另外一種用法–可以維護目標文件的更新.make堅持一個原則—目標文件要比依賴文件新.

3.4 安裝程序

打包好的源代碼一般包含一個特殊的make目標程序,便是install.該目標程序將會在系統目錄下安裝最後生成的可執行程序.通常安裝在**/usr/local/bin中,即本地主機上生成軟件的常見安裝目錄**.然而,需要管理員權限.

$ sudo make install

安裝結束後,就可以查看程序是否可以運行.

$ which diction
/usr/local/bin/diction
man diction
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章