Linux下跨机构建后如何防止make触发项目不必要重编译
问题根因
make判定是否需要重编译的核心逻辑是对比目标文件(.o、库、可执行文件)和依赖文件(源码、头文件、Makefile、配置文件)的修改时间戳,只要目标文件不存在、时间戳早于依赖文件、或者构建命令和上次记录的不一致,就会触发重编,对应这个场景,全量重编基本是以下几个原因导致的:
- 时间戳异常:虽然同步了两台机器的系统时间,但rsync传输时如果源端文件系统是纳秒级精度(现代ext4/XFS默认),目标嵌入式设备用的是低精度文件系统(比如UBIFS、FAT、老版ext3仅支持秒级/2秒级精度),时间戳截断后会出现大量目标文件时间戳早于依赖文件的情况;如果是同步完系统时间才做的服务器端构建,时间回拨也会导致时间戳逻辑混乱。
- 构建规则校验触发重编:libssh2 1.4.0基于autotools构建,生成的Makefile会硬编码交叉编译阶段的编译器路径、编译参数,还会自动校验构建命令是否和上次一致。构建目录拷到目标机后,默认调用的是本地原生编译器,和之前记录的交叉编译器路径、参数完全不匹配,make会直接判定所有目标失效触发全量重编。如果目标机上存放构建目录的绝对路径和服务器上构建时的路径不一致,也会触发部分规则的重编逻辑。
- Makefile自更新触发连锁重编:autotools生成的Makefile默认会在检测到configure.ac、Makefile.am等文件存在时,自动重新生成Makefile本身,一旦Makefile被重写,所有目标都会被判定需要重编。
解决操作
按顺序操作即可避免全量重编:
- 修正rsync传输逻辑,显式保证时间戳正确传输,避免属性带来的干扰:
传输完成后登录目标机,进入构建目录,给所有已编译好的库、目标文件刷最新时间戳,确保其时间晚于所有源码、配置文件:rsync -aHAXt --numeric-ids libssh2-1.4.0 user@machine:/path/to/package/cd /path/to/package/libssh2-1.4.0 find . -type f \( -name "*.o" -o -name "*.a" -o -name "*.so*" -path "*/src/*" \) -exec touch {} \; - 执行make check时显式屏蔽不必要的重编规则,注意把CC、CFLAGS、LDFLAGS替换成交叉编译时用的实际参数,仅把编译器名换成目标机本地的gcc即可,不需要重新执行configure:
命令里的make -o Makefile -o config.h -o configure CC=gcc CFLAGS="原编译参数" LDFLAGS="原链接参数" check-o 文件名是告诉make,指定的文件就算时间戳更新也不要判定为过期,不会触发Makefile、config.h相关的连锁重编。 - 如果上述操作后还是触发源码重编,直接加参数告诉make忽略所有源码、头文件的改动,只构建缺失的测试程序即可:
这个参数会让make跳过所有已有.o文件对应的源码重编步骤,只会编译tests目录下还没生成的测试可执行文件,完全不会重编已经构建好的libssh2库代码。make --assume-old=*.c --assume-old=*.h check
内容的提问来源于stack exchange,提问作者Mixen
相关产品推荐
相关产品推荐

