GNU構建系統和Autotool

来源:https://www.cnblogs.com/net-saiya/archive/2017/12/28/8134842.html
-Advertisement-
Play Games

原文:http://os.51cto.com/art/201609/518191.htm 經常使用Linux的開發人員或者運維人員,可能對configure->make->make install相當熟悉。事實上,這叫GNU構建系統,利用腳本和make程式在特定平臺上構建軟體。這種方式成為一種習慣, ...


原文:http://os.51cto.com/art/201609/518191.htm

經常使用Linux的開發人員或者運維人員,可能對configure->make->make install相當熟悉。事實上,這叫GNU構建系統,利用腳本和make程式在特定平臺上構建軟體。這種方式成為一種習慣,被廣泛使用。本文從用戶視角和開發者視角詳細說明,這種構建方式的細節,以及開發者如何利用autoconf和automake等工具(autotools)創建相容GNU構建系統的項目。

為了簡化可移植構建的難度,在早期有一套autotools工具幫助程式員構建軟體。我們熟知的configure->make->make install三部曲,大多都是基於autotools來構建的。autotools是GNU程式的標準構建系統,所以其實我們經常在使用三部曲。有些程式雖然也是這三部曲,但卻不是用autotools實現的,比如nginx的源碼就是作者自己編寫的構建程式。

用戶視角

用戶通過configure->make->make install基於源碼安裝軟體。然而大部分用戶可能並不知道這個過程究竟做了些什麼。

configure腳本是由軟體開發者維護併發布給用戶使用的shell腳本。這個腳本的作用是檢測系統環境,最終目的是生成Makefile和config.h。

make通過讀取Makefile文件,開始構建軟體。而make install可以將軟體安裝到需要安裝的位置。

如上圖,開發者在分發源碼包時,除了源代碼(.c .h…),還有許多用以支撐軟體構建的文件和工具,其中最重要的文件就是Makefile.in和config.h.in。configure腳本執行成功後,將為每一個*.in文件處理成對應的非*.in文件。

大部分情況只生成Makefile和config.h,因為Makefile用於make程式識別並構建軟體,而config.h中定義的巨集,有助於軟體通過預編譯來改變自身的代碼,以適應目標平臺某些特殊性。有些軟體在configure階段,還可以生成其他文件,這完全取決於如軟體本身。

configure

當運行configure時,將看到類似如下的系統檢查,這些檢查的多少取決於軟體本身的需要,也就是由軟體開發者來定義和編寫的。

  1. checking for a BSD-compatible install... /usr/bin/install -c 
  2. checking whether build environment is sane... yes 
  3. checking for a thread-safe mkdir -p... /bin/mkdir -p 
  4. checking for gawk... gawk 
  5. checking whether make sets $(MAKE)... yes 
  6. checking for gcc... gcc 
  7. checking for C compiler default output file name... a.out 
  8. ...  

一般來說,configure主要檢查當前目標平臺的程式、庫、頭文件、函數等的相容性。這些檢查結果將作用於config.h和Makefile文件的生成。從而影響最終的編譯。

用戶也可以通過給configure配置參數來定製軟體需要包含或不需要包含的組件、安裝路徑等行為。這些參數分為5組,可以通過執行./configure --help來查看,軟體提供哪些配置參數:

  • *安裝路徑相關配置。最常見的是--prefix。
  • *程式名配置。例如--program-suffix可用於為生成的程式添加尾碼。
  • *跨平臺編譯。不太常用。
  • *動態庫靜態庫選項。用於控制是否生成某種類型的庫文件。
  • 程式組件選項。用於配置程式是否將某種功能編譯到程式中,一般形如--with-xxx。這可能是最常用的配置,而且由軟體開發者來定義。

(*表示這是幾乎所有軟體都支持的配置,因為這些配置是autotool生成的configure腳本預設支持的。)

configure在執行過程中,除了生成Makefile外,還會生成的文件包括但不限於:

  • config.log 日誌文件
  • config.cache 緩存,以提高下一次configure的速度,需通過-C來指定才會生成
  • config.status 實際調用編譯工具構建軟體的shell腳本

如果軟體通過libtool構建,還會生成libtool腳本。關於libtool腳本如何生成,請看開發者視角。

configure經常會中途出錯,這一般是由於當前平臺不具有構建該軟體所必需的依賴(庫、函數、頭文件、程式…)。此時,不要慌張,仔細查看輸出,解決這些依賴。

開發者視角

開發者除了編寫軟體本身的代碼外,還需要負責生成構建軟體所需要文件和工具。當我接觸到autotools後,我發現,雖然有工具的幫助,但這件事情依舊十分複雜。

對於C或C++程式員,在早期,構建跨平臺的應用程式是相當繁瑣的一件事情,而且對於經驗不足的程式員而言,甚至難度巨大。因為構建可移植的程式的必要前提是對各個平臺足夠瞭解,這往往要花上相當長的時間去積累。

Unix系統的分支複雜度很高,不同的商用版或開源版或多或少都有差異。這些差異主要體現在:系統組件、系統調用。我們主要將Unix分為如下幾個大類:IBM-AIX HP-UX Apple-DARWIN Solaris Linux FreeBSD。Unix分支大全

因此,對於開發者而言,要麼自己編寫構建用的腳本,這往往需要極其扎實的shell能力和平臺熟悉度。另一個選擇就是部分依賴工具。autoconf和automake就是這樣的工具。

autoreconf

為了生成configure腳本和Makefile.in等文件,開發者需要創建並維護一個configure.ac文件(在早期,通常叫configure.in文件,雖然沒有區別,但強烈建議使用.ac,因為.in文件往往意味著被configure腳本識別為模板文件並生成直接參与最終構建的文件,configure.in在命名上有歧義),以及一系列的Makefile.am。autoreconf程式能夠自動按照合理的順序調用autoconf automake aclocal等程式。

configure.ac

configure.ac用於生成configure腳本。autoconf工具用來完成這一步。下麵是一個configure.ac的例子:

  1. AC_PREREQ([2.63]) 
  2. AC_INIT([st], [1.0], [[email protected]]) 
  3. AC_CONFIG_SRCDIR([src/main.c]) 
  4. AC_CONFIG_HEADERS([src/config.h]) 
  5.  
  6. AM_INIT_AUTOMAKE([foreign]) 
  7.  
  8.  
  9. # Checks for programs. 
  10. AC_PROG_CC 
  11. AC_PROG_LIBTOOL 
  12.  
  13. # Checks for libraries. 
  14.  
  15. # Checks for header files. 
  16.  
  17. # Checks for typedefs, structures, and compiler characteristics. 
  18.  
  19. # Checks for library functions. 
  20.  
  21. AC_CONFIG_FILES([Makefile 
  22.                  src/Makefile 
  23.                  src/a/Makefile 
  24.                  src/b/Makefile]) 
  25. AC_OUTPUT  

其中以AC_開頭的類似函數調用一樣的代碼,實際是一些被稱為“巨集”的調用。這裡的巨集與C中的巨集概念類似,會被替換展開。m4是一個經典的巨集工具,autoconf正是構建在m4之上,可以理解為autoconf預先實現了大量的,用於檢測系統可移植性的巨集,這些巨集在展開後就是大量的shell腳本。所以編寫configure.ac需要對這些巨集熟練掌握,並且合理調用。有時,甚至可以自己實現自己的巨集。

autoscan和configure.scan

可以通過調用autoscan命令得到一個初始化的configure.scan文件,然後重命名為configure.ac後,在此基礎上編輯configure.ac。autoscan會掃描源碼,並生成一些通用的巨集調用、輸入的聲明以及輸出的聲明。儘管autoscan十分方便,但是沒人能夠在構建之前,就把代碼完全寫好,因此autoscan通常用於初始化configure.ac。

autoheader和config.h

autoheader命令掃描configure.ac中的內容,並確定需要如何生成config.h.in。每當configure.ac有所變化,都可以通過再次執行autoheader更新config.h.in。在configure.ac通過AC_CONFIG_HEADERS([config.h])告訴autoheader應當生成config.h.in的路徑。在實際的編譯階段,生成的編譯命令會加上-DHAVE_CONFIG_H定義巨集,於是在代碼中,我們可以通過下麵代碼安全的引用config.h。

  1. /bin/sh ../../libtool --tag=CC   --mode=compile gcc -DHAVE_CONFIG_H ... 
  2. #ifdef HAVE_CONFIG_H 
  3. #include <config.h> 
  4. #endif  

config.h包含了大量的巨集定義,其中包括軟體包的名字等信息,程式可以直接使用這些巨集;更重要的是,程式可以根據其中的對目標平臺的可移植性相關的巨集,通過條件編譯,動態的調整編譯行為。

automake和Makfile.am

手工編寫Makefile是一件相當煩瑣的事情,而且,如果項目複雜的話,編寫難度將越來越大。因而,automake工具應運而生。我們可以編寫像下麵這樣的Makefile.am文件,並依靠automake來生成Makefile.in:

  1. SUBDIRS = a b 
  2. bin_PROGRAMS    = st 
  3. st_SOURCES      = main.c 
  4. st_LDADD        = $(top_builddir)/src/a/liba.la $(top_builddir)/src/b/libb.la   

這裡通過SUBDIRS聲明瞭兩個子目錄,子目錄的中的構建需要靠a/Makefile.am和b/Makefile.am來進行,這樣多目錄組織起來就方便多了。

bin_PROGRAMS聲明一個可執行文件目標,st_SOURCES指定這個目標所依賴的源代碼文件。另外,st_LDADD聲明瞭可執行文件在連接時,需要依賴的Libtool庫文件。

通過這個Makefile.am文件生成的Makefile.in文件相當大,不便貼出,但是可以想象,Makefile.in要比我們手工編寫的Makefile文件複雜的多。

automake的出現晚於autoconf,所以automake是作為autoconf的擴展來實現的。通過在configure.ac中聲明AM_INIT_AUTOMAKE告訴autoconf需要配置和調用automake。

aclocal

上面提到,configure.ac實際是依靠巨集展開來得到configure的。因此,能否成功生成取決於,巨集定義能否找到。autoconf會從自身安裝路徑下來尋找事先定義好了巨集。然而對於像automake、libtool和gettext等第三方擴展巨集,甚至是開發者自行編寫的巨集就一無所知了。於是,存在這個工具aclocal,將在configure.ac同一目錄下生成aclocal.m4,在掃描configure.ac的過程中,將第三方擴展和開發者自己編寫的巨集定義複製進去。這樣,autoconf在遇到不認識的巨集時,就會從aclocal.m4中查找。

下麵這張圖更為詳細的展現了整個工具鏈是如何互相配合的。

libtool

libtool試圖解決不同平臺下,庫文件的差異。libtool實際是一個shell腳本,實際工作過程中,調用了目標平臺的cc編譯器和鏈接器,以及給予合適的命令行參數。libtool可以單獨使用,這裡只介紹與autotools集成使用相關的內容。

automake支持libtool構建聲明。在Makefile.am中,普通的庫文件目標寫作xxx_LIBRARIES:

  1. noinst_LIBRARIES = liba.a 
  2.  
  3. liba_SOURCES = ao1.c ao2.c ao3.c  

而對於一個libtool目標,寫作xxx_LTLIBRARIES,並以.la作為尾碼聲明庫文件。

  1. noinst_LTLIBRARIES = liba.la 
  2.  
  3. liba_la_SOURCES = ao1.c ao2.c ao3.c  

在configure.ac中需要聲明LT_INIT:

  1. ... 
  2.  
  3. AM_INIT_AUTOMAKE([foreign]) 
  4.  
  5. LT_INIT 
  6.  
  7. ...  

有時,如果需要用到libtool中的某些巨集,則推薦將這些巨集copy到項目中。首先,通過AC_CONFIG_MACRO_DIR([m4])指定使用m4目錄存放第三方巨集;然後在最外層的Makefile.am中加入ACLOCAL_AMFLAGS = -I m4。

all-in-one

上面討論了很多關於autoreconf的細節。實際上,如今我們可以直接調用autoreconf --install來自動調用上面提到的所有子命令。這裡--install參數試圖將輔助的腳本和巨集copy到當前項目目錄中,下麵是執行時的輸出:

  1. autoreconf: Entering directory `.' 
  2. autoreconf: configure.ac: not using Gettext 
  3. autoreconf: running: aclocal  
  4. autoreconf: configure.ac: tracing 
  5. autoreconf: running: libtoolize --copy 
  6. libtoolize: putting auxiliary files in `.'. 
  7. libtoolize: copying file `./ltmain.sh' 
  8. libtoolize: Consider adding `AC_CONFIG_MACRO_DIR([m4])' to configure.ac and 
  9. libtoolize: rerunning libtoolize, to keep the correct libtool macros in-tree. 
  10. libtoolize: Consider adding `-I m4' to ACLOCAL_AMFLAGS in Makefile.am. 
  11. autoreconf: running: /usr/bin/autoconf 
  12. autoreconf: running: /usr/bin/autoheader 
  13. autoreconf: running: automake --add-missing --copy --no-force 
  14. configure.ac:10: installing `./config.guess' 
  15. configure.ac:10: installing `./config.sub' 
  16. configure.ac:9: installing `./install-sh' 
  17. configure.ac:9: installing `./missing' 
  18. src/Makefile.am: installing `./depcomp' 
  19. autoreconf: Leaving directory `.'  

當我們以--install參數運行時,libtoolize --copy被調用,這將使得ltmain.sh被copy進來;接下來分別執行autoconf和autoheader;automake的參數為--add-missing --copy --no-force,這將使得幾個輔助腳本和文件被安裝到目錄下。

這些輔助文件預設安裝在configure.ac同一個目錄下,如果你希望用另一個目錄來存放他們,可以配置AC_CONFIG_AUX_DIR,例如AC_CONFIG_AUX_DIR([build-aux])將使用build-aux目錄來存放輔助文件。

如果不使用--install參數,輔助文件要麼不copy,要麼以軟鏈的形式創建。推薦使用--install,因為這樣,其他軟體維護可以避免由於構建工具版本不一致造成問題。

輔助文件

一個依靠GNU構建系統開發的軟體除了源碼之外,還有很多輔助的文件,有些是腳本,有些是文本文件。下麵將逐一解釋這些文件:

  • aclocal.m4:上面提到了,這個巨集定義文件裡面包含了第三方的巨集定義,用於autoconf展開configure.ac
  • NEWS README AUTHORS ChangeLog:這些文件是GNU軟體的標配,不過在項目中不一定需要加入。如果項目中沒有這些文件,每次autoreconf會提示缺少文件,不過這並不影響。如果不想看到這些錯誤提示,可以用AM_INIT_AUTOMAKE([foreign])來配置automake。foreign參數就是告訴automake不要這麼較真:)
  • config.guess config.sub:由automake產生,兩個用於目標平臺檢測的腳本
  • depcomp install-sh:由automake產生,用於完成編譯和安裝的腳本
  • missing:由automake產生
  • ltmain.sh:有libtoolize產生,該腳本用於在configure階段配置生成可運行於目標平臺的libtool腳本
  • ylwrap:由automake產生,如果檢測構建需要使用lex和yacc,那麼會產生這個包裝腳本
  • autogen.sh:在早期,autoreconf並不存在,軟體開發者往往需要自己編寫腳本,按照順序調用autoconf autoheader automake等工具程式。這個文件就是這樣的腳本。起這麼個名字可能是習慣性的

總結

本文總概念上闡述了autotool系列工具是如何工作的。相比如今現成的IDE,GNU構建系統其實是非常難用的,學習成本比較高。筆者認為最為效率的途徑是學習開源的程式,從中慢慢體會,慢慢吸收。另外,推薦幾個資料:

  • 《GNU Autoconf Automake and Libtool》
  • Autotools Tutorial
  • GNU網站上關於autoconf automake 和 libtool的手冊

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 22.添加附加文件刪除後,文件大小沒有發生改變的(優化文件和清空回收站) ...
  • LabVIEW的TCP/IP函數庫非常好用,但是不恰當地設置打開連接結點的參數將帶來一些問題,麻煩。如下圖的打開連接的參數設置: 上圖中指定了本地的埠,會發生這樣的情況。當我們關閉應用程式之後,連接被關閉,按照TCP/IP的協議,連接會話資源會處於一種time_wait的狀態,存活一段時間,一般都 ...
  • 當新增硬碟時,要做的幾個事情就是:先按需要進行分區、然後對分區進行格式化、再進行掛載即將指定分區掛到指定目錄上;必要的時候做下校驗; 常用的命令有: fdisk :磁碟分區相關指令 如:查看 新增 刪除 合併 分區等 partproabe:重讀分區表 mkfs:將分區格式化成指定文件系統格式 mou ...
  • 1.在macOS High Sierras上安裝VMware for mac 下載地址:VMware Fusion 8.5.1 https://pan.baidu.com/s/1skQ1OyL 2.Ubuntu14.04安裝 2.1 下載ubuntu14.04鏡像文件 下載地址:中科大鏡像源 htt ...
  • 操作前需要以下軟體,且,Ubuntu已經安裝在VMware Workstation上。 Ubuntu16.04 LTSVMware WorkstationSecureCRT VMware的編輯tab >虛擬網路編輯 菜單查看網路配置: 子網IP:192.168.92.0子網掩碼:255.255 ...
  • 本節總結: uboot啟動流程如下: 1)設置CPU為管理模式 2)關看門狗 3)關中斷 4)設置時鐘頻率 5)關mmu,初始化各個bank 6)進入board_init_f()函數 (初始化定時器,GPIO,串口等,劃分記憶體區域) 7)重定位 複製uboot,然後修改SDRAM上的uboot鏈接地 ...
  • 前言 一款不錯的代碼質量管理工具Sonar 前期準備 官方參考文檔 https://docs.sonarqube.org/display/SONAR/Documentation 軟體下載 https://www.sonarqube.org/downloads/ https://dev.mysql.c ...
  • 問題背景: 一塊近似最小系統的控制小板,主要用於對電機,氣閥,集成液晶屏以及其他的部件控制。考慮電流會較大採用DC-DC穩壓管。 電路焊接完成後,最小系統正常工作。 問題: 加上液晶屏後,串口屏出現閃爍,5V電壓不穩。排除線路板線徑過細問題。 更換晶元後問題依然存在,但是穩壓晶元在某寶買的,還是擔心 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...