MAKE 的使用
当编译单个文件时,使用GCC已经绰绰有余,但对于有几十个甚至上百个源文件的大工程来讲,单纯用GCC命令进行编译肯定就不行了,那样编译一次太麻烦,这就要求有一种自动化的方法,于是在Linux系统中Make工具就诞生了。
1、 什么是Make makefile shell
什么是Make,可以将Make理解为一种脚本,这种脚本主要是用于多文件编译,在传统的命令行式编译方式中,如果修改了工程中的某一个头文件,有时候不需要重新编译整个工程,而只需要编译与这个头文件相关联的源文件即可,但如何以手动的方式从一个大工程里将这些文件找出,并手动编译,是件很麻烦的事情。
为了解决这一问题,设计了Make,make程序可以维护具有相互依赖性的源文件,当某些文件发生改变时,它能自动识别出,并只对相应文件进行自动编译。
虽然make工具有很多智能识别机制,但它无法自动了解他所面对的工程源文件的组成以及依赖规则,这些都需要开发人员编写makefile脚本,告诉make工具。MakeFile编写好以后,就可以在每次修改源文件之后,执行make命令就好了。Makefile make
什么又是makefile了,很多windows的程序开发人员都不知道这个东西,因为那些Windows的IDE都为你做了这些工作,但我觉得要作为一个好的和专业的程序员,makefile还是要懂得,这就好像在有这么多的HTML的编辑器,但如果你想成为一个专业人士,就必须了解HTML的标识的含义。特别在Linux下的软件编译,你就必须自己写makefile了,会不会写makefile,从一个侧面说明了一个人是否具备完成某个大型大工程的能力。
2、 makefile的组成
一个完整的makefile文件通常由五个部分组成:
◆显示规则
显示规则是指主动编写描述规则,用于指示在何种状态下更新哪些目标文件,即编写makefile时需要明确指出各目标文件所依赖的源文件的集合,以及编译本目标文件所需的命令。
◆隐含规则
指用make中默认的编译方式进行编译,即make工具可以根据目标文件的类型自动推导出的规则(由于我们的make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略书写Makefile ,这是由make所支持的)
abc.o abc.c cc -o abc.o -c abc.c
◆变量定义
为提升语句的灵活性,在make脚本中可以使用变量,来代表一个字符串,一组编译命令或一组文件名。(在makefile 中我们要定义一系列的变量,变量一般都是字符串,这个有点类似于C语言中的宏,当makefile 被执行时,其中的变量都会被扩展到相应的引用位置上)
◆makefile指示符
指示符告诉make工具,当程序在读取makefile文件时要执行的动作。
(文件指示包括三部分,一个是在一个makefile中引用另外一个makefile,就像C语言中的include一样,另一个是指根据某些情况制定MakeFile中的有效部分,就像C语言中的预编译#if一样,还有就是定义一个多行的命令,)
◆ 注释
Makefile中将#作为注释标识符
【注】如果此行的第一个非空字符为#,则此行为注释
如果此行的结尾存在一个反斜杠(\),则下一行也被视为注释行
如果在代码中需要使用字符#,就要使用转义字符\#来表示此字符并非一个注释符
3、 makefile的基本语法
makefile主要由规则组成,即编写makefile要遵循一定的规则,在makefile中规则是用于描述在何种状态下,用何种命令创建何种文件。
一条makefile的规则原型:
Target … : dependency…
<Tab>Command
…
…
◆ Target代表目标文件,既可以是一个目标代码文件,也可以是一个可执行文件,还可以是一个伪目标
◆ Dependency代表生成上述目标文件所需要的文件(即依赖文件)
◆ Command代表响应命令,即由依赖文件生成目标文件所需要的命令
【注意】规则中的命令必须以Tab键开头,make 工具会将所有以Tab键开头的行当
成命令交给shell 执行。
为方便阅读,对于一个较长的命令行可以书写到多行上,注意行与行之间要
用“\”链接。
在makefile中,规则主要包括两部分,一是依赖关系,一是生成目标的方法。
其中规则的顺序很重要,因为,makefile中只应该有一个最终目标,其他的目标都是
被这个目标所连带出来的,所以一定要让make知道你的最终目标是什么,一般来
说,定义在Makefile中的目标可能会很多,但是第一条规则中的目标将被确立为最
终的目标,如果第一条规则中目标有多个,那么,第一个目标将会成为最终目标,
make所要完成的也就是这个目标。
4、 Makefile变量
相比于C语言,Makefile中的变量更像C语言中的宏定义。在引用变量的地方,变量会被其定义的数据所代替。
1、 变量的定义
◆ 递归展开式变量
递归展开式变量是通过“=”或“define”定义的,它的展开是在引用时严格的字符串或数字的替换。
#var1="first var1 define"
#var2:=$(var1) "var2 define"
#var1="second var1 define"
#clean:
# @echo $(var1)
# @echo $(var2)
#define var1
#first
#endef
#define var2
#$(var1) "var2 define"
#endef
#define var1
#second
#endef
#clean:
# @echo $(var1)
# @echo $(var2)
#var1=$(var2)
#var2=$(var3)
#var3=bss
#clean:
# @echo $(var1)
◆ 直接展开式变量
在变量的定义时就完成对其引用变量的展开,就确定了引用变量的值,这个值不会随着其他变量的变化而变化。
2、 变量的引用
定义了一个变量之后,就可以在很多地方使用它,变量的引用方式是:
$(VAR_NAME)或者${VAR_NAME}
对于一些简单变量的引用,也可以不用括号进行变量名德标记就可以直接使用,但此类型的引用方式只是用于变量名为单个字符的情况,当变量名为多个字符而不加括号时,实际引用的是以变量名第一个字符为变量名德变量,为了不造成混乱,建议所有的变量引用都加上括号。
五、Make的执行
1、make的执行原理
针对于makefile的原型表达式中,target这一个或多个的目标文件依赖于Dependency中的文件,其生成规则定义在Command中,说白一点就是,dependency中如果有一个以上的文件比target文件要新的话,Command所定义的命令就会被执行,这是makefile的规则,也是makefile中最核心的内容。
2、 指定makefile文件
默认情况下,make会在当前的工作目录下搜索MakeFile文件,并读取、执行MakeFile文件,查找顺序为:makefile、MakeFile。如果当前工作目录下没有找到上述两个文件中的任何一个,Make将不读取任何文件,而可以通过命令行指定一个目标,如果当前工作目录下存在符合此目标的依赖文件,则采用默认的命令创建或更新目标文件。
Make –f Filename Or make –file FileName
3、 使用make进行编译测试
Make在执行MakeFile时,如果出现命令执行错误,就会立即停止执行,也就是说错误发生之后的命令将不会被执行。
Make –k Or make –keep-going
六、伪目标
伪目标并不代表一个真正的文件名,在执行make时,可以通过指定一个伪目标来执行其所在规则中定义的命令。
有时候也将伪目标称为标签,经常会定义一个伪目标clean,用于清理工程编译的文件:
Clean:
Rm *.o myapp
规则中rm是shell中的删除命令,用于删除当前目录下所有的.o文件和可执行文件myapp,当进行重新编译时,通常会输入make clean调用命令 rm *.o myapp
来删除旧的文件。
【注意】在定义一个为目标时,如果当前的目录下存在clean文件,则输入 make clean 时,由于伪目标规则中没有依赖文件,而且clean文件总是最新的,因此按照MakeFile文件的运行规则,rm *.o myapp是不会被执行的,这显然是有问题的,为了解决这种问题,要用到.PHONY,使用这个字符串可以显示指定clean为伪目标,而不将其视为文件。
.PHONY 的格式为:
.PHONY :clean
这样,clean就被定义为一个伪目标,不管当前目录下有没有名为clean的文件,输入命令make clean后其对应的命令总会被执行,不在去检查其依赖源文件列
表,而是直接执行命令,这在无形中叶提高了执行效率。
当编译单个文件时,使用GCC已经绰绰有余,但对于有几十个甚至上百个源文件的大工程来讲,单纯用GCC命令进行编译肯定就不行了,那样编译一次太麻烦,这就要求有一种自动化的方法,于是在Linux系统中Make工具就诞生了。
1、 什么是Make makefile shell
什么是Make,可以将Make理解为一种脚本,这种脚本主要是用于多文件编译,在传统的命令行式编译方式中,如果修改了工程中的某一个头文件,有时候不需要重新编译整个工程,而只需要编译与这个头文件相关联的源文件即可,但如何以手动的方式从一个大工程里将这些文件找出,并手动编译,是件很麻烦的事情。
为了解决这一问题,设计了Make,make程序可以维护具有相互依赖性的源文件,当某些文件发生改变时,它能自动识别出,并只对相应文件进行自动编译。
虽然make工具有很多智能识别机制,但它无法自动了解他所面对的工程源文件的组成以及依赖规则,这些都需要开发人员编写makefile脚本,告诉make工具。MakeFile编写好以后,就可以在每次修改源文件之后,执行make命令就好了。Makefile make
什么又是makefile了,很多windows的程序开发人员都不知道这个东西,因为那些Windows的IDE都为你做了这些工作,但我觉得要作为一个好的和专业的程序员,makefile还是要懂得,这就好像在有这么多的HTML的编辑器,但如果你想成为一个专业人士,就必须了解HTML的标识的含义。特别在Linux下的软件编译,你就必须自己写makefile了,会不会写makefile,从一个侧面说明了一个人是否具备完成某个大型大工程的能力。
2、 makefile的组成
一个完整的makefile文件通常由五个部分组成:
◆显示规则
显示规则是指主动编写描述规则,用于指示在何种状态下更新哪些目标文件,即编写makefile时需要明确指出各目标文件所依赖的源文件的集合,以及编译本目标文件所需的命令。
◆隐含规则
指用make中默认的编译方式进行编译,即make工具可以根据目标文件的类型自动推导出的规则(由于我们的make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略书写Makefile ,这是由make所支持的)
abc.o abc.c cc -o abc.o -c abc.c
◆变量定义
为提升语句的灵活性,在make脚本中可以使用变量,来代表一个字符串,一组编译命令或一组文件名。(在makefile 中我们要定义一系列的变量,变量一般都是字符串,这个有点类似于C语言中的宏,当makefile 被执行时,其中的变量都会被扩展到相应的引用位置上)
◆makefile指示符
指示符告诉make工具,当程序在读取makefile文件时要执行的动作。
(文件指示包括三部分,一个是在一个makefile中引用另外一个makefile,就像C语言中的include一样,另一个是指根据某些情况制定MakeFile中的有效部分,就像C语言中的预编译#if一样,还有就是定义一个多行的命令,)
◆ 注释
Makefile中将#作为注释标识符
【注】如果此行的第一个非空字符为#,则此行为注释
如果此行的结尾存在一个反斜杠(\),则下一行也被视为注释行
如果在代码中需要使用字符#,就要使用转义字符\#来表示此字符并非一个注释符
3、 makefile的基本语法
makefile主要由规则组成,即编写makefile要遵循一定的规则,在makefile中规则是用于描述在何种状态下,用何种命令创建何种文件。
一条makefile的规则原型:
Target … : dependency…
<Tab>Command
…
…
◆ Target代表目标文件,既可以是一个目标代码文件,也可以是一个可执行文件,还可以是一个伪目标
◆ Dependency代表生成上述目标文件所需要的文件(即依赖文件)
◆ Command代表响应命令,即由依赖文件生成目标文件所需要的命令
【注意】规则中的命令必须以Tab键开头,make 工具会将所有以Tab键开头的行当
成命令交给shell 执行。
为方便阅读,对于一个较长的命令行可以书写到多行上,注意行与行之间要
用“\”链接。
在makefile中,规则主要包括两部分,一是依赖关系,一是生成目标的方法。
其中规则的顺序很重要,因为,makefile中只应该有一个最终目标,其他的目标都是
被这个目标所连带出来的,所以一定要让make知道你的最终目标是什么,一般来
说,定义在Makefile中的目标可能会很多,但是第一条规则中的目标将被确立为最
终的目标,如果第一条规则中目标有多个,那么,第一个目标将会成为最终目标,
make所要完成的也就是这个目标。
4、 Makefile变量
相比于C语言,Makefile中的变量更像C语言中的宏定义。在引用变量的地方,变量会被其定义的数据所代替。
1、 变量的定义
◆ 递归展开式变量
递归展开式变量是通过“=”或“define”定义的,它的展开是在引用时严格的字符串或数字的替换。
#var1="first var1 define"
#var2:=$(var1) "var2 define"
#var1="second var1 define"
#clean:
# @echo $(var1)
# @echo $(var2)
#define var1
#first
#endef
#define var2
#$(var1) "var2 define"
#endef
#define var1
#second
#endef
#clean:
# @echo $(var1)
# @echo $(var2)
#var1=$(var2)
#var2=$(var3)
#var3=bss
#clean:
# @echo $(var1)
◆ 直接展开式变量
在变量的定义时就完成对其引用变量的展开,就确定了引用变量的值,这个值不会随着其他变量的变化而变化。
2、 变量的引用
定义了一个变量之后,就可以在很多地方使用它,变量的引用方式是:
$(VAR_NAME)或者${VAR_NAME}
对于一些简单变量的引用,也可以不用括号进行变量名德标记就可以直接使用,但此类型的引用方式只是用于变量名为单个字符的情况,当变量名为多个字符而不加括号时,实际引用的是以变量名第一个字符为变量名德变量,为了不造成混乱,建议所有的变量引用都加上括号。
五、Make的执行
1、make的执行原理
针对于makefile的原型表达式中,target这一个或多个的目标文件依赖于Dependency中的文件,其生成规则定义在Command中,说白一点就是,dependency中如果有一个以上的文件比target文件要新的话,Command所定义的命令就会被执行,这是makefile的规则,也是makefile中最核心的内容。
2、 指定makefile文件
默认情况下,make会在当前的工作目录下搜索MakeFile文件,并读取、执行MakeFile文件,查找顺序为:makefile、MakeFile。如果当前工作目录下没有找到上述两个文件中的任何一个,Make将不读取任何文件,而可以通过命令行指定一个目标,如果当前工作目录下存在符合此目标的依赖文件,则采用默认的命令创建或更新目标文件。
Make –f Filename Or make –file FileName
3、 使用make进行编译测试
Make在执行MakeFile时,如果出现命令执行错误,就会立即停止执行,也就是说错误发生之后的命令将不会被执行。
Make –k Or make –keep-going
六、伪目标
伪目标并不代表一个真正的文件名,在执行make时,可以通过指定一个伪目标来执行其所在规则中定义的命令。
有时候也将伪目标称为标签,经常会定义一个伪目标clean,用于清理工程编译的文件:
Clean:
Rm *.o myapp
规则中rm是shell中的删除命令,用于删除当前目录下所有的.o文件和可执行文件myapp,当进行重新编译时,通常会输入make clean调用命令 rm *.o myapp
来删除旧的文件。
【注意】在定义一个为目标时,如果当前的目录下存在clean文件,则输入 make clean 时,由于伪目标规则中没有依赖文件,而且clean文件总是最新的,因此按照MakeFile文件的运行规则,rm *.o myapp是不会被执行的,这显然是有问题的,为了解决这种问题,要用到.PHONY,使用这个字符串可以显示指定clean为伪目标,而不将其视为文件。
.PHONY 的格式为:
.PHONY :clean
这样,clean就被定义为一个伪目标,不管当前目录下有没有名为clean的文件,输入命令make clean后其对应的命令总会被执行,不在去检查其依赖源文件列
表,而是直接执行命令,这在无形中叶提高了执行效率。