Makefile

总结下边的内容 :

  1. 文件中的第一个target是最终目标
  2. 命令列表中的每条命令必须以 Tab 开头
  3. 如果 prerequistes 中如果有一个以上的文件比 target 文件更新的话,command 所定义的命令就会执行,这就是 Makefile 规则
  4. 如果这个工程的头文件改变了,那么我们需要编译引用了这个头文件的C文件,并链接目标程序。
  5. make clean 执行删除文件和所有中间文件。这里要说明,clean, 类似C语言中的 label一样,其冒号后什么也没有,那么,make就不会自动去找文件的依赖性,也就不会自动执行其后所定义的命令,要执行其后的命令,就要在make命令后明显得指出这个label的名字,这样的方法非常有用,我们可以在一个makefile中定义不用的编译或和编译无关的命令,比如程序的打包,程序的备份.
  6. make 会比较 targets 文件和 prerequisits 文件的修改日期,如果 prerequistes 文件的日期要比 targets文件的日期新,或者 target不存在的话,那么,make就会执行后续定义的命令.
  7. make 会一层一层的找文件的依赖关系。知道编译出第一个目标文件。如果在找的过程中,出现问题,那么make 就会自动退出,并报错。但是make只管文件依赖性,比如,编译错误等等问题,make根本不理。即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那我就不工作了。
  8. 自动推到 只要 make 看到一个.o 文件,它就会自动的把 .c 文件加载依赖关系中。所以不需要我们自己指定. 如果一个目标在 Makefile 中的所有规则都没有零零列表,make会尝试在内建的隐含规则 ( Implicit Rule) 数据库中查找适用的规则,所以才会有如下例子中,哪些没有被指定的命令,只是指定了规则的,会执行隐含规则 gcc -c main.c 例如
  9.  all : ( 表示缺省的目标,就是最后目标啦,跟clean,是大家约定俗成的 )
  10. @echo 正在编译 XXX 模块, 当我们用 “@”字符在命令行前,那么,这个命令将不被make显示出来。这个例子,当make执行时,会输出”正在编译 XXX 模块”,但不会输出命令

例子:

# This is a temple makefile ( comment )

all : main

 

main : main.o stack.o maze.o  

  gcc main.o stack.o maze.o -o main

 

main.o : main.h stack.h maze.h

stack.o : stack.h main.h

maze.o : maze.h main.h

 

.PHONY : clean

clean :  

  @echo "cleanning project"  

  -rm main *.o  

  @echo "clean completed"

 


 

Makefile 不需要任何文件扩展名,只需要用 vi Makefile,编辑就可以了。

除了Hello World 这种极为简单的程序之外,一般的程序都是由多个源文件编译链接而成的,这些源文件的处理通常用 Makefile 来管理。

多个文件编译时,如果一个文件需要修改,例如有3个源文件, gcc main.c stack.c maze.c –o main 如果编译之后又对 maze.c做了修改,又要把所有的源文件编译一遍,即使 main.c stack.c 和那些头文件都没有修改也要跟着重新编译。(还记的以前不,只要你的文件中加入了新修改的文件的头文件,即有 #include “maze.h”, 那么就要跟着重新编译),一个大型的软件项目往往由上千个源文件组成,全部编译一遍要几个小时,而且,只改一个源文件就要求全部重新编译肯定是不合理的。

写一个makefile文件和源代码放在同一个目录下: ( 使用 Makefile 做文件名 )

makefile文件

然后,在这个目录下运行 make 编译

make

gcc –c main.c

gcc –c stack.c

gcc –c maze.c

gcc main.o stack.o maze.o –o main

make命令会自动读取当前目录下的Makefile文件,完成相应编译步骤,Makefile由一组规则组成,每条格式为:

target : prerequistes

     command1

     command2

例如:

main: main.o stack.o maze.o

          gcc main.o stack.o maze.o –o main

目标和条件之间的关系是,欲更新目标,必须首先更新它的所有条件,所有条件中只要有一个条件被更新了,目标也必须随之被更新,所谓“更新”就是执行一遍规则中的命令列表,命令列表中的每条命令必须以一个 Tab开头,注意不能是空格,Makefile的格式不像C语言的缩进那么随意,对于Makefile中的每个以Tab开头的命令,make会创建一个Shell进程去执行它。

如果 prerequistes 中如果有一个以上的文件比 target 文件更新的话,command 所定义的命令就会执行,这就是Makefile的规则,也是Makefile最核心的内容。

总体规则

1)如果这个过程没有编译过,那么我们的所有C文件都要编译并被链接。

2)如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并列接目标程序。

3)如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的C文件,并链接目标程序。

只要我们Makefile学的好,所有这一切,只用一个make命令就可以完成。

 

以上的 Makefile 格式可以稍微调整,比如 ( 可以修改的更格式清楚一点 )

main: main.o stack.o maze.o

          gcc main.o maze.o stack.o –o main

 

main.o: main.h stack.h maze.h

stack.o: stack.h main.h

maze.o: maze.h main.h

 

.PHONY : clean

clean:

              -rm main *.o

.PHONY: clean         ( 表示 clean 是个伪目标文件 )

其中的,clean是删除多余文件。

#号在 Makefile中时注释。


make 执行编译

make clean 执行删除执行文件和所有的中间目标文件。

make 会比较 targets 文件和 prerequisits 文件的修改日期,如果 prerequistes 文件的日期要比 targets文件的日期新,或者 target不存在的话,那么,make就会执行后续定义的命令.

这里要说明,clean, 类似C语言中的 label一样,其冒号后什么也没有,那么,make就不会自动去找文件的依赖性,也就不会自动执行其后所定义的命令,要执行其后的命令,就要在make命令后明显得指出这个label的名字,这样的方法非常有用,我们可以在一个makefile中定义不用的编译或和编译无关的命令,比如程序的打包,程序的备份。

注意, Makefile中的第一个 target 一定是最终目标,比如最后的可执行程序。

make 会一层一层的找文件的依赖关系。知道编译出第一个目标文件。如果在找的过程中,出现问题,那么make 就会自动退出,并报错。但是make只管文件依赖性,比如,编译错误等等问题,make根本不理。即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那我就不工作了。

变量

变量类似间接引用,比如我们有很多 .o 文件,当我们修改时,可能需要在Makefile中的很多地方都要修改,如果Makefile很大时,维护困难,但是如果我们将所有的.o文件保存在一个变量中,例如obj这个变量中,那么只要在Makefile中的一个地方修改,就可以实现全部修改。

obj = main.o kdb.o command.o display.o \   ( 这个反斜杠是换行 )

          insert.o search.o files.o utils.o

这样的话,比如,你想增加一个.o文件,那么只需要在这个地方增加就可以了。

在Makefile后边,格式为

edit : $(obj)   在Makefile中 其实就是使用 shell 脚本,shell脚本中 $(obj) 是变量

 

edit : $(obj)

          cc –o edit $(obj )

这样就简单多了。

 

自动推到

只要 make 看到一个.o 文件,它就会自动的把 .c 文件加载依赖关系中。所以不需要我们自己指定。类似上边的

main.o: main.h stack.h maze.h

stack.o: stack.h main.h

maze.o: maze.h main.h

 

简单风格 Makefile

objects = main.o kdb.o command.o display.o \

                 insert.o search.o files.o utils.o

 

edit : $(objects)

                 cc –o edit $(objects)

 

$(objects): defs.h        ( 全部需要引用这个头文件 )

kdb.o command.o files.o : command.h

display.o insert.o search.o files.o : buffer.h

 

.PHONY : clean

clean :

                rm edit $( objects)                //删除全部编译文件,目的是,如果有问题,重新编译

                                                              // 当然需要删除以前编译过的文件

这种简单的风格,Makefile便的简单了。但是依赖关系变的有点凌乱了。没办法,鱼和熊掌不能兼得。

还是好的依赖关系比较好吧。毕竟程序都不打。顶多几个~10几个文件而已。

clean 都是放在文件的最后,好的风格。

.PHONY : clean

clean :

               -rm edit $(objects)

Makefile总述

Makefile中 主要包括 5 个东西: 显示规则,隐晦规则,变量定义,文件指示,注释

1)显示规则说明了,文件的依赖和生成的命令

2)隐晦规则,由于make有自动推到功能,可以方便我们比较粗略的写Makefile

3)变量定义,间接,有点类似C语言中的宏

4)文件指示,包括 3 点

  • 在一个Makefile中引用另一个Makefile,有点像C中的 #include
  • 根据情况制定Makefile的有效部分,有点类似C中的 #if
  • 定义多行命令

5)注释,#号表示注释,如果要用这个符号,可以使用”\#”转义

文件名: Makefile 也可以使用 Make.linux 等等,不过在使用make命令时,要加上 make –f Make.linux

 

@echo 正在编译 XXX 模块, 当我们用 “@”字符在命令行前,那么,这个命令将不被make显示出来。这个例子,当make执行时,会输出”正在编译 XXX 模块”,但不会输出命令。

all : ( 表示缺省的目标,就是最后目标啦,跟clean,是大家约定俗成的 )

标准

 

posted @ 2012-10-17 14:41  神之一招  阅读(3810)  评论(0编辑  收藏  举报