系列文章:
automake學(xué)習(xí)筆記 - helloworld
automake學(xué)習(xí)筆記 - 模塊化編譯
automake學(xué)習(xí)筆記 - 安裝與發(fā)布
automake學(xué)習(xí)筆記 - 交叉編譯
一般來說一個工程會由許多不同的模塊組成鳖眼。源碼放在一個地方尝哆,示例代碼放到另一個地方速勇,第三方庫又放到其他地方。這種時候又應(yīng)該怎么去使用automake呢妖啥?
這篇文章就討論了一下如何使用automake去進行模塊化編譯
我們還是用easylog來做例子,下面是我們修改后的easylog工程的根目錄下的文件:
configure.ac examples Makefile.am src
src目錄
src目錄放的就是庫的源代碼,我們使用src中的源代碼編譯出一個庫來給其他的程序使用easylog的功能
src目錄中有下面幾個文件log_interface.h掉房,easy_log.h,easy_log.cpp综苔,cout_log_interface.h酣倾,cout_log_interface.cpp煎饼,Makefile.am讹挎。實際上就是除了main.cpp,其他文件都放到了這里來吆玖。因為我們提供給別的是一個庫而不是一個可執(zhí)行程序筒溃,所以main.cpp可以不需要編譯到目標文件中
.h和.cpp的內(nèi)容和上一篇文章的內(nèi)容是一樣的。這里的重點其實是Makefile.am沾乘。讓我們先來看看它的內(nèi)容:
lib_LTLIBRARIES = libeasylog.la
libeasylog_la_SOURCES = cout_log_interface.cpp \
easy_log.cpp
其實它的內(nèi)容很簡單怜奖,就是指定了要編譯的庫的名字和庫的源碼。但是有一個問題翅阵,我們這里需要編譯的是但為什么這里的目標文件是libeasylog.la呢?
Libtool是一種屬于GNU構(gòu)建系統(tǒng)的GNU程序設(shè)計工具,它將靜態(tài)庫和動態(tài)庫抽象成了一種統(tǒng)一的叫做libtool庫的概念歪玲。libtool庫使用la作為后綴。它可以用來構(gòu)建靜態(tài)庫也能用來構(gòu)建動態(tài)庫掷匠,而最終編譯出來的到底是哪一種滥崩,在最后執(zhí)行configure命令的時候才能確定。同時它編譯的時候產(chǎn)生的文件就不再是.o文件而是.lo文件讹语。
這里lib_LTLIBRARIES的lib前綴表示的就是目標文件是一個動態(tài)庫而不是可執(zhí)行文件(bin前綴表示目標文件是可執(zhí)行文件,noinst_LTLIBRARIES表示目標文件是靜態(tài)庫)钙皮。而LTLIBRARIES的LT指的就是Libtool。還有一點是一般編譯庫文件的話我們會在文件名錢加上lib前綴,所以我們的目標文件是libeasylog.la株灸。
而下面的libeasylog_la_SOURCES就是指定編譯libeasylog.la使用的源代碼
這里順便說一點,如果這里需要鏈接其他的庫的話需要用 _LIBADD 去指定崇摄。如需要鏈接libpthread這個庫的話就需要這樣寫:
libeasylog_la_LIBADD = -lpthread
examples目錄
examples目錄里面放了這個庫的example代碼擎值。因為我們的庫是要提供給其他人使用的慌烧,所以一般除了文檔之外,還會有一些例子去幫助使用者了解應(yīng)該如何去使用我們的庫鸠儿。這個目錄中的example.cpp其實就是上一篇文章中的main.cpp:
#include "easy_log.h"
#include "cout_log_interface.h"
int main()
{
EasyLog log(std::make_shared<COutLogInterface>());
log.Debug("test", "testlog");
return 0;
}
這個目錄下也有一個Makefile.am屹蚊,它是用來配置example程序的編譯選項的:
AM_CPPFLAGS = -I$(top_srcdir)/src
bin_PROGRAMS = example
example_SOURCES = example.cpp
example_LDADD = -L$(top_builddir)/src \
-leasylog
AM_CPPFLAGS的值在c/c++預(yù)處理的時候會當(dāng)做參數(shù)傳給預(yù)處理器例如我們將源碼目錄傳給預(yù)處理器,這樣預(yù)處理器才能找到easy_log.h和cout_log_interface.h
這里的top_srcdir變量會在configure是被定義进每,它的值是工程目錄的位置(也就是configure所在目錄的位置)汹粤,后面的top_builddir也是類似的,不過它的值是編譯目錄的位置(也就是執(zhí)行make命令是所在的目錄)
這里編譯出來的example就是我們的demo程序
根目錄
根目錄下也有個Makefile.am,這個文件的內(nèi)容很簡單:
SUBDIRS = src examples
就是將src和examples指定為子目錄于是在make編譯的時候,編譯器就會進入到這兩個目錄中繼續(xù)編譯田晚。它們在這里的先后順序決定了編譯的先后順序嘱兼。因為examples中的example程序是依賴于easylog庫的,所以要然src先編譯
如果不在這里指定子目錄的話,在編譯目錄執(zhí)行make命令就不會自動編譯子目錄中為源碼,需要自己進到子目錄中手動執(zhí)行make命令。如果工程中的某些部分是可選編譯的時候可以這么做贤徒。
最后就是configure.ac文件了:
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
AC_INIT([easylog], [0.0.2], [466474482@qq.com])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
AC_CONFIG_SRCDIR([src/log_interface.h])
AC_CONFIG_HEADERS([config.h])
AM_PROG_AR
LT_INIT
# Checks for programs.
AC_PROG_CXX
AC_PROG_CC
AX_CXX_COMPILE_STDCXX_11
# Checks for libraries.
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_CONFIG_FILES([Makefile
examples/Makefile
src/Makefile])
AC_OUTPUT
它和上一篇文章只有一點點小的不同:
一是由于將log_interface.h放到src中了芹壕,所以AC_CONFIG_SRCDIR需要改一下
AC_CONFIG_SRCDIR([src/log_interface.h])
二是examples和src中的Makefile.am也需要在configure.ac中指定:
AC_CONFIG_FILES([Makefile
examples/Makefile
src/Makefile])
AC_CONFIG_FILES指定了一些需要從Makefile.in中生成的Makefile。這里如果不指定的話configure就不會為其生成Makefile
三是多了AM_PROG_AR和LT_INIT接奈。如果不定義這兩個宏的話,執(zhí)行autoreconf --install命令得到了下面的錯誤日志:
src/Makefile.am:1: error: Libtool library used but 'LIBTOOL' is undefined
src/Makefile.am:1: The usual way to define 'LIBTOOL' is to add 'LT_INIT'
src/Makefile.am:1: to 'configure.ac' and run 'aclocal' and 'autoconf' again.
src/Makefile.am:1: If 'LT_INIT' is in 'configure.ac', make sure
src/Makefile.am:1: its definition is in aclocal's search path.
automake: warnings are treated as errors
/usr/share/automake-1.15/am/ltlibrary.am: warning: 'libeasylog.la': linking libtool libraries using a non-POSIX
/usr/share/automake-1.15/am/ltlibrary.am: archiver requires 'AM_PROG_AR' in 'configure.ac'
src/Makefile.am:1: while processing Libtool library 'libeasylog.la'
autoreconf: automake failed with exit status: 1
注意AM_PROG_AR 要放在 LT_INIT 之前,要不然 autoreconf --install 的時候會報warn
如果已經(jīng)加上了 LT_INIT 但還是會報錯的話就是系統(tǒng)中沒有安裝libtool了,必須先安裝一下:
sudo apt-get install libtool
編譯工程
在工程根目錄創(chuàng)建子build目錄用于編譯
進入build目錄
執(zhí)行../configure
執(zhí)行make
之后進入build/examples運行example就可以看到下面輸出:
[test] testlog
靜態(tài)庫和動態(tài)庫的區(qū)別
我們之前在src/Makefile.am中生成的是動態(tài)庫lib_LTLIBRARIES,所以如果將build/src目錄刪掉,build/examples/example就會因為找不到庫而報錯:
/home/linjw/workspace/automake-demo/build/examples/.libs/lt-example: error while loading shared libraries: libeasylog.so.0: cannot open shared object file: No such file or directory
但如果將Makefile.am改成生成靜態(tài)庫則不會報錯踢涌,因為靜態(tài)庫將庫的代碼也編譯到可執(zhí)行程序之中了。
noinst_LTLIBRARIES = libeasylog.la
libeasylog_la_SOURCES = cout_log_interface.cpp \
easy_log.cpp
這里的noinst代表的其實是no install的意思
Demo項目
可以在這里查看完整的項目代碼