
背景
最近接手一个老项目,项目结构大体示意如下:
project
├── packaging
│ ├── Makefile
│ └── project.spec
└── src
├── knot-2.3.1
│ ├── aclocal.m4
│ ├── ar-lib
│ ├── compile
│ ├── config.guess
│ ├── config.sub
│ ├── configure
│ ├── configure.ac
│ ├── depcomp
│ ├── install-sh
│ ├── libtap
│ ├── ltmain.sh
│ ├── m4
│ ├── Makefile.am
│ ├── Makefile.in
│ └── missing
└── Makefile
项目目录中包含了第三方的项目 knot-2.3.1(knot 是什么不重要,重要的是它用了autotools)。src 目录下的 Makefile 中,调用了 knot 的编译流程:
knot:
cd ${KNOT_DIR}/..; \
./configure; \
make
位于 packaging 下的 Makefile 是用来生成 rpm 安装包的,部分内容如下:
packaging/Makefile:
all: rpm
rpm: $(TARBALL)
@mkdir -p {BUILD,BUILDROOT,SRPMS,SPECS}
@rpmbuild –define “_topdir ${PWD}” –define “_sourcedir ${PWD}” \
–define “buildroot ${PWD}/BUILDROOT” –define “_rpmdir ${PWD}” -ba ${SPECFILE}
$(TARBALL):
@rm -rf $(PKG_NAME)-$(PKG_VERSION)
cd ${PROJ_ROOT}/.. && git archive –format=tar –prefix=/ $(TAG) src | gzip >packaging/${TARBALL}
@rm -rf $(PKG_NAME)-$(PKG_VERSION)
由于项目是通过 git 进行版本控制,这里通过 git 对项目的 src 目录进行打包,然后运行 rpmbuild 编译成 rpm 包。
按道理说,在 packaging 目录下编译和在 src 目录下编译,出了是否打包成 rpm 之外,都是完全一样的。然而,实际操作后发现,在 packaging 下可以正常编译,而在 src 目录下运行 make 会报一个错误:
/project/src/knotdb/knot-2.3.1/missing: line 81: aclocal-1.15: command not found
WARNING: 'aclocal-1.15' is missing on your system.
You should only need it if you modified 'acinclude.m4' or
'configure.ac' or m4 files included by 'configure.ac'.
The 'aclocal' program is part of the GNU Automake package:
<http://www.gnu.org/software/automake>
It also requires GNU Autoconf, GNU m4 and Perl in order to run:
<http://www.gnu.org/software/autoconf>
<http://www.gnu.org/software/m4/>
<http://www.perl.org/>
问题分析
只看错误提示,会以为这是一个 aclocal 版本不符的问题,于是会想到升级 aclocal 到 1.15 版本。但是这样做就掉坑里了,想想看为什么 packaging 里面能正常编译通过?明明是一模一样的项目文件,对不对?我甚至在 packaging 编译过程中提取 tar 包,与外面的 src 做 diff,确实文件内容都是完全一致的。那么问题出在哪里?
其实这个网上也有人遇到过了,比如这个How to overcome“’aclocal-1.15′ is missing on your system”warning when compiling?。导致相同文件编译却一个成功一个报错的原因,是两份项目文件的时间戳不一致。
由于项目代码通过 git 管理,而 git 不保存文件的时间戳信息,导致 autotools 的某些脚本被认为过期,make的时候会重新生成; 而由 tar 解压来的文件,时间戳都是最新的,不会重新生成,这就导致了编译行为差异。
解决方法
知道了原因,只要更新编译脚本的时间戳就可以了。
touch --date="`date`" aclocal.m4 Makefile.am configure Makefile.in