让Makefile自动推导依赖关系

时间:2021-07-26 12:48:58

用到4个文件:hello.h hello.cpp main.cpp Makefile

hello.h

#ifndef MAKE_FILE_TEST
#define MAKE_FILE_TEST

void hello();
#endif

hello.cpp

#include <iostream>
#include "hello.h"
using namespace std;


void hello()
{
	cout<<"hello Makefile!"<<endl;
}

main.cpp

#include "hello.h"

int main()
{
	hello();
	return 0;
}

Makefile

cc=g++
target=main

$(target):main.o hello.o
	$(cc) -o $(target) main.o hello.o
main.o:main.cpp
	$(cc) -c -o main.o main.cpp
hello.o:hello.cpp
	$(cc) -c -o hello.o hello.cpp

.PHONY:clean
clean:
	-rm -f $(target) *.o

执行make,会生成main程序,一切OK。

但是如果我们把hello.h中的void hello();注释掉,再次make,将会出现

make: `main' is up to date.
正常情况下,是会出错的,因为main.cpp虽然包含了hello.h,但是展开hello.h之后,并没有void hello();这个函数声明,main.cpp会出现一个编译错误。但是这里的情况是所有的源文件(.CPP)都没有被重新编译,因为他们我们的makefile的规则中,没有指明这些源文件依赖了hello.h。

当然,我们可以修改Makefile,指明源文件依赖了hello.h。

cc=g++
target=main

$(target):main.o hello.o
	$(cc) -o $(target) main.o hello.o
main.o:main.cpp hello.h
	$(cc) -c -o main.o main.cpp
hello.o:hello.cpp hello.h
	$(cc) -c -o hello.o hello.cpp

.PHONY:clean
clean:
	-rm -f $(target) *.o
分别在main.o:main.cpp 和hello.o:hello.cpp后面添加了hello.h,指明这两个源文件依赖了hello.h。

执行make

g++ -c -o main.o main.cpp
main.cpp: In function ‘int main()’:
main.cpp:5:8: error: ‘hello’ was not declared in this scope
make: *** [main.o] Error 1
OK,错误出现了。

这个反例只是为了说明如何做,才能让头文件被修改时,依赖这个头文件的源文件被重新编译。

但是,如果一个工程中有几百个头文件(.h)和几百个源文件(.cpp),再假设这个工程根本不是自己写的,那该怎么办?难道打开所有的cpp文件看看他们包含了哪些头文件???


还好,编译器可以自动推导出来cpp依赖的头文件。

root@ubuntu:/home/workspace/Makefile/mf2# arm-linux-gcc -MM hello.cpp 
hello.o: hello.cpp hello.h
root@ubuntu:/home/workspace/Makefile/mf2# g++ -MM hello.cpp
hello.o: hello.cpp hello.h
root@ubuntu:/home/workspace/Makefile/mf2# gcc -MM hello.cpp
hello.o: hello.cpp hello.h
root@ubuntu:/home/workspace/Makefile/mf2# cc -MM hello.cpp
hello.o: hello.cpp hello.h
可以看到,-MM选项可以让编译器去推敲依赖的文件。

继续往下之前,先来一个小插曲。Makefile可以自动推导编译命令,把hello.h中的void hello(); 取消注释。修改Makefile如下:

cc=g++
target=main

$(target):main.o hello.o
	$(cc) -o $(target) main.o hello.o
main.o:main.cpp hello.h
hello.o:hello.cpp hello.h

.PHONY:clean
clean:
	-rm -f $(target) *.o
执行make clean,然后make,可以看到程序被正确编译了。

root@ubuntu:/home/workspace/Makefile/mf2# make clean
rm -f main *.o
root@ubuntu:/home/workspace/Makefile/mf2# make
g++    -c -o main.o main.cpp
g++    -c -o hello.o hello.cpp
g++ -o main main.o hello.o
注意:目标规则中编译命令不能省略。即$(cc) -o $(target) main.o hello.o不能省略。这条命令中指明的编译器将是自动推敲出来的命令使用的编译器。

因为我们使用的是g++,所以自动推导出来的命令也使用g++。


OK,小插曲结束,继续。

利用-MM推敲依赖文件,修改Makefile。

cc=g++
target=main
src=main.cpp hello.cpp

$(target):main.o hello.o
	$(cc) -o $(target) main.o hello.o

include $(src:.cpp=.d)
%.d:%.cpp
	set -e;rm -f $@;\
	$(cc) -MM $< >$@

.PHONY:clean
clean:
	-rm -f $(target) *.o
思路已断,未完待续