关闭

make规则

标签: makefilefilelibraryincludeshellgcc
909人阅读 评论(0) 收藏 举报
分类:

Makefile

更多参照:见链接GNU Make手册

执行make时候会自动在当前目录顺序搜寻GNUMakefileMakefilemakefile

 

Make的基本规则:

         Target  [属性] 分隔符 [依赖文件] [;命令行 ]

           {Tab 命令行}

         注:命令行间可以加入任意多个空行,但空行也要以tab开头。Cat –v-t-e Makefile会使Makefile文件中tab^]显示,行尾以$显示。

         注:命令过长,用/来连接多行成一行。注释以#开头,如果#要用作字符符号,“#”。

 

分隔符

         ::目标有多个规则。哪条规则中的依赖文件比目标新,执行哪条规则。如果多条规则的依赖文件都比目标新,多条规则都执行。由于后面的规则可能覆盖前面规则的执行结构,所以规则顺序不同,执行结构也不同。

         ^把本规则依赖文件和目标文件已有的依赖文件合起来,生成目标新的依赖文件列表。

         -清除目标已有依赖文件,把本规则依赖文件作为目标依赖文件列表。

         :!对每个更新过的依赖文件都执行一次命令菜单。 ???

         |内部规则专用。 ???

如:file.o file.c

         file.o ^ filef.c 现依赖文件为file.c filef.c

         file.o - filef.c 现依赖文件为 filef.c

 

命令行属性

 -     若本命令的执行错误,忽略掉,继续向下执行。(不加该标志,make会停止)

+   始终执行本命令,即使make参数使用了-n-q-t。(前提是本规则中依赖文件新与目标文件,命令行需要执行)

@  本命令行不在标准输出显示。

 

Target属性

         指定多个目标文件属性: 属性 属性 …… :目标 目标 ……

         规则中指定单个目标属性:目标 属性:[依赖文件] ……

         ·IGNORE 类似与命令行属性-

         ·SILENT 类似与命令行属性@

         ·PRECIOUS 保留中间文件

         ·LIBRARY 目标是一个库。如果make发现目标是lib(member)lib((entry))形式,会自动给名为lib的目标加上该属性。

         ·LIBRARYM 目标是库的一个成员。如果make发现目标是libmember)形式,会自动给lib目标加上·LIBRARY,被member目标加上·LIBRARYM。本属性不可在makefile文件显式声明。

         ·SYMBOL 目标是指定入口的库成员。Make会自动给lib((entry))的目标和依赖文件加上本属性。本属性不可在makefile文件显式声明。

 

伪目标

         Linux提供的内部伪目标:

         ·ERROR

                   Make遇到错误,执行该目标规则。

·INCLUDE file1 ……

         包含其他makefile文件,其他makefile文件位于·INCLUDE规则的依赖文件位置。实际上,是把包含的文件内容copy到当前位置。比如:包含一个宏定义文件,以便在当前位置展开,本makefile文件可以用这些宏。形式:

                            ·INCLUDE filename1 filename2…… 

或要包含的文件不在当前文件夹

                            ·INCLUDE :路径1 路径2 ……

                            ·INCLUDE filename1 filename2 ……

或者

                            ·INCLUDE <路径/filename> ……

·IMPORT :宏 ……

         使用环境变量中的宏。

         ·IMPORT :·ENVERTHING 可以使用环境中所有宏了。

·EXPORT :宏 ……

         将宏及当前值输入环境变量中。

·SETDIR=路径

         改变当前工作路径。

 

注:有时候要定义的伪目标可能与文件名重。比如存在clean这个文件。可以用:

         PHONYclean

         cean

                   …………

         PHONY的作用是确保下面的clean是伪目标,非文件,从而避免混乱。

 

宏:

         赋值号

         赋值号:

                   = 将后面的字符串赋给宏

                   = 后面跟字符串常量,将常量的内容赋给宏     ??貌似不对

                   +=  宏原值加空格,加字符串,构成新宏值

         宏引用:$() ${}。宏只有一个字符,可用$宏。如$A,等同$(A)

         注意:makefile中,宏的引用必须在宏的定义之后。

         注意:宏可以嵌套。如:INDEX=1  $(DEADFILE$(INDEX)),等同$(HEADFILE1)

         注意:宏可以在make命令参数定义、makefile中定义、引自环境宏,当make命令参数定义的宏含空格是,应用“宏=值”括起来。

         注意:宏处理顺序:内定义宏——shell环境宏——makefile中定义的宏——make命令参数宏。由于后面的宏处理会覆盖前面的宏,所以优先级为:make命令参数宏——makefile宏——shell环境宏——内定义宏。所有我们可以在不改变makefile的情况下,在命令行给宏赋新值而使用新宏值。

 

内定义宏:

         普通宏,代表特殊的值:

         DIRSETSTR 路径和文件间分割符一般为‘/

         MAKEDIR  make的绝对路径

         NULL 空字符传,多用于条件表达式中比较

         OS 运行的操作系统名称

         PWD 运行make是活动工作目录绝对路径

         SHELL 运行的shell

         属性宏,用于整个makefile中目标文件属性,作用域是整个makefile文件:

         IGNORE=yes  把所有目标文件属性设置成·IGNOREyes可以用任何非空字符串代替。

         SILENT

         PRECIOUS

 

动态宏:

         S@ S%:目标文件名称。当目标是lib(member)形式时,$@表示库名lib$%表示成员名member

         $> :适用与目标文件是lib(member)的情形,$>代表lib$>不适用与目标是普通文件。

         $* :目标文件去掉后缀的名称。

         $^ :本规则中的依赖文件。

         $& :本规则中目标在所有规则中的所有依赖文件。     

         $< :当前规则的依赖文件列表中比目标新的依赖文件。

         $?:当前目标的所有依赖文件中比目标新的依赖文件。

         用于依赖文件列表的动态宏:

         $$@ :目标文件名。如果目标是库,表示库名。

         $$% :目标文件名。如果目标是库,表示成员名。

         $$> :去掉后缀的目标文件名。

         $$* :仅当目标文件是库的成员时使用,表示库名。

 

修改宏:

         适用与代表文件名(或文件列表)、或者至少有着文件名形式的宏:

FILE=/home/friky/hello.o /home/h.c mf.h

         $(FILEd)        展开路径  /home/friky /home .

         $(FILEb)        展开无扩展名的文件名  hello h mf

         $(FILEf)         展开文件名  hello.o h.c mf.h

         $(FILEdb)      /home/friky/hello ……

         替换宏中字符串:

         宏:s/原字符串/替换字符串      替换

         宏:原扩展名=新扩展名                仅适用与表示文件列表的宏

         宏:^”前缀

         宏:+”后缀          如:FILE^”/usr/” +”.o”

         注:前缀、后缀的修改,make默认为宏表示文件名列表,如果宏中有空格,make会任务有多个文件名,对每个文件名都进行前缀、后缀操作。如果前缀、后缀中也有空格,就会以空格为分割,从前缀、后缀中逐个提取字符串,分别与各个文件名组合。

         如:FILE=h d  $(FILE^”1 2”)1h 1d 2h 2d

 

Make预定义的宏:

         ARAr    库管理命理                       ARFLAGS-ruv

         ASas 汇编程序                               ASFLAGS

         CCcc  c编译器                              CFLAGS-O

         C++CCC  c++编译器                    C++FLAGS-O

         CXXg++  c++编译器                  CXXFLAGS

         CPP$(CC) –E  带标注输出的预处理程序 

         CPPFLAGS

         LDld  链接器                                  LDFLAGS

         RMrm –f

         MAKEmake                                       MAKEFLAGSNULL 

         LIBSUFFIXE.a  库扩展名             A.a

MAKEMAKEFLAGS这两个宏用于makefile中嵌套make命令行,来完成程序不同模块间makefile的互相调用。即使make命令中用了-nMAKE宏也要执行。

 

内部规则:

         内部规则根据目标文件和依赖文件的扩展名定义,在正式执行make前就已经定义好了,如果makefile没有显式的定义关于某个目标文件的规则,make就会根据该目标文件的扩展名找相应的内部规则,——删掉目标文件后缀,加上预定义的依赖文件后缀,得到完整依赖文件,结合内部规则的命令行生成完整的规则。

         .h    头文件              .o      目标文件                   .c      c源文件

         .C     c++源文件       .s      汇编源文件              .f       FORTRAN源文件

         .sh    shell文件         .y      Yacc-C源语法          .l       Lex源语法

         内部规则可以是单后缀的或双后缀的。单后缀只给出目标文件后缀,无依赖文件。双后缀,第一个后缀为依赖文件扩展名,第二个后缀为目标文件后缀。如:

         .c:    

                   $(CC) $(CFLAGS) –O $@ $<

         .c .o:

                   $(CC) $(CFLAGS) –c $<

         注意:可能一个后缀名出现在多条内部规则中,如:.c.o/.f.o等。实际上,make.o寻找内部规则时,找到一个匹配规则,还要看在当前工作目录是否有与目标文件同名、且后缀为规则第一个后缀的文件,找到,应用该规则,否则,继续找内部规则。

         exanple1: main.o proc1.o proc2.o

                  gcc main.o proc1.o proc2.o -o example1

main.o: main.c mylib.h

                  gcc -c main.c

proc1.o: proc1.c mylib.h

                  gcc -c proc1.c

proc2.o: proc2.c

                  gcc -c proc2.c

         利用内部规则:可简写成:

         exanple1: main.o proc1.o proc2.o

                  gcc main.o proc1.o proc2.o -o example1

         main.o proc1.omylib.h

         (没有显式定义时找内部规则??显示定义??规则??依赖??

修改内部规则:

1.       修改内部规则中用到的宏

2.       重写整个内部规则,最好放在makefile最前面,make处理makefile时,运行到该语句,就会用新的定义覆盖原有内部规则,在后面再用到这个规则,就会使用新的规则。

定义新的后缀和内部规则:

         定义后缀:NEW ROMAN:后缀名 后缀名

         如:SUFFIXES.n

         若定义个.o.n内部规则,但当前工作文件夹只有hello.c文件,执行make hello.n,不能正常工作,因为make一次只能检查一个内部规则。make hello.o hello.nOK了,需要一个中间过程生成hello.o.o.n规则使用。

        

         #(用%的模式规则??

         # gcc -M参数,会输出一个规则,以目标文件作为目标,以.c文件和其包含的头文件作为依赖文件。-M 加“”<> 包含的头文件,-MM只加“”包含的的头文件。

 

库:

         linux中,生成可执行文件,如果链接一般的.o文件,则整个文件内容都会装入可执行文件,如果链接的是库,则只从库中找出用到的变量和函数,装如可执行文件。因此将编译好的目标模块统一放在库中是个较好的习惯。

         建立和维护库规则:

形式1liblib(member1)lib(member2)……

make遇到这样的规则会自动给lib赋予·LIBRARY属性,给member赋予·LIBRARYM属性。

形式2lib ·LIBRARYmember1  member2 ……

显式指定·LIBRARY属性。

形式3lib((entry))

一旦make识别这样的形式,会自动给lib赋予·LIBRARY属性、entry赋予·SYMBOL属性,然后根据entry在库中找相依的成员文件。返回该entry的成员的建立时间,用真正的文件名替换entry。然后的处理与直接给出成员文件名一样。

根据.o文件更新库:     ar –ruv 库名 .o文件名

mylib: mylib(file1.o)

         gcc –c file1.c

         ar –ruv mylib file1.o

         rm file1.o

mylib: mylib(file2.o)

         gcc –c file2.c

         ar –ruv mylib file2.o

         rm file2.o

…………

有多少个成员,写多少规则,麻烦……

 

mylibmylibfile1.o file2.o ……)

         gcc –c $?:b.c

         ar –ruv $@ $?

         rm  –f  $?

 

内部规则.c.o

         .o.a:

                   $(AR)  $(ARFLAGS) $@ $?

                   rm  -f $?

         可以直接简写成: mylibmylibfile1.omylib(file2.o) …………

         Make处理整个语句时,先检查库的依赖文件,从第一个文件file1.o开始,如果file1.o晚于file1.c,应用.c.o规则。然后第二个依赖文件…………,所有依赖文件处理完,应用.o.a规则更新库。Make在识别mylib为库后,会自动加上.a扩展名。所以在终端输出的信息都显示为mylib.a

         .a:

                make $@

 

使用库进行链接:

         可执行文件的依赖文件列表中用的库成员:lib(成员文件名)或者lib((成员entry)),然后命令行的ld只要加上参数lib就可以了。

         内部规则:.o.e:

                                 $(LD)  $(LDFLAGS) –o $@ $< $(LDLIBS)

         LDLIBS定义了标准函数库的列表。用到自定义的库,可以LDLIBS+=库名。

         LDLIBS+=mulib

         prog.emylibfile1.o

         make维护prog.e是会根据内部规则为他找依赖文件和更新命令。

 

#Makefile中的函数:

         Makefile中的函数使用必须指明函数名字和参数。函数处理的结果将返回到在makefile文件中的调用处。格式:

         $(函数名 参数,参数,……)      

         ${函数名 参数,参数,……}

         如:

         $(wildcard 参数)     展开一列所有符合参数描述的文件名列表

         $(patsubst  %.c%.o,参数3)   三个参数分别是匹配模式、替换模式、字符列表

        

         Shell函数:makeshell函数的返回结果返回到调用点前,会把换行和回车统一替换成空格,如果最后字符是换行或回车,去掉。

         SOUR=$(shell cat foo)

#makefile中的条件语句:

         ifeq/ifneq (arg1arg2)

         ifeq/ifneq arg1”“arg2

  ……‘arg1’‘arg2

  …… arg1”‘arg2

  ……‘arg1’“arg2

         ……………………

   else

         ……………………

   endif

 

 

Make命令:

         Make [参数] [] [目标 目标 ……]

         一般从第一条规则开始维护。检查顺序:第一个依赖文件——第一个依赖文件的依赖文件……    ——>第二个依赖文件——第二个依赖文件的依赖文件……   ……    树状一条路径逐层展开,直查找到依赖文件都是源文件,然后原路返回,查找下一条路径。同一规则的依赖文件按照从左至右顺序。

 

参数:

         -c dir 指定make工作后的工作目录

         -e 不允许makefile中给环境宏赋值

         -f filename 指定makefile文件

         -i 忽略makefile中命令执行是产生的错误,不中止make

         -k 执行命令出错,放弃当前目标文件,转向其他目标

         -n 按实际执行是顺序显示命令,包括@开头的,但不实际执行

         -p 显示makefile中所有宏定义和内部规则

         -r 忽略内部规则

         -s 执行,但不显示执行的命令

         -S 执行makefile命令菜单时出错即退出makefile

         -t 修改每个目标文件的创建日期,但不真正重新创建目标文件

         -V 显示make版本号

         -x 把所有宏输出到环境

 

命令行属性、目标属性、make参数都是用来控制make的,当三者属性发生矛盾时候,规则遵循的属性优先顺序为:命令行属性——目标属性——make参数,但三者都未指定,则用默认。

 
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:10207次
    • 积分:148
    • 等级:
    • 排名:千里之外
    • 原创:2篇
    • 转载:6篇
    • 译文:0篇
    • 评论:2条
    文章分类
    文章存档