Linux | C語言開發 | 自動編譯工具autoconf、automake | MakeFile

2020-08-12 20:59:07

使用autoconf和automake工具來幫助我們自動地生成符合自由軟體慣例的 Makefile。

參考

最初的原版沒找到,找到了幾個較詳述的部落格。按照部落格一步一步實驗並記錄在‘範例’中。
Configure,Makefile.am, Makefile.in, Makefile檔案之間關係(轉) - 一個人的天空@ - 部落格園

automake,autoconf使用詳解 - 風雪之隅

automake的理解和實踐總結_yihongxiaoxiang的專欄-CSDN部落格_automake視訊

autoconf和automake流程 - 簡書

Makefile

Makefile是用於自動編譯和鏈接的 ,一個工程有很多檔案組成,每一個檔案的改變都會導致工程的重新鏈接,但是不是 所有的檔案都需要重新編譯,Makefile中紀錄有檔案的資訊,在 make時會決定在鏈接的時候需要重新編譯哪些檔案.
 
  Makefile的宗旨就是 :讓編譯器知道要編譯一個檔案需要依賴其他的 哪些檔案.當那些依賴檔案有了改變,編譯器會自動的發現最終的生成檔案已經過時,而重新編譯相應的 模組.
  
  Makefile的 基本結構不是 很複雜,但當一個程式開發人員開始寫Makefile時,經常會懷疑自己寫的 是 否符合慣例,而且自己寫的 Makefile經常和自己的 開發環境相關聯,當系統環境變數或路徑發生了變化後,Makefile可能還要跟着修改.這樣就造成了手工書寫Makefile的 諸多問題,automake恰好能很好地幫助我們解決這些問題.
  
  使用automake,程式開發人員只需要寫一些簡單的 含有預定義宏的 檔案,由autoconf根據一個宏檔案生成configure,由automake根據另一個宏檔案生成Makefile.in,再使用configure依據Makefile.in來生成一個符合慣例的 Makefile.下面 下麪我們將詳細介紹Makefile的 automake生成方法.

簡介

autoscan (autoconf)

autoscan是用來掃描原始碼目錄生成configure.scan檔案。autoscan可以用目錄名做爲參數,但如果你不使用參數的話,那麼autoscan將認爲使用的是當前目錄.autoscan將掃描你所指定目錄中的原始檔,並建立configure.scan檔案.

掃描原始碼以搜尋普通的可移植性問題,比如檢查編譯器,庫,標頭檔案等,生成檔案configure.scan,它是configure.ac的一個雛形。
autoscan

  • configure.scan
    configure.scan包含了系統設定的 基本選項,裏面都是 一些宏定義.我們需要將它改名爲configure.ac

aclocal (automake)

根據已經安裝的宏,使用者定義宏和acinclude.m4檔案中的宏將configure.ac檔案所需要的宏集中定義到檔案 aclocal.m4中。aclocal是一個perl 指令碼程式,它的定義是:「aclocal - create aclocal.m4 by scanning configure.ac」
在这里插入图片描述

autoheader(autoconf)

根據configure.ac中的某些宏,比如cpp宏定義,執行m4,聲稱config.h.in
在这里插入图片描述

automake

automake將Makefile.am中定義的結構建立Makefile.in,然後configure指令碼將生成的Makefile.in檔案轉換 爲Makefile。如果在configure.ac中定義了一些特殊的宏,比如AC_PROG_LIBTOOL,它會呼叫libtoolize,否則它 會自己產生config.guess和config.sub

我們使用automake --add-missing來產生Makefile.in.
  選項–add-missing的 定義是 「add missing standard files to package」,它會讓automake加入一個標準的軟體包所必須的一些檔案.
  我們用automake產生出來的Makefile.in檔案是符合GNU Makefile慣例的 ,接下來我們只要執行configure這個shell 指令碼就可以產生合適的Makefile檔案了.

Makefile.am

Makefile.am是用來生成Makefile.in的 ,需要你手工編寫。Makefile.am中定義了一些內容:

AUTOMAKE_OPTIONS

AUTOMAKE_OPTIONS是 automake的 選項。在執行automake時,它會檢查目錄下是否存在標準GNU軟體包中應具備的各種檔案,例如AUTHORS.ChangeLog.NEWS等檔案。我們將其設定成foreign時,automake會改用一般軟體包的標準來檢查.

bin_PROGRAMS

bin_PROGRAMS是指定我們所要產生的 可執行檔案的檔名.如果你要產生多個可執行檔案,那麼在各個名字間用空格隔開.

helloworld_SOURCES

helloworld_SOURCES是指定產生"helloworld"時所需要的原始碼.如果它用到了多個原始檔,那麼請使用空格符號將它們隔開.

#比如需要helloworld.h, helloworld.c
helloworld_SOURCES= helloworld.h helloworld.c.

如果你在 bin_PROGRAMS定義了多個可執行檔案,則對應每個可執行檔案都要定義相對的filename_SOURCES

Makefile.am例子

AUTOMAKE_OPTIONS = foreign

# 定義包含哪些子目錄
SUBDIRS = avl thread httpp net log timing

# 定義生成的可執行檔案
bin_PROGRAMS = icecast

# install時不被導出的標頭檔案
noinst_HEADERS = admin.h cfgfile.h logging.h sighandler.h connection.h \
    global.h util.h slave.h source.h stats.h refbuf.h client.h

# 生成icecast所需要的原始檔
icecast_SOURCES = cfgfile.c main.c logging.c sighandler.c connection.c global.c \
    util.c slave.c source.c stats.c refbuf.c client.c

# 依賴的庫
icecast_DEPENDENCIES = @ICECAST_OPTIONAL@ net/libicenet.la thread/libicethread.la \
    httpp/libicehttpp.la log/libicelog.la avl/libiceavl.la timing/libicetiming.la
icecast_LDADD = $(icecast_DEPENDENCIES) @XIPH_LIBS@ @KATE_LIBS@

AUTOMAKE_OPTIONS = foreign
# 生成不需要install的lib
noinst_LTLIBRARIES = libicethread.la
noinst_HEADERS = thread.h

# lib的原始檔
libicethread_la_SOURCES = thread.c

autoconf

將configure.ac中的宏展開,生成 configure指令碼。這個過程可能要用到aclocal.m4中定義的宏。
  autoconf用來產生configure檔案。configure是一個指令碼,它能設定源程式來適應各種不同的操作系統平臺,並且根據不同的系統來產生合適的Makefile,從而可以使你的原始碼能在不同的操作系統平臺上被編譯出來。
  configure.in檔案的內容是一些宏,這些宏經過autoconf 處理後會變成檢查系統特性、環境變數、軟體必須的參數的shell指令碼。configure.in檔案中的宏的順序並沒有規定,但是你必須在所有宏的最前面和最後面分別加上AC_INIT宏和AC_OUTPUT宏.
  我們在使用automake時,實際上還需要用到其他的一些宏,但我們可以用aclocal來幫我們自動產生.執行aclocal後我們會得到aclocal.m4檔案.
  產生了configure.in和aclocal.m4兩個宏檔案後,我們就可以使用autoconf來產生configure檔案了.

在这里插入图片描述

configure

./configure的過程

在这里插入图片描述

Makefile

在符合GNU Makefiel慣例的 Makefile中,包含了一些基本的預先定義的操作:

  • make
    根據Makefile編譯原始碼,連線,生成目標檔案,可執行檔案.
  • make clean
    清除上次的 make命令所產生的 object檔案(後綴爲".o"的 檔案)及可執行檔案.
  • make install
    將編譯成功的 可執行檔案安裝到系統目錄中,一般爲/usr/local/bin目錄.
  • make dist
    產生髮布軟體包檔案(即distribution package).這個命令將會將可執行檔案及相關檔案打包成一個tar.gz壓縮的檔案用來作爲發佈軟體的 軟體包.它會在當前目錄下生成一個名字類似PACKAGE-VERSION.tar.gz的 檔案.PACKAGE和VERSION,是 我們在 configure.in中定義的AM_INIT_AUTOMAKE(PACKAGE, VERSION).
  • make distcheck
    生成發佈軟體包並對其進行測試檢查,以確定發佈包的正確性.

範例

安裝

yum install automake autoconf

還會自動安裝一些依賴包(perl)

概述

按照慣例從helloworld開始。
命令執行順序:

  1. 執行autoscan 生成configure.scan
  2. 然後手動修改configure.scan爲configure.in 有的平臺爲configure.ac
  3. 修改configure.in 裏面的內容。
  4. 執行autoheader生成檔案configure.h.in(現在一般改爲configure.ac)。configure.in裡有宏AC_CONFIG_HEADER()時用
  5. 執行libtoolize生成一些libtool 的檔案這些檔案跟平臺適應性有關係。
  6. 執行autoconf 執行過程中會生成configure 檔案
  7. 手動寫makefile.am
  8. 執行automake –a 將makefile.am 生成Makefile.in 同時生成選項可以補齊檔案config.guess,config.sub,install-sh,missing,depcomp
  9. 然後執行./configure && make && make install

整個過程中:

  1. 需要建立2個檔案:
helloworld.c
Makefile.am
  1. 需要修改一個檔案:
    執行autoscan後生成的configure.scan 檔案修改爲 configure.in

1.編寫.c檔案

  • 在hello/目錄下建立一個hello.c檔案,並編譯執行它:
mkdir helloAutoMake
cd helloAutoMake/
  • 編寫原始檔helloworld.c:
#include <stdio.h>
int main(){
    printf("Hello automake!\n");
    return 0;
}
[root@iZ2ze2y6fwj9mvujtsiya4Z helloAutoMake]# ll
total 4
-rw-r--r-- 1 root root 79 Aug 12 19:38 helloworld.c

2. autoscan

autoscan會掃描原始碼以搜尋普通的可移植性問題,比如檢查編譯器、庫、標頭檔案等,生成檔案configure.scan,它是configure.ac或者configure.in的雛形。
在这里插入图片描述

  • 我們使用autoscan命令來幫助我們根據目錄下的 原始碼生成一個configure.in的模板檔案。
[root@iZ2ze2y6fwj9mvujtsiya4Z helloAutoMake]# autoscan
[root@iZ2ze2y6fwj9mvujtsiya4Z helloAutoMake]# ls
autoscan.log  configure.scan  helloworld.c
  • 執行後在 hellowrold目錄下會生成一個檔案:configure.scan,我們可以拿它作爲configure.in的 藍本.(生成了configure.scan,autoscan.log檔案)

  • 將configure.scan 修改爲 configure.in

[root@iZ2ze2y6fwj9mvujtsiya4Z helloAutoMake]# mv configure.scan configure.in
[root@iZ2ze2y6fwj9mvujtsiya4Z helloAutoMake]# ls
autoscan.log  configure.in  helloworld.c
  • 修改configure.in
    在这里插入图片描述
#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.69])
AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])
AC_CONFIG_SRCDIR([helloworld.c])
# AC_CONFIG_HEADERS([config.h]) #這行不註釋,則需要執行autoheader
AM_INIT_AUTOMAKE(helloworld, 1.0) # 新增名稱和版本資訊
# Checks for programs.
AC_PROG_CC

# Checks for libraries.

# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

# AC_OUTPUT
AC_OUTPUT(Makefile) # 需要輸出Makefile檔案

3. acloacl

aclocal 是一個perl 指令碼程式。aclocal 根據configure.in 檔案的內容,自動生成aclocal.m4 和autom4te.cache檔案。但是使用configure.in時會提示一個warning,爲避免這個warning可以命名爲configure.ac

[root@iZ2ze2y6fwj9mvujtsiya4Z helloAutoMake]# aclocal
aclocal: warning: autoconf input should be named 'configure.ac', not 'configure.in'
  • 生成 aclocal.m4 和 autom4te.cache (生成aclocal.m4的過程中涉及到configure.in)
[root@iZ2ze2y6fwj9mvujtsiya4Z helloAutoMake]# ll
total 52
-rw-r--r-- 1 root root 37794 Aug 12 20:15 aclocal.m4
drwxr-xr-x 2 root root  4096 Aug 12 20:15 autom4te.cache
-rw-r--r-- 1 root root     0 Aug 12 20:02 autoscan.log
-rw-r--r-- 1 root root   529 Aug 12 20:14 configure.in
-rw-r--r-- 1 root root    79 Aug 12 19:38 helloworld.c
  • 下面 下麪是以configure.ac命名的結果:
[root@iZ2ze2y6fwj9mvujtsiya4Z helloAutoMake]# mv configure.in configure.ac
[root@iZ2ze2y6fwj9mvujtsiya4Z helloAutoMake]# aclocal
[root@iZ2ze2y6fwj9mvujtsiya4Z helloAutoMake]# ll
total 52
-rw-r--r-- 1 root root 37794 Aug 12 20:15 aclocal.m4
drwxr-xr-x 2 root root  4096 Aug 12 20:17 autom4te.cache
-rw-r--r-- 1 root root     0 Aug 12 20:02 autoscan.log
-rw-r--r-- 1 root root   529 Aug 12 20:14 configure.ac
-rw-r--r-- 1 root root    79 Aug 12 19:38 helloworld.c

3.5 autoheader

autoheader是建立configure標頭檔案模板的操作,這一步執不執行與在configure.ac/configure.in中是否定義AC_CONFIG_HEADERS([config.h])有關,如果沒有定義就不需要執行,如果定義了就一定需要執行。

4. antoconf

  • 用來產生configure 檔案。
  • configure 是一個指令碼,它能設定源程式來適應各種不同的操作系統平臺,並且根據不同的系統來產生合適的Makefile ,從而可以使你的原始碼能在不同的操作系統平臺上被編譯出來。
[root@iZ2ze2y6fwj9mvujtsiya4Z helloAutoMake]# autoconf
[root@iZ2ze2y6fwj9mvujtsiya4Z helloAutoMake]# ll
total 188
-rw-r--r-- 1 root root  37794 Aug 12 20:15 aclocal.m4
drwxr-xr-x 2 root root   4096 Aug 12 20:35 autom4te.cache
-rw-r--r-- 1 root root      0 Aug 12 20:02 autoscan.log
-rwxr-xr-x 1 root root 137628 Aug 12 20:35 configure
-rw-r--r-- 1 root root    529 Aug 12 20:14 configure.ac
-rw-r--r-- 1 root root     79 Aug 12 19:38 helloworld.c
  • 生成 configure (根據 configure.in, 和 aclocal.m4)

  • autoconf從configure.in這個列舉編譯軟體時所需要各種參數的 模板檔案中建立configure.

  • autoconf需要GNU m4宏處理器來處理aclocal.m4,生成configure指令碼.

  • m4是 一個宏處理器.將輸入拷貝到輸出,同時將宏展開.宏可以是 內嵌的 ,也可以是 使用者定義的 .除了可以展開宏,m4還有一些內建的 函數,用來參照檔案,執行命令,整數運算,文字操作,回圈等.m4既可以作爲編譯器的 前端,也可以單獨作爲一個宏處理器.

5. 編寫Makefile.am

在這裏插入程式碼片
AUTOMAKE_OPTIONS= foreign
bin_PROGRAMS= helloworld
helloworld_SOURCES= helloworld.c

6. automake --add-missing

  • 生成 Makefile.in, depcomp, install-sh, 和 missing (根據 Makefile.am, 和 aclocal.m4)

[root@iZ2ze2y6fwj9mvujtsiya4Z helloAutoMake]# automake --add-missing
configure.ac:8: warning: AM_INIT_AUTOMAKE: two- and three-arguments forms are deprecated.  For more info, see:
configure.ac:8: http://www.gnu.org/software/automake/manual/automake.html#Modernize-AM_005fINIT_005fAUTOMAKE-invocation
[root@iZ2ze2y6fwj9mvujtsiya4Z helloAutoMake]# ll
total 216
-rw-r--r-- 1 root root  37794 Aug 12 20:15 aclocal.m4
drwxr-xr-x 2 root root   4096 Aug 12 20:41 autom4te.cache
-rw-r--r-- 1 root root      0 Aug 12 20:02 autoscan.log
-rwxr-xr-x 1 root root 137628 Aug 12 20:35 configure
-rw-r--r-- 1 root root    529 Aug 12 20:14 configure.ac
lrwxrwxrwx 1 root root     32 Aug 12 20:41 depcomp -> /usr/share/automake-1.13/depcomp
-rw-r--r-- 1 root root     79 Aug 12 19:38 helloworld.c
lrwxrwxrwx 1 root root     35 Aug 12 20:41 install-sh -> /usr/share/automake-1.13/install-sh
-rw-r--r-- 1 root root     84 Aug 12 20:43 Makefile.am
-rw-r--r-- 1 root root  22764 Aug 12 20:43 Makefile.in
lrwxrwxrwx 1 root root     32 Aug 12 20:41 missing -> /usr/share/automake-1.13/missing

7. configure

./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /usr/bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking whether make supports nested variables... yes
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables... 
checking whether we are cross compiling... no
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 style of include used by make... GNU
checking dependency style of gcc... gcc3
checking that generated files are newer than configure... done
configure: creating ./config.status
config.status: creating Makefile
config.status: executing depfiles commands

生成 Makefile, config.log, 和 config.status

[root@iZ2ze2y6fwj9mvujtsiya4Z helloAutoMake]# ll
total 284
-rw-r--r-- 1 root root  37794 Aug 12 20:15 aclocal.m4
drwxr-xr-x 2 root root   4096 Aug 12 20:41 autom4te.cache
-rw-r--r-- 1 root root      0 Aug 12 20:02 autoscan.log
-rw-r--r-- 1 root root   9022 Aug 12 20:53 config.log
-rwxr-xr-x 1 root root  29045 Aug 12 20:53 config.status
-rwxr-xr-x 1 root root 137628 Aug 12 20:35 configure
-rw-r--r-- 1 root root    529 Aug 12 20:14 configure.ac
lrwxrwxrwx 1 root root     32 Aug 12 20:41 depcomp -> /usr/share/automake-1.13/depcomp
-rw-r--r-- 1 root root     79 Aug 12 19:38 helloworld.c
lrwxrwxrwx 1 root root     35 Aug 12 20:41 install-sh -> /usr/share/automake-1.13/install-sh
-rw-r--r-- 1 root root  22828 Aug 12 20:53 Makefile
-rw-r--r-- 1 root root     84 Aug 12 20:43 Makefile.am
-rw-r--r-- 1 root root  22764 Aug 12 20:52 Makefile.in
lrwxrwxrwx 1 root root     32 Aug 12 20:41 missing -> /usr/share/automake-1.13/missing

8. make

[root@iZ2ze2y6fwj9mvujtsiya4Z helloAutoMake]# make
gcc -DPACKAGE_NAME=\"FULL-PACKAGE-NAME\" -DPACKAGE_TARNAME=\"full-package-name\" -DPACKAGE_VERSION=\"VERSION\" -DPACKAGE_STRING=\"FULL-PACKAGE-NAME\ VERSION\" -DPACKAGE_BUGREPORT=\"BUG-REPORT-ADDRESS\" -DPACKAGE_URL=\"\" -DPACKAGE=\"helloworld\" -DVERSION=\"1.0\" -I.     -g -O2 -MT helloworld.o -MD -MP -MF .deps/helloworld.Tpo -c -o helloworld.o helloworld.c
mv -f .deps/helloworld.Tpo .deps/helloworld.Po
gcc  -g -O2   -o helloworld helloworld.o  

9. ./helloworld

[root@iZ2ze2y6fwj9mvujtsiya4Z helloAutoMake]# ./helloworld 
Hello automake!