1. 程式人生 > >Makefile.am文件配置

Makefile.am文件配置

目錄文件 靜態 使用 腳本 指定 ash 子目錄 str 數據文件

Makefile.am

Makefile.am是一種比Makefile更高層次的編譯規則,可以和configure.in文件一起通過調用automake命令,生成Makefile.in文件,再調用./configure的時候,就將Makefile.in文件自動生成Makefile文件了。所以Makefile.am文件是比Makefile文件更高的抽象。

下面我根據自己的工作中的一些應用,來討論Makefile.am的編寫。我覺得主要是要註意的問題是將編譯什麽文件?這個文件會不會安裝?這個文件被安裝到什麽目錄下?可以將文件編譯成可執行文件來安裝,也可以編譯成靜態庫文件安裝,常見的文件編譯類型有下面幾種:

  • PROGRAMS。表示可執行文件
  • LIBRARIES。表示庫文件
  • LTLIBRARIES。這也是表示庫文件,前面的LT表示libtool。
  • HEADERS。頭文件。
  • SCRIPTS。腳本文件,這個可以被用於執行。如:example_SCRIPTS,如果用這樣的話,需要我們自己定義安裝目錄下的example目錄,很容易的,往下看。
  • DATA。數據文件,不能執行。

可執行文件

bin_PROGRAMS = client  
  
client_SOURCES = key.c connect.c client.c main.c session.c hash.c  
client_CPPFLAGS 
= -DCONFIG_DIR=\"$(sysconfdir)\" -DLIBRARY_DIR=\"$(pkglibdir)\" client_LDFLAGS = -export-dynamic -lmemcached noinst_HEADERS = client.h INCLUDES = -I/usr/local/libmemcached/include/ client_LDADD = $(top_builddir)/sx/libsession.la \ $(top_builddir)/util/libutil.la

上面就是一個全部的Makefile.am文件,這個文件用於生成client可執行應用程序,引用了兩個靜態庫和MC等動態庫的連接。分析一下:

  • bin_PROGRAMS:表示指定要生成的可執行應用程序文件,這表示可執行文件在安裝時需要被安裝到系統中,如果只是想編譯。不想被安裝到系統中,可以用noinst_PROGRAMS來代替。
    • bin_PROGRAMS=client 這一行表示什麽意思?解釋如下:
      • PROGRAMS知道這是一個可執行文件。
      • client表示編譯的目標文件。
      • bin表示目錄文件被安裝到系統的目錄。
  • client_SOURCES:表示生成可執行應用程序所用的源文件,這裏註意,client_是由前面的bin_PROGRAMS指定的,如果前面是生成example,那麽這裏就是example_SOURCES,其它的類似標識也是一樣。
  • client_CPPFLAGS:這和Makefile文件中一樣,表示C語言預處理器參數,這裏指定了DCONFIG_DIR,以後在程序中,就可以直接使用CONFIG_DIR,不要把這個和另一個CFLAGS混淆,後者表示編譯器參數。
  • client_LDFLAGS:這個表示在連接時所需要的庫文件選項標識。這個也就是對應一些如-l,-shared等選項。
  • noinst_HEADERS:這個表示該頭文件只是參加可執行文件的編譯,而不用安裝到安裝目錄下。如果需要安裝到系統中,可以用include_HEADERS來代替。
  • INCLUDES:連接時所需要的頭文件。
  • client_LDADD:連接時所需要的庫文件,這裏表示需要兩個庫文件的支持,下面會看到這個庫文件又是怎麽用Makefile.am文件後成的。

再談談關於上文中的全局變量引用,可能有人註意到$(top_builddir)等全局變量(因為這個文件之前沒有定義),其實這個變量是Makefile.am系統定義的一個基本路徑變量,表示生成目標文件的最上層目錄,如果這個Makefile.am文件被其它的Makefile.am文件,這個會表示其它的目錄,而不是這個當前目錄。還可以使用$(top_srcdir),這個表示工程的最頂層目錄,其實也是第一個Makefile.am的入口目錄,因為Makefile.am文件可以被遞歸性的調用。

下面再說一下上文中出現的$(sysconfdir),在系統安裝時,我們都記得先配置安裝路徑,如./configure --prefix=/install/apache 其實在調用這個之後,就定義了一個變量$(prefix),表示安裝的路徑,如果沒有指定安裝的路徑,會被安裝到默認的路徑,一般都是/usr/local。在定義$(prefix),還有一些預定義好的目錄,其實這一些定義都可以在頂層的Makefile文件中可以看到,如下面一些值:

  • bindir = $(prefix)/bin。
  • libdir = $(prefix)/lib。
  • datadir=$(prefix)/share。
  • sysconfdir=$(prefix)/etc。
  • includedir=$(prefix)/include。

這些量還可以用於定義其它目錄,例如我想將client.h安裝到include/client目錄下,這樣寫Makefile.am文件:

clientincludedir=$(includedir)/client  
clientinclude_HEADERS=$(top_srcdir)/client/client.h  

這就達到了我的目的,相當於定義了一個安裝類型,這種安裝類型是將文件安裝到include/client目錄下。
我們自己也可以定義新的安裝目錄下的路徑,如我在應用中簡單定義的:

devicedir = ${prefix}/device  
device_DATA = package  

這樣的話,package文件會作為數據文件安裝到device目錄之下,這樣一個可執行文件就定義好了。註意,這也相當於定義了一種安裝類型:devicedir,所以你想怎麽安裝就怎麽安裝,後面的XXXXXdir,dir是固定不變的。

靜態庫文件

編譯靜態庫和編譯動態庫是不一樣的,我們先看靜態庫的例子,這個比較簡單。直接指定 XXXX_LTLIBRARIES或者XXXX_LIBRARIES就可以了。如果不需要安裝到系統,將XXXX換成noinst就可以。還是再羅嗦一下:

一般推薦使用libtool庫編譯目標,因為automake包含libtool,這對於跨平臺可移植的庫來說,肯定是一個福音。
看例子如下:

noinst_LTLIBRARIES = libutil.la  
  
noinst_HEADERS = inaddr.h util.h compat.h pool.h xhash.h url.h device.h   
  
libutil_la_SOURCES = access.c config.c datetime.c hex.c inaddr.c log.c device.c pool.c rate.c sha1.c stanza.c str.c xhash.c  
  
libutil_la_LIBADD = @LDFLAGS@  

第一行的noinst_LTLIBRARIES,這裏要註意的是LTLIBRARIES,另外還有LIBRARIES,兩個都表示庫文件。前者表示libtool庫,用法上基本是一樣的。如果需要安裝到系統中的話,用lib_LTLIBRARIES
註意:靜態庫編譯連接時需要其它的庫的話,采用XXXX_LIBADD選項,而不是前面的XXXX_LDADD。編譯靜態庫是比較簡單的,因為直接可以指定其類型。

動態庫文件

想要編譯XXX.so文件,需要用_PROGRAMS類型,這裏一個關於安裝路徑要註意的問題是,我們一般希望將動態庫安裝到lib目錄下,按照前面所討論的,只需要寫成lib_PROGRAMS就可以了,因為前面的lib表示安裝路徑,但是automake不允許這麽直接定義,可以采用下面的辦法,也是將動態庫安裝到lib目錄下

projectlibdir=$(libdir) //新建一個目錄,就是該目錄就是lib目錄  
projectlib_PROGRAMS=project.so  
project_so_SOURCES=xxx.C  
project_so_LDFLAGS=-shared -fpic //GCC編譯動態庫的選項  

SUBDIRS的用法

這是一個很重要的關鍵詞,我們前面生成了一個一個的目標文件,但是一個大型的工程項目是由許多個可執行文件和庫文件組成,也就是包含多個目錄,每個目錄下都有用於生成該目錄下的目標文件的Makefile.am文件,但頂層目錄是如何調用,才能使下面各個目錄分別生成自己的目標文件呢?就是SUBDIRS關鍵詞的用法了。

看一下我的工程項目,這是頂層的Makefile.am文件

EXTRA_DIST = Doxyfile.in README.win32 README.protocol contrib UPGRADE  
  
devicedir = ${prefix}/device  
device_DATA = package  
  
SUBDIRS = etc man  
if USE_LIBSUBST  
SUBDIRS += subst  
endif  
SUBDIRS += tools io sessions util client dispatch server hash storage sms  

UBDIRS表示在處理目錄之前,要遞歸處理哪些子目錄,這裏還要註意處理的順序。比如我的client對sessions和utils這兩上目標文件有依賴,就在client之前需要處理這兩個目標文件。
EXTRA_DIST:將哪些文件一起打包。

Makefile.am文件配置