如果你仍未使用過 Autotools,那麼這篇文章將改變你遞交程式碼的方式。
你有沒有下載過流行的軟體專案的原始碼,要求你輸入幾乎是儀式般的 ./configure; make && make install
命令序列來構建和安裝它?如果是這樣,你已經使用過 GNU Autotools 了。如果你曾經研究過這樣的專案所附帶的一些檔案,你可能會對這種構建系統的顯而易見的複雜性感到害怕。
好的訊息是,GNU Autotools 的設定要比你想象的要簡單得多,GNU Autotools 本身可以為你生成這些上千行的組態檔。是的,你可以編寫 20 或 30 行安裝程式碼,並免費獲得其他 4,000 行。
如果你是初次使用 Linux 的使用者,正在尋找有關如何安裝應用程式的資訊,那麼你不必閱讀本文!如果你想研究如何構建軟體,歡迎閱讀它;但如果你只是要安裝一個新應用程式,請閱讀我在的文章。
對於開發人員來說,Autotools 是一種管理和打包原始碼的快捷方式,以便使用者可以編譯和安裝軟體。 Autotools 也得到了主要打包格式(如 DEB 和 RPM)的良好支援,因此軟體儲存庫的維護者可以輕鬆管理使用 Autotools 構建的專案。
Autotools 工作步驟:
./configure
步驟中,Autotools 掃描宿主機系統(即當前正在執行的計算機)以發現預設設定。預設設定包括支援庫所在的位置,以及新軟體應放在系統上的位置。make
步驟中,Autotools 通常通過將人類可讀的原始碼轉換為機器語言來構建應用程式。make install
步驟中,Autotools 將其構建好的檔案複製到計算機上(在設定階段檢測到)的相應位置。這個過程看起來很簡單,和你使用 Autotools 的步驟一樣。
GNU Autotools 是我們大多數人認為理所當然的重要軟體。與 GCC(GNU 編譯器集合)一起,Autotools 是支援將自由軟體構建和安裝到正在執行的系統的腳手架。如果你正在執行 POSIX 系統,可以毫不保守地說,你的計算機上的作業系統裡大多數可執行軟體都是這些這樣構建的。
即使是你的專案是個玩具專案不是作業系統,你可能會認為 Autotools 對你的需求來說太過分了。但是,儘管它的名氣很大,Autotools 有許多可能對你有益的小功能,即使你的專案只是一個相對簡單的應用程式或一系列指令碼。
首先,Autotools 考慮到了可移植性。雖然它無法使你的專案在所有 POSIX 平台上工作(這取決於你,編碼的人),但 Autotools 可以確保你標記為要安裝的檔案安裝到已知平台上最合理的位置。而且由於 Autotools,高階使用者可以輕鬆地根據他們自己的系統情況客製化和覆蓋任何非最佳設定。
使用 Autotools,你只要知道需要將檔案安裝到哪個常規位置就行了。它會處理其他一切。不需要可能破壞未經測試的作業系統的客製化安裝指令碼。
Autotools 也得到了很好的支援。將一個帶有 Autotools 的專案交給一個發行版打包者,無論他們是打包成 RPM、DEB、TGZ 還是其他任何東西,都很簡單。打包工具知道 Autotools,因此可能不需要修補、魔改或調整。在許多情況下,將 Autotools 專案結合到流程中甚至可以實現自動化。
要使用 Autotools,必須先安裝它。你的發行版可能提供一個單個的軟體包來幫助開發人員構建專案,或者它可能為每個元件提供了單獨的軟體包,因此你可能需要在你的平台上進行一些研究以發現需要安裝的軟體包。
Autotools 的元件是:
automake
autoconf
automake
make
雖然你可能需要安裝專案所需的編譯器(例如 GCC),但 Autotools 可以很好地處理不需要編譯的指令碼或二進位制檔案。實際上,Autotools 對於此類專案非常有用,因為它提供了一個 make uninstall
指令碼,以便於刪除。
安裝了所有元件之後,現在讓我們了解一下你的專案檔案的組成結構。
GNU Autotools 有非常具體的預期規範,如果你經常下載和構建原始碼,可能大多數都很熟悉。首先,原始碼本身應該位於一個名為 src
的子目錄中。
你的專案不必遵循所有這些預期規範,但如果你將檔案放在非標準位置(從 Autotools 的角度來看),那麼你將不得不稍後在 Makefile
中對其進行調整。
此外,這些檔案是必需的:
NEWS
README
AUTHORS
ChangeLog
你不必主動使用這些檔案,它們可以是包含所有資訊的單個彙總文件(如 README.md
)的符號連結,但它們必須存在。
在你的專案根目錄下建立一個名為 configure.ac
的檔案。autoconf
使用此檔案來建立使用者在構建之前執行的 configure
shell 指令碼。該檔案必須至少包含 AC_INIT
和 AC_OUTPUT
M4 宏。你不需要了解有關 M4 語言的任何資訊就可以使用這些宏;它們已經為你編寫好了,並且所有與 Autotools 相關的內容都在該文件中定義好了。
在你喜歡的文字編輯器中開啟該檔案。AC_INIT
宏可以包括包名稱、版本、報告錯誤的電子郵件地址、專案 URL 以及可選的源 TAR 檔名稱等引數。
AC_OUTPUT 宏更簡單,不用任何引數。
AC_INIT([penguin], [2019.3.6], [[[email protected]][8]])AC_OUTPUT
如果你此刻執行 autoconf
,會依據你的 configure.ac
檔案生成一個 configure
指令碼,它是可以執行的。但是,也就是能執行而已,因為到目前為止你所做的就是定義專案的後設資料,並要求建立一個設定指令碼。
你必須在 configure.ac
檔案中呼叫的下一個宏是建立 Makefile 的函數。 Makefile
會告訴 make
命令做什麼(通常是如何編譯和連結程式)。
建立 Makefile
的宏是 AM_INIT_AUTOMAKE
,它不接受任何引數,而 AC_CONFIG_FILES
接受的引數是你要輸出的檔案的名稱。
最後,你必須新增一個宏來考慮你的專案所需的編譯器。你使用的宏顯然取決於你的專案。如果你的專案是用 C++ 編寫的,那麼適當的宏是 AC_PROG_CXX
,而用 C 編寫的專案需要 AC_PROG_CC
,依此類推,詳見 Autoconf 文件中的 Building Programs and Libraries 部分。
例如,我可能會為我的 C++ 程式新增以下內容:
AC_INIT([penguin], [2019.3.6], [[[email protected]][8]])AC_OUTPUTAM_INIT_AUTOMAKEAC_CONFIG_FILES([Makefile])AC_PROG_CXX
儲存該檔案。現在讓我們將目光轉到 Makefile
。
Makefile
並不難手寫,但 Autotools 可以為你編寫一個,而它生成的那個將使用在 ./configure
步驟中檢測到的設定選項,並且它將包含比你考慮要包括或想要自己寫的還要多得多的選項。然而,Autotools 並不能檢測你的專案構建所需的所有內容,因此你必須在檔案 Makefile.am
中新增一些細節,然後在構造 Makefile
時由 automake
使用。
Makefile.am
使用與 Makefile
相同的語法,所以如果你曾經從頭開始編寫過 Makefile
,那麼這個過程將是熟悉和簡單的。通常,Makefile.am
檔案只需要幾個變數定義來指示要構建的檔案以及它們的安裝位置即可。
以 _PROGRAMS
結尾的變數標識了要構建的程式碼(這通常被認為是原語目標;這是 Makefile
存在的主要意義)。Automake 也會識別其他原語,如 _SCRIPTS
、_ DATA
、_LIBRARIES
,以及構成軟體專案的其他常見部分。
如果你的應用程式在構建過程中需要實際編譯,那麼你可以用 bin_PROGRAMS
變數將其標記為二進位制程式,然後使用該程式名稱作為變數字首參照構建它所需的原始碼的任何部分(這些部分可能是將被編譯和連結在一起的一個或多個檔案):
bin_PROGRAMS = penguinpenguin_SOURCES = penguin.cpp
bin_PROGRAMS
的目標被安裝在 bindir
中,它在編譯期間可由使用者設定。
如果你的應用程式不需要實際編譯,那麼你的專案根本不需要 bin_PROGRAMS
變數。例如,如果你的專案是用 Bash、Perl 或類似的解釋語言編寫的指令碼,那麼定義一個 _SCRIPTS
變數來替代:
bin_SCRIPTS = bin/penguin
Automake 期望原始碼位於名為 src
的目錄中,因此如果你的專案使用替代目錄結構進行佈局,則必須告知 Automake 接受來自外部源的程式碼:
AUTOMAKE_OPTIONS = foreign subdir-objects
最後,你可以在 Makefile.am
中建立任何自定義的 Makefile
規則,它們將逐字複製到生成的 Makefile
中。例如,如果你知道一些原始碼中的臨時值需要在安裝前替換,則可以為該過程建立自定義規則:
all-am: penguin touch bin/penguin.sh penguin: bin/penguin.sh @sed "s|__datadir__|@datadir@|" $< >bin/$@
一個特別有用的技巧是擴充套件現有的 clean
目標,至少在開發期間是這樣的。make clean
命令通常會刪除除了 Automake 基礎結構之外的所有生成的構建檔案。它是這樣設計的,因為大多數使用者很少想要 make clean
來刪除那些便於構建程式碼的檔案。
但是,在開發期間,你可能需要一種方法可靠地將專案返回到相對不受 Autotools 影響的狀態。在這種情況下,你可能想要新增:
clean-local: @rm config.status configure config.log @rm Makefile @rm -r autom4te.cache/ @rm aclocal.m4 @rm compile install-sh missing Makefile.in
這裡有很多靈活性,如果你還不熟悉 Makefile
,那麼很難知道你的 Makefile.am
需要什麼。最基本需要的是原語目標,無論是二進位制程式還是指令碼,以及原始碼所在位置的指示(無論是通過 _SOURCES
變數還是使用 AUTOMAKE_OPTIONS
告訴 Automake 在哪裡查詢原始碼)。
一旦定義了這些變數和設定,如下一節所示,你就可以嘗試生成構建指令碼,並調整缺少的任何內容。
你已經構建了基礎結構,現在是時候讓 Autotools 做它最擅長的事情:自動化你的專案工具。對於開發人員(你),Autotools 的介面與構建程式碼的使用者的不同。
構建者通常使用這個眾所周知的順序:
$ ./configure$ make$ sudo make install
但是,要使這種咒語起作用,你作為開發人員必須引導構建這些基礎結構。首先,執行 autoreconf
以生成使用者在執行 make
之前呼叫的 configure
指令碼。使用 -install
選項將輔助檔案(例如符號連結)引入到 depcomp
(這是在編譯過程中生成依賴項的指令碼),以及 compile
指令碼的副本(一個編譯器的包裝器,用於說明語法,等等)。
$ autoreconf --installconfigure.ac:3: installing './compile'configure.ac:2: installing './install-sh'configure.ac:2: installing './missing'
使用此開發構建環境,你可以建立原始碼分發包:
$ make dist
dist
目標是從 Autotools “免費”獲得的規則。這是一個內建於 Makefile
中的功能,它是通過簡單的 Makefile.am
設定生成的。該目標可以生成一個 tar.gz
存檔,其中包含了所有原始碼和所有必要的 Autotools 基礎設施,以便下載程式包的人員可以構建專案。
此時,你應該仔細檢視存檔檔案的內容,以確保它包含你要傳送給使用者的所有內容。當然,你也應該嘗試自己構建:
$ tar --extract --file penguin-0.0.1.tar.gz$ cd penguin-0.0.1$ ./configure$ make$ DESTDIR=/tmp/penguin-test-build make install
如果你的構建成功,你將找到由 DESTDIR
指定的已編譯應用程式的本地副本(在此範例的情況下為 /tmp/penguin-test-build
)。
$ /tmp/example-test-build/usr/local/bin/examplehello world from GNU Autotools
Autotools 是一個很好的指令碼集合,可用於可預測的自動發布過程。如果你習慣使用 Python 或 Bash 構建器,這個工具集對你來說可能是新的,但它為你的專案提供的結構和適應性可能值得學習。
而 Autotools 也不只是用於程式碼。Autotools 可用於構建 Docbook 專案,保持媒體有序(我使用 Autotools 進行音樂發布),文件專案以及其他任何可以從可自定義安裝目標中受益的內容。