Makefile.am中如何自动配置foo_HEADERS包含所有.h文件?
原项目中,Makefile.am需要手动列出指定目录下数百个头文件:
foo_HEADERS = file1.h file2.h ...
随着项目迭代,新增头文件需要自动纳入,但Makefile的$(wildcard)无法满足需求(该Makefile是configure.ac中AC_CONFIG_FILES的目标文件)。
我提出的现有方案:
- 在Makefile.am中配置:
foo_HEADERS = @FOO_INCLUDE_HFILES@ EXTRA_HEADERS =
- 在configure.ac中添加自动生成头文件列表的逻辑:
# 构建$(srcdir)/include/foo下所有.h文件列表,替代无法正常工作的make变量$(wildcard) ac_include_foo_h_files=`ls $srcdir/include/foo/*.h` ac_include_foo_h_files=`basename -a $ac_include_foo_h_files` AC_SUBST(FOO_INCLUDE_HFILES, "`echo $ac_include_foo_h_files`")
该方案可正常运行,但存在两个疑问:
- 是否有更通用的方案替代
ls、basename -a、echo的用法? - 若采用该方案,为何必须在Makefile.am中设置
EXTRA_HEADERS =?
1. 跨平台通用替代方案
你当前用的ls、basename -a依赖GNU工具的扩展特性,比如basename -a在BSD系统上就不支持,而且ls处理带空格的文件名容易出问题。更通用的方式是用纯Shell循环实现,完全不依赖非标准工具,所有Autotools支持的系统都能跑:
替换configure.ac里的代码为:
ac_include_foo_h_files="" # 遍历目标目录下的.h文件 for file in "$srcdir/include/foo"/*.h; do # 处理目录下没有.h文件的情况(避免通配符原样输出) [ -f "$file" ] || continue # 用Shell内置语法提取文件名,替代basename filename="${file##*/}" # 拼接成空格分隔的列表 ac_include_foo_h_files="$ac_include_foo_h_files $filename" done # 去掉开头多余的空格 ac_include_foo_h_files="${ac_include_foo_h_files# }" AC_SUBST(FOO_INCLUDE_HFILES, "$ac_include_foo_h_files")
这种写法没有任何外部工具依赖,还能正确处理含特殊字符(比如空格)的文件名,兼容性拉满。
2. 为何要设置EXTRA_HEADERS =
核心是阻止Automake自动扫描头文件。
Automake默认会自动扫描当前Makefile.am所在目录下的所有.h文件,把没被任何_HEADERS变量包含的文件加到EXTRA_HEADERS里。但你的头文件在$(srcdir)/include/foo目录,不在当前目录,Automake扫不到;同时如果当前目录有其他头文件,反而会被错误加进来。
设置EXTRA_HEADERS =(空值)会强制关闭这个自动扫描行为,确保只有你通过@FOO_INCLUDE_HFILES@指定的头文件被纳入foo_HEADERS。另外,运行make dist打包分发版时,Automake会把EXTRA_HEADERS或_HEADERS里的文件都打包,空的EXTRA_HEADERS配合你生成的列表,能保证include/foo下的头文件不会被漏掉。
内容的提问来源于stack exchange,提问作者emacs drives me nuts

