automake命令

automake 命令 #

automake是 GNU 构建系统的一部分,用于从Makefile.am文件自动生成符合 GNU 编码标准的Makefile.in文件。它与autoconf配合使用,简化了跨平台软件包的构建系统创建过程。

语法 #

automake [选项]... [Makefile]...

常用选项 #

选项 描述
--help 显示帮助信息
--version 显示版本信息
-a, --add-missing 添加缺少的标准文件到包中
-c, --copy 复制而不是创建符号链接
-f, --force-missing 强制更新标准文件
-i, --ignore-deps 禁用依赖项跟踪
-v, --verbose 启用详细输出
-W 类别 报告指定类别的警告
--foreign 放宽 GNU 标准要求
--gnits 严格遵守 GNU 标准
--gnu 遵守 GNU 标准(默认)
--include-deps 包含自动生成的依赖项
--no-force 不强制更新生成的文件
--output-dir=目录 将文件放在指定目录中
--strictness=类型 设置严格程度(gnu, gnits, foreign)

基本用法 #

1. 生成 Makefile.in 文件 #

automake

这将处理当前目录中的Makefile.am文件,并生成Makefile.in文件。

2. 添加缺少的标准文件 #

automake --add-missing

这将添加缺少的标准文件(如install-shmissing等)到项目中。

3. 使用外国模式(较少限制) #

automake --foreign

这将放宽 GNU 标准要求,适用于非 GNU 项目。

4. 强制更新所有文件 #

automake --force-missing --add-missing

5. 为特定 Makefile.am 生成 Makefile.in #

automake src/Makefile

Makefile.am 基本结构 #

Makefile.am是 automake 的主要输入文件,它使用一种增强的 Makefile 语法来描述项目的构建规则。以下是一个基本的Makefile.am文件结构:

# 定义要构建的程序
bin_PROGRAMS = myprogram

# 定义程序的源文件
myprogram_SOURCES = main.c utils.c

# 定义编译标志
myprogram_CFLAGS = -Wall -O2

# 定义链接标志
myprogram_LDFLAGS = -lm

# 定义要安装的头文件
include_HEADERS = myprogram.h

# 定义要安装的数据文件
data_DATA = config.data

# 定义要安装的文档
doc_DATA = README.md

# 定义子目录
SUBDIRS = src lib doc

常用变量和前缀 #

1. 主要安装目录变量 #

变量前缀 安装目录 描述
bin_ $(bindir) 可执行程序
sbin_ $(sbindir) 系统管理员可执行程序
lib_ $(libdir) 库文件
include_ $(includedir) 头文件
data_ $(datadir) 架构无关的数据文件
pkgdata_ $(pkgdatadir) 特定于包的数据文件
sysconf_ $(sysconfdir) 配置文件
sharedstate_ $(sharedstatedir) 修改的架构无关数据
localstate_ $(localstatedir) 修改的架构无关数据(本地)
pkglib_ $(pkglibdir) 特定于包的库文件
pkginclude_ $(pkgincludedir) 特定于包的头文件
pkgsysconf_ $(pkgsysconfdir) 特定于包的配置文件
doc_ $(docdir) 文档文件
info_ $(infodir) Info 文档
html_ $(htmldir) HTML 文档
dvi_ $(dvidir) DVI 文档
pdf_ $(pdfdir) PDF 文档
ps_ $(psdir) PostScript 文档
man_ $(mandir) Man 页面
noinst_ 不安装 不安装但会构建
check_ 不安装 仅在运行测试时构建

2. 主要基本类型 #

类型 描述
PROGRAMS 可执行程序
LIBRARIES 静态库
LTLIBRARIES Libtool 库(静态或共享)
HEADERS 头文件
SCRIPTS 脚本
DATA 数据文件
MANS Man 页面
TEXINFOS Texinfo 文档

3. 目标特定变量 #

变量后缀 描述
_SOURCES 源文件列表
_CFLAGS C 编译标志
_CXXFLAGS C++编译标志
_CPPFLAGS 预处理器标志
_LDFLAGS 链接器标志
_LDADD 链接时添加的对象文件或库
_LIBADD 添加到库的对象文件或库
_DEPENDENCIES 额外的依赖项

4. 全局变量 #

变量 描述
SUBDIRS 要递归处理的子目录
DIST_SUBDIRS 分发时包含的子目录
EXTRA_DIST 额外的分发文件
CLEANFILES make clean 时要删除的文件
DISTCLEANFILES make distclean 时要删除的文件
MAINTAINERCLEANFILES make maintainer-clean 时要删除的文件
AM_CFLAGS 全局 C 编译标志
AM_CXXFLAGS 全局 C++编译标志
AM_CPPFLAGS 全局预处理器标志
AM_LDFLAGS 全局链接器标志
ACLOCAL_AMFLAGS aclocal 的标志
AUTOMAKE_OPTIONS automake 选项

高级用法 #

1. 构建和安装程序 #

# 定义要构建的程序
bin_PROGRAMS = program1 program2

# 定义每个程序的源文件
program1_SOURCES = main1.c utils.c
program2_SOURCES = main2.c utils.c

# 定义编译标志
program1_CFLAGS = -DPROGRAM1 -Wall
program2_CFLAGS = -DPROGRAM2 -Wall

# 定义链接标志
program1_LDADD = -lm
program2_LDADD = -lm -lpthread

2. 构建和安装库 #

# 静态库
lib_LIBRARIES = libstatic.a
libstatic_a_SOURCES = lib1.c lib2.c

# Libtool库(可以是静态或共享的)
lib_LTLIBRARIES = libshared.la
libshared_la_SOURCES = lib1.c lib2.c
libshared_la_LDFLAGS = -version-info 1:0:0

3. 条件构建 #

configure.ac中:

AM_CONDITIONAL([ENABLE_FEATURE], [test "x$enable_feature" = xyes])

Makefile.am中:

if ENABLE_FEATURE
bin_PROGRAMS = feature_program
feature_program_SOURCES = feature.c
else
bin_PROGRAMS = basic_program
basic_program_SOURCES = basic.c
endif

4. 构建多个目录 #

顶层Makefile.am

SUBDIRS = lib src doc tests

lib/Makefile.am

lib_LTLIBRARIES = libmylib.la
libmylib_la_SOURCES = lib1.c lib2.c

src/Makefile.am

bin_PROGRAMS = myprogram
myprogram_SOURCES = main.c
myprogram_LDADD = ../lib/libmylib.la

5. 安装数据文件 #

# 安装配置文件
sysconf_DATA = config.conf

# 安装特定于包的数据文件
pkgdata_DATA = data1.dat data2.dat

# 安装图标
icondir = $(datadir)/icons
icon_DATA = app.png

6. 自定义安装目录 #

# 定义自定义目录
myappdir = $(datadir)/myapp
myapp_DATA = data.xml

# 定义自定义脚本目录
myappscriptdir = $(libexecdir)/myapp
myappscript_SCRIPTS = helper.sh

7. 使用构建钩子 #

# 在所有目标之前运行
all-local:
	@echo "Building all targets"

# 在安装之前运行
install-data-local:
	$(MKDIR_P) $(DESTDIR)$(datadir)/myapp/extra
	$(INSTALL_DATA) extra.dat $(DESTDIR)$(datadir)/myapp/extra/

# 在卸载之前运行
uninstall-local:
	rm -f $(DESTDIR)$(datadir)/myapp/extra/extra.dat
	-rmdir $(DESTDIR)$(datadir)/myapp/extra

8. 分发额外文件 #

# 添加额外文件到分发包
EXTRA_DIST = README.md LICENSE contrib scripts

# 不分发某些文件
dist-hook:
	rm -rf $(distdir)/contrib/private

实用示例 #

1. 简单的可执行程序 #

bin_PROGRAMS = hello
hello_SOURCES = hello.c
hello_CFLAGS = -Wall -O2

2. 多个可执行程序 #

bin_PROGRAMS = prog1 prog2
prog1_SOURCES = main1.c common.c common.h
prog2_SOURCES = main2.c common.c common.h

3. 构建库和使用它的程序 #

# 库
lib_LTLIBRARIES = libmylib.la
libmylib_la_SOURCES = lib.c lib.h
libmylib_la_LDFLAGS = -version-info 1:0:0

# 程序
bin_PROGRAMS = myprog
myprog_SOURCES = main.c
myprog_LDADD = libmylib.la

4. 安装头文件 #

# 公共头文件
include_HEADERS = public.h

# 特定于包的头文件
pkginclude_HEADERS = mylib.h mylib_utils.h

5. 安装数据和配置文件 #

# 配置文件
sysconf_DATA = myapp.conf

# 数据文件
pkgdata_DATA = data/*.xml

# 自定义目录中的数据
resourcesdir = $(datadir)/myapp/resources
resources_DATA = resources/*.png resources/*.svg

6. 构建和运行测试 #

# 测试程序
check_PROGRAMS = test1 test2
test1_SOURCES = test1.c
test2_SOURCES = test2.c

# 测试脚本
TESTS = test1 test2 test3.sh

7. 使用条件编译 #

if ENABLE_GUI
bin_PROGRAMS = myapp-gui
myapp_gui_SOURCES = gui.c common.c
myapp_gui_CFLAGS = $(GTK_CFLAGS)
myapp_gui_LDADD = $(GTK_LIBS)
endif

if ENABLE_CLI
bin_PROGRAMS += myapp-cli
myapp_cli_SOURCES = cli.c common.c
endif

8. 生成源文件 #

BUILT_SOURCES = generated.h

generated.h: generator.sh data.txt
	./generator.sh data.txt > $@

CLEANFILES = generated.h

9. 安装 man 页面 #

# Man页面
man1_MANS = myapp.1
man5_MANS = myapp.conf.5

10. 安装多语言支持 #

# 国际化支持
SUBDIRS = po
EXTRA_DIST = intl

# 设置翻译域
PACKAGE = myapp
localedir = $(datadir)/locale
DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@

常见问题排查 #

1. 缺少标准文件 #

错误:

Makefile.am:1: error: required file './NEWS' not found

解决方案:

# 创建缺少的文件
touch NEWS README AUTHORS ChangeLog

# 或者使用--foreign选项
automake --foreign

2. 未定义的宏 #

错误:

Makefile.am:5: error: variable 'noinst_LIBRARIES' is defined but no program or library has that name

解决方案:

# 确保定义了库的源文件
noinst_LIBRARIES = libtest.a
libtest_a_SOURCES = test.c

3. 源文件找不到 #

错误:

make: *** No rule to make target 'missing_file.c', needed by 'myprogram-missing_file.o'.  Stop.

解决方案:

# 确保所有源文件都存在并正确列出
myprogram_SOURCES = existing_file.c

4. 子目录问题 #

错误:

automake: error: cannot open < src/Makefile.am: No such file or directory

解决方案:

# 确保每个列在SUBDIRS中的子目录都有Makefile.am文件
touch src/Makefile.am

5. 版本不匹配 #

错误:

warning: The 'AM_INIT_AUTOMAKE' macro requires version 1.14, but have 1.15.1.

解决方案:

# 更新AM_INIT_AUTOMAKE调用中的版本号
AM_INIT_AUTOMAKE([1.15])

与其他构建系统的比较 #

构建系统 优点 缺点 适用场景
Automake 成熟、广泛支持、标准化 语法复杂、学习曲线陡峭 GNU 项目、需要广泛兼容性的 Unix/Linux 项目
CMake 跨平台、现代语法、IDE 支持 不如 Automake 在 Unix 系统上灵活 跨平台项目、需要 IDE 集成
Meson 快速、简单、现代 相对较新、不如 Automake 成熟 新项目、注重构建速度
SCons Python 语法、灵活 构建速度较慢 Python 项目、需要高度定制的构建系统

提示和技巧 #

1. 使用 autoreconf 简化流程 #

# 一步完成所有autotools步骤
autoreconf -i

2. 使用并行构建 #

configure.ac中:

# 启用并行构建支持
AM_INIT_AUTOMAKE([parallel-tests])

3. 使用静默规则 #

configure.ac中:

# 使用静默规则
AM_SILENT_RULES([yes])

这将使构建输出更简洁,只显示正在执行的操作,而不是完整的命令行。

4. 使用通配符 #

# 使用通配符匹配源文件
myprogram_SOURCES = $(wildcard *.c)

5. 使用变量替换 #

# 从C文件生成对象文件列表
SOURCES = file1.c file2.c file3.c
OBJECTS = $(SOURCES:.c=.o)

6. 使用自定义规则 #

# 自定义规则生成文件
%.c: %.y
	$(YACC) $(YFLAGS) -o $@ $<

# 确保自动生成的文件被清理
CLEANFILES = $(wildcard *.tab.c)

7. 使用递归变量和即时变量 #

# 递归变量(在使用时展开)
RECURSIVE = $(SOURCES:.c=.o)

# 即时变量(在定义时展开)
IMMEDIATE := $(SOURCES:.c=.o)

扩展阅读 #