下面再來看看多個源檔案的例子。
如何寫用code1.c, code2.c產生 prog1的configure.in和Makefile.am。首先建立一個專案檔夾testproj。在testproj下建立dir1目錄。
[kang@node16 kang]$ mkdir testproj
[kang@node16 kang]$ mkdir dir1
然後在dir1目錄中分別建立code1.c, code1.h, code2.c, code2.h,下面原始碼都只由幾個簡單的語句組成,以便說明問題。
下面是code1.h:
#include <stdlib.h>
void foo_a();
下面是code1.c:
#include "code1.h"
void foo_a()
{
printf("This is code1./n");
}
下面是code2.h:
#include <stdlib.h>
void foo_b();
下面是code2.c,這裡讓code.c作為prog1的進入點:
#include "code1.h"
#include "code2.h"
void foo_b()
{
printf("This is code2./n");
}
int main()
{
foo_a();
foo_b();
}
建立好這幾個檔案之後,下面就可以正式建立configure.in和Makefile.am了。
首先在testproj目錄下建立configure.in檔案:
#指定項目的一個源檔案
AC_INIT(dir1/code2.c)
#指定項目名稱和版本號碼
AM_INIT_AUTOMAKE(prog1, 0.0.1)
#檢查編譯器
AC_PROG_CC
#輸出Makefile檔案
AC_OUTPUT(Makefile dir1/Makefile)
同時建立testproj目錄下的Makefile.am檔案,這個檔案很簡單,就一句話:
SUBDIRS=dir1
然後建立dir1目錄下的Makefile.am檔案,這才是真正起作用的Makefile.am檔案:
bin_PROGRAMS=prog1
prog1_SOURCES=code1.c code2.c
完成之後,為了方便操作,再寫一個autogen.sh檔案,儲存在testproj目錄下。
#!/bin/sh
aclocal
automake --add-missing
autoconf
./autogen.sh即可在testproj目錄下產生configure和makefile檔案,同時在dir1目錄下也會產生一個makefile檔案。現在在testproj目錄下執行make,螢幕將顯示如下資訊:
[kang@node16 testproj]$ make
Making all in dir1
make[1]: Entering directory `/home/kang/testproj/dir1'
gcc -DPACKAGE=/"prog1/" -DVERSION=/"0.0.1/" -I. -I. -g -O2 -c code1.c
code1.c:6:2: warning: no newline at end of file
gcc -DPACKAGE=/"prog1/" -DVERSION=/"0.0.1/" -I. -I. -g -O2 -c code2.c
code2.c:13:2: warning: no newline at end of file
gcc -g -O2 -o prog1 code1.o code2.o
make[1]: Leaving directory `/home/kang/testproj/dir1'
make[1]: Entering directory `/home/kang/testproj'
make[1]: Nothing to be done for `all-am'.
make[1]: Leaving directory `/home/kang/testproj'
進入dir1目錄,就可以看到產生的prog1程式。如果再執行make install,prog1將被安裝到預設的/usr/local/bin目錄下去。
這就是一個最簡單的configure.in和Makefile.am的編寫情況。你如果不熟悉,最好自己動手做一遍,複雜的configure.in和Makefile.am都是在這個基礎上擴充的。
在此基礎上,如果要同時實現code1.c, code2.c產生 prog1, 而 code3.c產生prog2。由於code1.c,code2.c,code3.c都在同一個目錄,只要改寫dir1目錄下的Makefile.am就可以了。
為了便於說明問題,首先要在dir1目錄下增加一個code3.h 和code3.c檔案。
下面是code3.h:
#include <stdlib.h>
void foo_c();
下面是code3.c:
#include "code3.h"
void foo_c()
{
printf("This is code3./n");
}
int main()
{
foo_c();
}
然後修改dir1目錄下的Makefile.am檔案:
bin_PROGRAMS=prog1 prog2
prog1_SOURCES=code1.c code2.c
prog2_SOURCES=code3.c
再重新執行一次autogen.sh。make之後,在dir1目錄下就會同時存在prog1和prog2兩個程式。
那麼,兩個處在不同子目錄下的檔案如何共同產生一可執行檔呢?一般互相引用的來源程式都是放在同一個目錄下的,如果要放在不同的目錄,可以把要引用的源檔案編譯成靜態庫檔案。為便於說明問題,準備了如下檔案:
在testproj目錄下建立dir2目錄,儲存code4.h和code4.c檔案。
下面是code4.h:
#include <stdlib.h>
void foo_d();
下面是code4.c:
#include "code1.h"
#include "code4.h"
void foo_d()
{
printf("This is code4./n");
}
int main()
{
foo_a();
foo_d();
}
修改testproj目錄下的configure.in檔案。
#指定項目的一個源檔案
AC_INIT(dir2/code4.c)
#指定項目名稱和版本號碼
AM_INIT_AUTOMAKE(myproject, 0.0.1)
#檢查編譯器
AC_PROG_CC
#檢查ranlib
AC_PROG_RANLIB
#輸出Makefile檔案
AC_OUTPUT(Makefile dir1/Makefile dir2/Makefile)
同時修改testproj目錄下的Makefile.am檔案。
SUBDIRS = dir1 dir2
在dir1目錄下修改Makefile.am檔案。這時是將code1.c編譯成一個不安裝(noinst)的靜態庫檔案。
noinst_LIBRARIES=libcode1.a
libcode1_a_SOURCES=code1.c
在dir2目錄下添加一個Makefile.am檔案。
INCLUDES= -I../dir1
bin_PROGRAMS=prog4
prog4_SOURCES=code4.c
prog4_LDADD=../dir1/libcode1.a
然後執行autogen.sh就可以了。
補充問答。
問題1:如何指定特定的編譯器(AC_PROG_CC只會檢查C編譯器?)?
答:首先在configure.in中加上對特殊編譯器的檢查,如果檢查不到,則configure時會停止並給出“Couldn't find mpicc.”的出錯資訊:
#檢查mpicc編譯器
AC_CHECK_PROG(MPICC,mpicc,yes,no)
if test "$MPICC" = no; then
AC_MSG_ERROR([Couldn't find mpicc.])
fi
然後把需要用mpicc編譯的來源程式放在一個目錄下面。在這個目錄中先用上面的方法寫Makefile.am檔案。然後再加上下面這部分:
CC=mipcc
CFLAGS=
這樣用自己定義的編譯器和編譯標誌取代系統定義的編譯器和編譯標誌。
問題2:因為有部分程式不能公開發布,所以我想將它們產生庫,(*.la, 通過libtool 產生),但我解開產生的壓縮檔,發現庫檔案沒在壓縮檔裡面,所以make的時候會有些函數找不到,產生錯誤。請問如何能讓帶庫檔案的檔案夾也一起包括的壓縮檔裡去呢?
答:如果代碼中用了庫檔案,要先編譯安裝庫檔案,再編譯代碼。你可以把編譯成庫檔案的代碼獨立出來單獨打包,這樣也便於管理。前面給的例子中庫檔案是只編譯不安裝的。下面給一個動態庫安裝的例子。
問題3:我做的Makefile安裝時預設安裝在/usr/local/bin底下,而我想安裝在/usr/sbin下,不知道該怎麼改?
答:這個問題不需要修改configure.in或者Makefile.am檔案。用./configure --help可以看到有一個bindir參數可以指定可執行檔的安裝目錄。你只需要執行./configure --bindir=/usr/sbin就可以了。