手寫 Makefile 痛苦且難移植。GNU Build System (Autoconf + Automake + Libtool) 讓專案支援標準 ./configure && make && make install 三步安裝。本文以 HelloWorld.cpp 為例,完整演示從 autoscan 到生成 Makefile 的標準化流程,並深度解析 Makefile.am 編寫規則與打包發布。
| 工具 | 角色 |
|---|---|
autoscan | 掃描原始碼 → 生成 configure.scan |
autoconf | 處理 configure.ac → 生成 configure 腳本 |
automake | 處理 Makefile.am → 生成 Makefile.in |
aclocal | 展開 configure.ac 巨集 → aclocal.m4 |
autoheader | 生成 config.h.in |
libtool | 跨平台程式庫建立 |
autoscan → configure.scanmv configure.scan configure.ac,編輯巨集aclocal → aclocal.m4autoheader → config.h.inautoconf → configure (可執行)Makefile.amautomake --add-missing → Makefile.in + 缺失檔案 (NEWS/README/ChangeLog/AUTHORS)./configure → MakefileAC_PREREQ([2.69])
AC_INIT([HelloWorld], [1.0], [postmaster@126.com])
AC_CONFIG_SRCDIR([HelloWorld.cpp])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE([HelloWorld], [1.0])
AC_PROG_CXX
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
| 前綴 | 含義 | 安裝目標 |
|---|---|---|
bin_ | 可執行檔 | $(bindir) (/usr/local/bin) |
lib_ | 靜態/動態庫 | $(libdir) (/usr/local/lib) |
noinst_ | 不安裝,僅建置 | — |
include_ | 頭檔 | $(includedir) (/usr/local/include) |
data_ | 資料檔 | $(datadir) (/usr/local/share) |
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
client_LDADD = $(top_builddir)/sx/libsession.a $(top_builddir)/util/libutil.a
projectlibdir = $(libdir)
projectlib_PROGRAMS = project.so
project_so_SOURCES = xxx.c
project_so_LDFLAGS = -shared -fPIC
noinst_LTLIBRARIES = libutil.la
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
noinst_HEADERS = inaddr.h util.h compat.h pool.h xhash.h url.h device.h
LTLIBRARIES (Libtool) 而非 LIBRARIES,跨平台零修改_HEADERS 宣告,否則 make dist 不會打包prefix = /usr/local
bindir = $(prefix)/bin
libdir = $(prefix)/lib
includedir = $(prefix)/include
sysconfdir = $(prefix)/etc
datadir = $(prefix)/share
# 自訂路徑
sysdatedir = $(prefix)/sysdate
sysdate_DATA = data1 data2
make dist
# 生成 HelloWorld-1.0.tar.gz
# 內含:所有原始碼、Makefile.am、configure 相關檔、EXTRA_DIST 指定檔
nodist_client_SOURCES = client.c 排除特定檔案EXTRA_DIST = README.md LICENSE 額外納入# 1. 建立專案
mkdir helloworld && cd helloworld
cat > HelloWorld.cpp <<'EOF'
#include
using namespace std;
int main() { cout << "Hello World" << endl; return 0; }
EOF
# 2. autoscan
autoscan
mv configure.scan configure.ac
# 編輯 configure.ac (見上)
# 3. aclocal
aclocal
# 4. autoheader
autoheader
# 5. autoconf
autoconf
# 6. Makefile.am
cat > Makefile.am <<'EOF'
AUTOMAKE_OPTIONS = foreign
bin_PROGRAMS = HelloWorld
HelloWorld_SOURCES = HelloWorld.cpp
EOF
# 7. automake
automake --add-missing
# 提示缺檔案
touch NEWS README ChangeLog AUTHORS
automake --add-missing
# 8. configure
./configure
# 生成 Makefile
# 9. 建置安裝
make
make install # 安裝至 /usr/local/bin/HelloWorld
Autotools 學習曲線陡峭,但一次掌握,終身受用。標準化建置系統是開源專案專業度的門檻,也是跨平台移植的基石。