原文:thoughtbot.com/blog/the-ma…shell
若是你以前使用過 Unix 系設備開發,你可能使用過下面這幾行命令來安裝軟件:ruby
./configure
make
make install
複製代碼
我使用過不少次,但在我剛開始使用 Linux 的時候並不知道這幾行命令的意思,只知道安裝軟件的時候在命令行輸入這幾行命令就好了。工具
最近我在開發一個 Unix 工具,因此想弄明白這個標準化安裝命令背後的原理。不止 Unix 用戶對這幾行命令很熟悉,若是要開發一款針對 Homebrew、 Linux 或者 BSD 包管理器的應用,這也是一個很重要的知識點。接下來讓咱們深刻 Unix 去搞清楚這幾行命令的做用。測試
整個過程分爲三步:ui
配置spa
configure
腳本負責在你使用的系統上準備好軟件的構建環境。確保接下來的構建和安裝過程所須要的依賴準備好,而且搞清楚使用這些依賴須要的東西。命令行
Unix 程序通常是用 C 語言寫的,因此咱們一般須要一個 C 編譯器去構建它們。在這個例子中 configure
要作的就是確保系統中有 C 編譯器,並肯定它的名字和路徑。code
構建blog
當 configure
配置完畢後,可使用 make
命令執行構建。這個過程會執行在 Makefile
文件中定義的一系列任務將軟件源代碼編譯成可執行文件。生命週期
你下載的源碼包通常沒有一個最終的 Makefile
文件,通常是一個模版文件 Makefile.in
文件,而後 configure
根據系統的參數生成一個定製化的 Makefile
文件。
安裝
如今軟件已經被構建好而且能夠執行,接下來要作的就是將可執行文件複製到最終的路徑。make install
命令就是將可執行文件、第三方依賴包和文檔複製到正確的路徑。
這一般意味着,可執行文件被複制到某個 PATH
包含的路徑,程序的調用文檔被複制到某個 MANPATH
包含的路徑,還有程序依賴的文件也會被存放在合適的路徑。
由於安裝這一步也是被定義在 Makefile
中,因此程序安裝的路徑能夠經過 configure
命令的參數指定,或者 configure
經過系統參數決定。
若是要將可執行文件安裝在系統路徑,執行這步須要賦予相應的權限,通常是經過 sudo。
安裝過程簡單說就是 configure
腳本根據系統信息將 Makefile.in
模版文件轉換爲 Makefile
文件,可是 configure
和 Makefile.in
文件是怎麼產生的呢?
若是你曾經試着打開 configure
或者 Makefile.in
文件,你會發現超長並且複雜的 shell 腳本語言。有時候這些腳本代碼比它們要安裝的程序源代碼還要長。
若是想手動建立一個這樣的 configure
腳本文件是很是可怕的,好消息是這些腳本是經過代碼生成的。
經過這種方式構建的軟件一般是經過一個叫作 autotools
的工具集打包的。這個工具集包含 autoconf
、automake
等工具,全部的這些工具使得維護軟件生命週期變得很容易。最終用戶不須要了解這些工具,但卻可讓軟件在不一樣的 Unix 系統上的安裝步驟變得簡單。
咱們以一個 Hello world 的簡單 C 程序爲例,來看看如何使用 autotools
打包。
下面是程序源碼,源代碼文件命名:main.c
#include <stdio.h>
int main(int argc, char* argv[]) {
printf("Hello world\n");
return 0;
}
複製代碼
咱們不直接寫 configure
腳本文件,而是經過建立一個描述文件 configure.ac
來描述 configure 須要作的事情。configure.ac
使用 m4sh 寫,m4sh 是 m4
宏命令和 shell 腳本的組合。
第一個用到的宏命令是 AC_INIT
,這個命令會初始化 autoconf 並配置一些關於軟件的基本信息。下面這行代碼表示,軟件名是 helloworld
,版本是 0.1
,維護做者是 george@thoughtbot.com
:
AC_INIT([helloworld], [0.1], [george@thoughtbot.com])
複製代碼
由於這個項目須要用到 automake
,因此咱們要用下面這個命令來初始化它:
AM_INIT_AUTOMAKE
複製代碼
接下來,咱們須要告訴 autoconf
configure 腳本須要的依賴。在這個例子中,configure 須要的只是 C 編譯器,咱們能夠用下面這個宏命令來設置:
AC_PROG_CC
複製代碼
若是咱們須要別的依賴,可使用別的 m4
宏命令來設置;例如 AC_PATH_PROG
表示在 PATH
上搜索一個特定的程序。
此時咱們已經列出了全部的依賴,咱們可使用它們。前面有提到, configure
腳本會根據系統的信息和 Makefile.in
文件生成 Makefile
文件。
下面這個宏命令 AC_CONFIG_FILES
表示讓 autoconf 配置 configure 腳本找到 Makefile.in
文件,並將文件內的佔位符用對應的值替換,例如將 @PACKAGE_VERSION@
替換成 0.1
,而後將結果寫在 Makefile
文件中。
AC_CONFIG_FILES([Makefile])
複製代碼
最後,當咱們把全部配置信息都告訴 autoconf 後,可使用 AC_OUTPUT
命令去輸出腳本:
AC_OUTPUT
複製代碼
下面這段代碼是 configure.ac
中的全部代碼,相比 4737 行的 configure
腳本文件,這些代碼好懂多了
AC_INIT([helloworld], [0.1], [george@thoughtbot.com])
AM_INIT_AUTOMAKE
AC_PROG_CC
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
複製代碼
還差一點咱們就能夠發佈軟件了,configure
腳本須要一個 Makefile.in
文件,將系統相關信息填充進去後,生成最終的 Makefile
文件。
查看 Makefile.in
腳本發現它的代碼又長又複雜,手寫不太可能。不過能夠先寫一個 Makefile.am
腳本,而後經過 automake
工具生成 Makefile.in
腳本。Makefile.am
腳本相比 Makefile.in
簡單一些,接下來看看如何去寫。
首先須要告訴 automake
項目的結構,由於這裏的例子不是標準的 GNU 項目的結構,因此結構聲明爲 foreign
:
AUTOMAKE_OPTIONS = foreign
複製代碼
接下來告訴 automake
須要 Makefile 構建的軟件名字:
bin_PROGRAMS = helloworld
複製代碼
上面這行代碼其實包含了不少信息,這多虧了 automake
的命名規則。
PROGRAMS
稱爲「primary 主要」字段,它告訴了 automake
helloworld
文件的屬性。例如這裏的 PROGRAMS
表示這個文件須要編譯,而屬性是 SCRIPTS
或 DATA
的文件則不須要編譯。
這裏的 bin
前綴則是在告訴 automake
後面的文件須要安裝在 bindir
變量所指示的路徑下。相似 bindir
這樣變量還有 libdir
和 pkglibdir
,這些都是 autotools
定義的變量,也能夠建立自定義的變量。
若是項目中包含 Ruby 腳本,能夠定義 rubydir
變量,用來記錄安裝 Ruby 腳本的地方:
rubydir = ${datadir}/ruby
ruby_DATA = my_script.rb my_other_script.rb
複製代碼
安裝路徑前能夠再一些前綴來讓 automake
作一些別的操做。
由於定義了 「PROGRAMS
程序」,因此須要告訴 automake
它的源文件。下面這行代碼裏,前綴 helloworld
表示編譯的軟件名字,而不是要安裝的的路徑。
helloworld_SOURCES = main.c
複製代碼
下面這段是 Makefile.am
腳本的完整代碼,和 configure.ac
一塊兒編譯 helloworld
軟件。相比它生成的 Makefile.in
腳本代碼少了不少:
AUTOMAKE_OPTIONS = foreign
bin_PROGRAMS = helloworld
helloworld_SOURCES = main.c
複製代碼
如今已經寫好了全部須要的腳本,使用 autotools 就能夠生成 configure
和 Makefile.in
腳本。
首先須要爲 autotools 準備 m4 腳本環境:
aclocal
複製代碼
接下來使用 autoconf
將 configure.ac
生成 configure
腳本,用 automake
將 Makefile.am
生成爲 Makefile.in
腳本:
autoconf
automake --add-missing
複製代碼
最終使用軟件的用戶不須要關心使用 autotools 的部分,因此咱們只須要把 configure
和 Makefile.in
腳本發佈出去就能夠了,不須要前面寫的腳本。
autotools 也能夠幫咱們發佈軟件。Makefile 裏有各類各樣的命令,包括構建一個能夠發佈的軟件包:
./configure
make dist
複製代碼
甚至能夠測試軟件包可否在各類版本系統上安裝:
make distcheck
複製代碼
如今終於知道這段安裝命令的來歷和工做原理了!
下面分別展現下軟件發佈和安裝的命令:
發佈:
aclocal # 設置m4 環境
autoconf # 生成 configure 腳本
automake --add-missing # 生成 Makefile.in 腳本
./configure # 生成 Makefile 腳本
make distcheck # 使用 Makefile 構建一個發佈軟件並測試
複製代碼
安裝:
./configure # 生成 Makefile 腳本
make # 構建軟件
make install # 使用 Makefile 安裝軟件
複製代碼