linux autotools 簡單案例入門

  • 項目驗證成功平臺:中標麒麟兆芯B61(x86_64、rpm系) + 優麒麟社區版19.10(x86_64、deb系)
  • 項目知識點來源:linux開源項目caja、mate-settings-daemon
  • 項目資源、源碼鏈接:
  • 本文知識點摘要:Makefile.am和Makefile.in的關係

1、 目標:從只有 .c 源碼到生成 Makefile 文件,編譯運行

2、項目的README文件:

1、手動編譯:
	gcc main.c show-notify.c show-notify.h `pkg-config --libs --cflags glib-2.0 gdk-2.0` -lnotify

2、重點文件名:
	configure.ac 、Makefile.am 

3、順序:
	- autoscan		-->產生autoscan.log、configure.sacn文件
	- mv configure.scan configure.ac
	- 修改configure.ac文件(例如指定項目的頂級目錄、解決automake編譯時的預處理與鏈接問題-即gcc的 -I -l 選項)
	- autoheader	-->產生config.h.in文件(注:這一步的前提是存在configure.ac/configure.in文件)
	- 編寫Makefil.am文件
	- aclocal		-->產生m4文件
	- automake --copy --add-missing		-->添加缺失的文件,並根據 Makefile.am 生成 Makefile.in
	- autoconf		-->根據configure.ac文件產生configure腳本
	- ./configure生成Makefile文件

4、細節點播:
	- AC_SUBST定義變量時 '=' 兩邊不要有空格
	- 爲啥Makefile.am要在configure.ac文件修改之後編寫?
		-- automake 可以從 autoconf 處繼承變量,這就是爲什麼 Makefile.am 裏的很多變量沒有定義,而可以直接使用
		-- 其實兩者的順序無所謂,只需要記住編譯代碼需要依賴哪些 .h .so 文件就行

3、針對該項目已經修改好的configure.ac文件

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

#autoscan的版本號是2.69
AC_PREREQ([2.69])
AC_INIT([show-notify-simple], [1.0], [[email protected]])
#需要使用automake生成Makefile.in文件
AM_INIT_AUTOMAKE
#指定項目的頂級目錄,即Makefile裏用到的 $(top_srcdir) 的值
#這裏是指main.c所在的目錄爲整個項目的頂級目錄
AC_CONFIG_SRCDIR([main.c])

AC_CONFIG_HEADERS([config.h])

# Checks for programs.此處一般是指編譯器檢測
AC_PROG_CC
AC_PROG_CPP

dnl ===========glib-2.0================
dnl ===========注意:= 兩邊不要有空格==
GLIB_2_CFLAGS="`pkg-config --cflags glib-2.0`"
AC_SUBST(GLIB_2_CFLAGS)
GLIB_2_LIBS="`pkg-config --libs glib-2.0`"
AC_SUBST(GLIB_2_LIBS)

dnl ===========gdk-pixbuf-2.0===================
dnl ===========AC_SUBST()是定義並提交一個變量===
GDK_2_PIXBUF_CFLAGS="`pkg-config --cflags gdk-pixbuf-2.0`"
AC_SUBST(GDK_2_PIXBUF_CFLAGS)
GDK_2_PIXBUF_LIBS="`pkg-config --libs gdk-pixbuf-2.0`"
AC_SUBST(GDK_2_PIXBUF_LIBS)

# Checks for libraries.

# Checks for header files. 檢測頭文件是否存在,這個最終會對應到項目頂級目錄下的 config.h 文件
# 如這裏,最終會在 config.h 文件中對應 HAVE_NOTIFY_H
AC_CHECK_HEADERS([notify.h])
# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.
#表示需要生成Makefile的地方,此處的意思是需要在頂級目錄下生成Makefile
AC_CONFIG_FILES([Makefile])

AC_OUTPUT

4、項目的Makefile.am文件:

NULL =

#要生成的可執行二進制文件的列表
bin_PROGRAMS = \
    show-notify-test \
    $(NULL)

#要生成的二進制可執行文件的依賴的源碼文件列表
#注:
#   - show-notify-test --> show_notify_test 下劃線的轉變
#   - _SOURCES 關鍵字不可少
#   - 爲啥整個文件裏沒有定義 top_srcdir 變量,這裏可以直接用?
#     --> 原因1:automake 從 autoconf 繼承而來
#     --> 原因2:參見 configure.ac AC_CONFIG_SRCDIR 字段的解釋
show_notify_test_SOURCES = \
    $(top_srcdir)show-notify.h \
    show-notify.c \
    main.c \
    $(NULL)

#要生成的二進制可執行文件的預處理階段頭文件的查找目錄列表(gcc -I選項)
#注:
#   - includedir 變量沒定義,爲何可以直接用?
#     --> $(includedir) 默認值是 '/usr/include/' 或者 '/usr/locale/include'
#     --> 原因:automake 從autoconf 繼承而來
#   - 其他2個值在 Makefile.am 沒有定義,爲啥可以直接用?
#     --> 原因1:automake 從 autoconf 繼承而來
#     --> 原因2:參見 configure.ac AC_SUBST 字段的解釋
show_notify_test_CPPFLAGS = \
    $(GLIB_2_CFLAGS) \
    $(GDK_2_PIXBUF_CFLAGS) \
    $(includedir) \
    $(NULL)

#要生成的二進制可執行文件的鏈接階段要鏈接的so庫列表(gcc -l選項)
#注:
#   - 下面這2個變量沒定義,爲何可以直接用?
#     --> 原因同上
show_notify_test_LDADD = \
    $(GLIB_2_LIBS) \
    $(GDK_2_PIXBUF_LIBS) \
    -lnotify \
    $(NULL)

# `automake 從 autoconf 繼承而來的講解`:
# Makefile裏用到的變量都是在configure中定義好的
# 而configure腳本是怎麼來的? --> 使用autoconf命令 根據 configure.ac文件生成的

5、可能的問題總結:

1)README文件列出的命令執行順序是固定的嗎?
  • 一般來說,從0開始構建項目時,大致順序就是這樣的,當你熟悉以後,你可以嘗試修改順序,查看報錯信息。例如:如果autheaderautoscan前運行,會提示你缺少configure.acconfigure.in文件。
2)我執行README文件裏的automake–copy–add-missing命令後報錯是因爲什麼?
  • 使用開源autotools系列工具構建項目時,項目頂級目錄下不可缺少的幾個文件是:AUTHORS、NEWS、ChangeLog、README。在運行該命令報錯時,touch以上文件即可,其餘缺少的文件在運行該命令時會自動創建。
3)configure.ac文件中的dnl關鍵字是什麼意思?
  • dnl關鍵字我也沒弄清楚,跟着開源configure.ac文件寫的,沒有報錯我就沒有進行額外查閱資料。
4)如果我自己從0開始寫項目,在生成Makefile後,執行make命令發現編譯失敗,那麼我應該從哪裏檢查問題?重新執行哪條命令後纔可以更新Makefile文件?難道我要從頭開始執行嗎?

注:以下的解釋是爲了方便初學者學習,準確解釋與操作可以跳轉:linux autotools使用總結(關鍵字、文件更新順序,調試技巧與錯誤解決) 以查看文件更新關係

  • configure.ac和Makefile.am在開發者自己修改的,make名命令能否執行成功主要靠這2個文件。
  • 先梳理清以下關係:
    • Makefile.am和Makefile.in關係:automake命令執行後會根據Makefile.am會生成/更新Makefile.in文件
    • configure.ac和configure關係:autoconf命令會根據configure文件生成/更新configure文件
  • 所有問題應該一目瞭然(即出錯原因):
    • Makefile.am語法錯誤或者關鍵字錯誤 --> 修改後先運行automake,再運行./configure即可更新Makefile文件
    • configure.ac缺少編譯器檢測選項或者缺少CFLAGS、LIBS的定義 --> 修改後先運行autoconf,再運行./configure即可更新Makefile文件
    • 若Makefile.am和configure.ac文件均更改了,那麼automake、autoconf、./configure依次執行即可
5)能不能大致總結以下Makefile.am、Makefile.in、configure.ac、configure文件的相互關係?
  • 細心的人可以發現,這個問題在上一條問題中有闡述,這裏再繼續做補充。

  • Makefile.in根據Makefile.am生成,那麼我們有必要查看或者修改Makefile.in文件嗎?

    • 在工作過程中(一般指修改開源代碼),我有過修改Makefile.in文件的經歷,具體原因已經忘記,但是一般很少修改Makefile.in文件
    • 如果是自己練習使用autotools系列工具,那幾乎也沒必要查看Makefile.in、Makefile和configure文件,因爲這3個文件的內容是很龐大的。
  • configure.ac文件內部有一些關鍵字段涉及到的知識較多,這一部分我會在linux autotools案例升級(多目錄編程實例)中進行講解

6)config.h文件有啥用?爲啥我沒看見你在代碼裏使用這個文件?
  • config.h頭文件中一般會有類似的如下信息

     //HAVE_STDLIB_H 這個宏是怎樣生成的,讀者可關注一下configure.ac內的AC_CHECK_HEADERS字段
     #define HAVE_STDLIB_H 1		//那麼這裏的意思就是autotools工具檢測到你的系統中存在stdlib.h文件,所以你可以在某個.c文件內部進行如下操作
    
     #include "config.h"
     #ifdef HAVE_STDLIB_H		//像這樣,你也可以在別的地方使用宏進行代碼控制
     #include <stdlib.h>
     #endif
    
7)我在兩臺不同的linux系統上(如rpm系與deb系)拷貝項目,需要重新進行編譯嗎?
  • 首先聲明,二進制文件一般只區分cpu架構(x86_64、mips64、aarch64等),不區分機器;故直接拷貝後,若cpu架構相同,且不缺少運行依賴的話,二進制文件是可以直接運行的
  • 從項目工程的角度來講,configure腳本文件、Makefile.in、Makefile文件的內容都是依賴於項目存在的路徑(即pwd命令);所以這就意味着,拷貝過後的configure、Makefile文件都不能直接使用,需要重新生成;注:即使是本地進行拷貝也是不能直接使用configure、Makefile文件的,讀者可以自己嘗試
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章