linux autotools案例升級(多目錄編程實例)

本文開發環境配置

需要的工具 優麒麟等deb系 fedora等rpm系
autotools工具 apt install autoconf automake libtool yum install autoconf automake libtool
glib庫 apt install libglib2.0-dev yum install glib2-devel
notify庫 apt install libnotify-dev yum install libnotify-devel

1、目標:解決子目錄之間源碼包含與編譯依賴的關係

本篇重在理解多目錄項目工程中,Makefile.am文件怎麼編寫,以及如何解決不同目錄之間的源碼依賴關係
即重點應該查看源碼#include與Makefile.am中_LIBADD _LDADD字段

2、項目的README文件:

1、命令行手動編譯  gcc time-notify/time-notify.c time-notify/time-notify.h src/show-notify.c src/show-notify.h test/main.c `pkg-config --cflags --libs glib-2.0 gdk-pixbuf-2.0` -I./src -I./time-notify -I. -lnotify

2、重點關注:
	- configure.ac內subdir-objects關鍵字的作用:多目錄工程中,automake要使用該參數
	- Makefile.am中.la文件的使用:用於解決gcc鏈接階段的依賴問題

3、新增知識難度:
    - 源碼目錄結構的改變:所有源碼在同一目錄 --->  項目中存在多個目錄,每個目錄下均有源代碼
    - 鏈接形式的改變:單一目錄時鏈接尋找 .o 文件  --->  多目錄時鏈接尋找 .la 文件

4、一些改變:(針對於案例入門項目的改變)
    根據步驟3中新增的難度,主要涉及2方面的改變:
    - configure.ac
        1) 需要增加 subdir-objects 關鍵字:--->  AM_INIT_AUTOMAKE(subdir-objects)
        2) 需要增加編譯器檢測:--->  AC_PROG_LIBTOOL
        3) 列出某一個需要生成 Makfile 文件的目錄: --->  AC_CONFIG_FILES([....]),具體參見configure.ac文件
    - Makefile.am
        Makefile 的本質應該在於自動尋找依賴,那麼這一塊的改變主要是在Makefile.am中指定多目錄時如何尋找依賴。
        參見 time-notify/Makefile.am 中 libtime_notify_la_LIBADD 條目

5、autotools系列命令運行順序:(主要是新增libtoolize命令)
    - autoscan、mv configure.sacn configure.ac
    - autoheader
    - 編寫Makefile.am文件
    - aclocal
    - libtoolize
    - automake --copy --add-missing
    - autoconf
    - ./configure
6、一個Makefile.am書寫說明
	問題描述:我編寫這個項目案例時在 time-notify/Makefile.am 的 libtime_notify_la_SOURCES 條目中使用 $(top_srcdir) 變量時,項目編譯不過去。(具體寫法可見該文件的最後一行)
	資料查找:出現問題後我發現開源Makefile.am在 _SOURCES 條目中列舉源文件時,如果是與Makefile.am同目錄的源文件,則不使用 $(top_srcdir) 變量。
	問題解決:刪去該變量後,項目可以編譯通過;不確定與環境是否有關,讀者可以自行嘗試。

3、項目的configure.ac文件

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
#autoscan命令的版本
AC_PREREQ([2.69])
#項目名稱,版本號,作者聯繫方式
AC_INIT([notify-plus], [1.0], [[email protected]])
#項目需要使用automake工具,所以增加下面這一行
#subdir-objects:多目錄編程時,必須要有該關鍵字
AM_INIT_AUTOMAKE(subdir-objects)
#指定$(top_srcdir)的值爲config.h.in所在的目錄
AC_CONFIG_SRCDIR([config.h.in])
#AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([config.h])

# Checks for programs.編譯器檢測
#自動檢測要使用的C編譯器
AC_PROG_CC
AC_PROG_CPP
#使用pkg-config根據.pc文件自動爲我們生成 _CFLAGS 和 _LIBS
AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
#生成.la文件需要
AC_PROG_LIBTOOL

#下面這個寫法是參考開源項目的寫法
LIBNOTIFY_REQUIRED_VERSION=0.7.0
GLIB_REQUIRED_VERSION=2.17.3

dnl ------------------------------
dnl check for libnotify
dnl ------------------------------
#利用pkg-config生成 _CFLAGS _LIBS
PKG_CHECK_MODULES(LIBNOTIFY,libnotify >= $LIBNOTIFY_REQUIRED_VERSION)
#AC_SUBST輸出能夠被Makefile.am使用的變量,這裏體現出automake從autoconf繼承的關係
AC_SUBST(LIBNOTIFY_CFLAGS)
AC_SUBST(LIBNOTIFY_LIBS)

dnl ------------------------------
dnl check for glib-2.0
dnl ------------------------------
PKG_CHECK_MODULES(GLIB2,glib-2.0 >= $GLIB_REQUIRED_VERSION)
AC_SUBST(GLIB2_CFLAGS)
AC_SUBST(GLIB2_LIBS)

# Checks for libraries.檢測系統庫是否存在
AC_CHECK_LIB([glib-2.0],[notify])

# Checks for header files.檢測頭文件是否存在
AC_CHECK_HEADERS([glib.h],[libnotify/notify.h])

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.指定要生成Makefile文件的地方
# 多目錄項目編程時自然要列出多個目錄
AC_CONFIG_FILES([Makefile
                src/Makefile
                time-notify/Makefile
                test/Makefile])

AC_OUTPUT

4、項目所有的Makefile.am文件

1) 項目根目錄的總Makefile.am

#定義NULL時,= 後面直接換行,不要增加空格
NULL =
#下面這行是我在調試項目時,系統提示考慮增加的,具體用處讀者自查
ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}

# 在這裏列舉子目錄時,如果目錄之間存在依賴關係時,那麼一定要在這裏使用先後關係體現出來(被依賴的寫在前面)
# 讀者可以嘗試打亂這裏寫好的順序,自己跑一遍編譯流程,查看編譯報錯
SUBDIRS = \
    src \
    time-notify \
    test \
    $(NULL)

2)src目錄的Makefile.am

NULL =

#表示最終要生成一個libtool文件,用於其他目錄下源碼的編譯鏈接
noinst_LTLIBRARIES = libshow-notify.la

# $(includdir)的值由autoconf爲我們自動生成,
# 默認是'/urs/include' 或 '/usr/local/include'
# _CPPFLAGS指定預處理階段頭文件的查找目錄(gcc -I)
libshow_notify_la_CPPFLAGS = \
    -I$(includedir) \
    $(GLIB2_CFLAGS) \
    $(LIBNOTIFY_CFLAGS) \
    $(NULL)

# automake可以從autoconf繼承變量
# 即Makefile文件用到下列變量時可以在configure腳本文件中尋找這些變量的定義
# 當然,這些變量最初是由開發者在configure.ac文件中增加的
# _LIBADD指定鏈接階段so庫的查找路徑(gcc -l)
libshow_notify_la_LIBADD = \
    $(GLIB2_LIBS) \
    $(LIBNOTIFY_LIBS) \
    $(NULL)

#_SOURCES指定要生成文件所依賴的源代碼文件
libshow_notify_la_SOURCES = \
    $(top_srcdir)/src/show-notify.h \
    show-notify.c \
    $(NULL)

3)time-notify目錄的Makefile.am

NULL =
#要生成一個libtool文件
noinst_LTLIBRARIES = libtime-notify.la

libtime_notify_la_CFLAGS = \
    -I$(top_srcdir)/src/ \
    $(GLIB2_CFLAGS) \
    $(NULL)

# 後續會總結出 _LIBADD 與 LDADD 的區別
libtime_notify_la_LIBADD = \
    $(top_srcdir)/src/libshow-notify.la \
    $(GLIB2_LIBS) \
    $(NULL)

libtime_notify_la_SOURCES = \
    time-notify.c \
    time-notify.h \
    $(NULL)
# 這個對應於README文件裏描述的 $(top_srcdir) 變量的問題
#$(top_srcdir)/time-notify/time-notify.c

4)test目錄的Makefile.am

NULL =
#表示要生成一個名爲 test-show-notify 的二進制文件
bin_PROGRAMS = \
    test-show-notify \
    $(NULL)
#表示main.c內包含的頭文件time-notify.h要從time-notify目錄下查找
test_show_notify_CPPFLAGS = \
    -I$(top_srcdir)/time-notify \
    $(NULL)

# _LDADD指定生成二進制文件所有要鏈接的so庫(gcc -l)
test_show_notify_LDADD = \
    $(top_srcdir)/time-notify/libtime-notify.la \
    $(NULL)
# _SOURCES指定要生成的二進制文件所依賴的源碼文件
test_show_notify_SOURCES = \
    main.c \
    $(NULL)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章