导航

一个简单的makefile文件

Posted on 2017-05-09 00:16  mxrmber  阅读(195)  评论(0)    收藏  举报

  关于makefile的介绍可以看这里,很经典的教程:http://blog.csdn.net/haoel/article/details/2886。

  刚刚从windows平台切换到linux平台下来写c++代码,选择vim作为代码的编辑器,因此自然而然就接触到了makefile。

因为现在写的也仅仅是小型的玩具级工程,所以目前对makefile的要求也比较低一些,只要能应对即使随意在工程中添加或者删除文件,

随意修改源文件对头文件的引用,也无需修改makefile的内容只要敲一个make命令也照样能编译好工程就可以,主要是为了方便。

  现在假设整个工程的文件只有三个 main.cpp foo.h foo.cpp

  看了以上链接地址中的教程,很容易能写出一个简单的makefile来:

CC = g++
Output = main.out 

$(Output) : main.o foo.o
    $(CC) -o $(Output) main.o foo.o

main.o: main.cpp
    $(CC) -c main.cpp

foo.o : foo.cpp foo.h
    $(CC) -c foo.cpp

.PHONY : clean
clean:
    -rm  *.o
    -rm  *.out 

 

   这样写的好处是看起来很清晰,一目了然哪个文件依赖于哪些文件,但是也有不方便的地方,

假如这个时候要向工程中添加两个文件:bar.cpp bar.h呢,那在编译整个工程的时候还是得需要再去修改makefile中的内容。

对于这种情况也是有解决办法的,利用makefile中的函数,如下:

  

CC = g++
Output = main.out 

Objects = $(patsubst %.cpp, %.o, $(wildcard *.cpp))  #列举当前路径下所有以".cpp"为后缀的文件,把.cpp替换成.o 展开来就是 Objects = main.o foo.o

$(Output) : $(Objects)
	$(CC) -o $(Output) $(Objects)

.PHONY : clean
clean:
	-rm  *.o
	-rm  *.out 

   以上这种方法利用了makefile的函数,以及其自动推导的功能,所以 main.o和foo.o的依赖关系不需要显示地写出来。

这样写了之后我们就可以在工程文件中随意地添加和删除文件而无需再去修改makefile文件了,但是这样的写法遇到如下的场景就比较无力,

比如,现在要向工程中添加一个头文件 define.h, 在main.cpp 中引用该头文件。按照以上的写法makefile推导出来的依赖关系为  main.o : main.cpp

而实际为 main.o : main.cpp define.h ,这样就造成一个问题,假如我们改写了define.h中的内容,在重新编译的时候只敲一个"make" 命令,

make会提示我们: *** is up to date,意思是所有的文件都是最新的,无需重新编译,可是我们分明已经改了其中一个文件了。这种问题可以在每个目标

文件的依赖文件里面添加所有需要用到的头文件去解决。但是这样就不够精确。比较精确一点的做法为利用g++编译器帮助我们生成每个目标文件的依赖关系。

  在Ubuntu下可以用 g++ -MM main.cpp 的方式来查看main.o 的依赖关系。这个就是比较精确的。

  所以解决以上问题的思路就是利用编译器的功能,结合makefile中include的作用来实现:

cc = g++ 
Output = main.out

$(Output) : $(patsubst %.cpp, %.o, $(wildcard *.cpp)) $(patsubst %.cpp, %.d, $(wildcard *.cpp))
	$(cc) -o $(Output) $(patsubst %.cpp, %.o, $(wildcard *.cpp))

%.d : %.cpp
	$(cc) -MM -std=c++11 $< > $@.$$$$;\    #生成每个对象文件的依赖关系写入临时文件
	sed -e 'a \	$(cc) -c -std=c++11 $<' $@.$$$$ > $@;\ #在临时文件中添加命令,为的是实现非默认以外的指令,例如默认情况下 g++ 编译时候并没有 -std=c++11的
                                      #选项,那么在源码中引用c++11中的特性时,makefile默认提供的指令就无法工作。 rm -f $@.$$$$    #删除临时文件 -include $(patsubst %.cpp, %.d, $(wildcard *.cpp)) .PHONY : clean clean: -rm *.o -rm *.out -rm *.d

   以上是自己这两天对makefile学习的一些总结,并不是零基础的教程,详细的教程还是去看链接地址中的教程,非常经典。