Makefile自动产生依赖文件(一)

一直以来用Makefile自动产生源文件(C/C++)的关联文件(.d)是一大问题。这里主要涉及到的是gcc的-MM选项(-M会包含系统头文件)。但gcc的-MM不是很完美,主要涉及到两方面:

  1. 没有目标文件路径

    g++ -MM src/string_parse.cpp
    

    输出:

    string_parse.o: src/string_parse.cpp src/string_parse.h
    

    而我们需要的是:

    src/string_parse.o: src/string_parse.cpp src/string_parse.h
    
  2. 头文件重命名时出现错误

    万一我们重命名了string_parse.h为string_other_parse.h则

    string_parse.o: src/string_parse.cpp src/string_other_parse.h
    

    make会找不到依赖文件str/string_other_parse.h报错。

参考网上的方案,我的解决方法是写个makedepend脚本处理:

#!/usr/bin/env bash
# Generate C/C++ file make depend file: Makefile.depends.
# Usage:
#   makedepend -f files -c (gcc|g++) -p flags

help() 
{
    echo "${0#*/} -f files -c (gcc|g++) -p flags"
}

while getopts "hf:c:p:" opt; do
    case $opt in
        h)
            help
            exit 0
            ;;
        f)
            files=$OPTARG
            ;;

        c)
            compiler=$OPTARG
            ;;

        p)
            flags=$OPTARG
            ;;
        *)
            exit 1
            ;;
    esac
done


if [ -z "$files" ] || [ -z "$compiler" ] || [ -z "$flags" ] ; then
    exit 1
fi

for file in $files
do
    obj="${file%.*}.o"
    result=`$compiler -MM $flags $file`
    if [ $? != 0 ] ; then
        exit 1
    fi

    result=${result/*:/$obj:}
    echo $result | sed -e 's/\//g'
    # add all file as target, so rename file will not error.
    echo $result | sed -e 's/.*://' -e 's/\//g' | fmt -1 | sed -e 's/^ *//' -e 's/$/:/'
done

在Makefile是这么用的:

Makefile.deps: $(FILES) $(HEADERS)
    makedepend -f "$(FILES)" -c "$(CXX)" -p "$(CPPFLAGS)" >$@

最后生成的Makefile.deps是这样的:

src/string_parse.o: src/string_parse.cpp src/string_parse.h
src/string_parse.cpp:
src/string_parse.h:

为了防止修改文件名后找不到,makedepend为每个依赖文件都建了一个空规则,make如果找不到文件,可以在这里找到。由于文件不存在,成为了伪目标,而伪目标永远是最新的,从而触发编译命令

参考:

陈皓的《跟我一起写Makefile》

Autodependencies with GNU make

http://blog.vjeux.com/category/makefile

1 thought on “Makefile自动产生依赖文件(一)

  1. Pingback引用通告: Makefile自动产生依赖文件(二) | 波波的博客

发表评论

电子邮件地址不会被公开。 必填项已用*标注