makefile编写过程中的难点

来源:互联网 发布:html5 帝国cms 编辑:程序博客网 时间:2024/05/17 00:18

  • Note
  • What is this
  • 规则
  • 隐含规则
  • 定义模式规则
  • 自动化变量
  • 相关函数
  • CFLAGS编译器参数
  • 参考文档

Note:

这篇博客用于讲解makefile编写过程中的一些难点,不是makefile的基础教程,不建议初学者阅读。这篇博客参考了其他的书籍和文章,在最后会给出,有需要的可以去看一下。笔者看过《GNU+Make项目管理(第三版)》和《跟我一起写Makefile-陈皓》,其中前者晦涩难懂,适合进阶阅读,后者的话就比较适合初学者阅读。在学习makefile编写之前,建议先学会gcc编译的方法和步骤,关于gcc相关的知识,笔者在以后也会更新。

What is this:

这篇文章将会带你学习makefile的变量用法、隐含规则、定义模式规则、自动化规则、相关函数等。

规则

makefile文件包含了一组用于编译应用程序的规则。make所看到的第一项规则会被作为默认规则使用。规则可分为三个部分:目标(target)、依赖目标或称必要条件(prerequisite)、命令(command):

target : prereq1 prereq2
commands

target 是一个必须建立的文件或进行的事情(伪目标);prerequisite或依存对象(dependent)是target被成功创建之前必须事先存在的文件;command是通过prerequisite生成target所需的shell命令,通常放到TAB符之后。
当make被要求处理某项规则时,它首先会找出prerequisite和target中指定的文件。如果prerequisite中存在关联到其他规则的文件,则make会先完成相应规则的更新动作,然后才会考虑target。如果prerequisite的存在时间在target时间之后,则make会执行命令以便重新建立target。command是在被传递给shell,并在subshell中运行,所以如果你希望第二条命令在同样的subshell中运行,就应该把两条命令写在一行,用分号隔开。

隐含规则

隐含规则不是模式规则就是后缀规则,当make检查一个target,如果找不到更新它的规则,就会使用隐含规则

定义模式规则

你可以使用模式规则定义一个隐含规则。模式规则一般是这样的:

%.o : %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

在模式规则中,至少在target中需要包含%,否则就是一般规则了。在target中,%代表任意字符,在prerequisite中,%和target的%表示的意思相同;也就是说,如果%.o 代表a.o b.o c.o ,那么%.c 就一定代表a.c b.c c.c 。这个模式规则就指出了怎么从一个.c文件生成相应的.o文件。

自动化变量

上面使用到了<@变量,这里就来讲解一下自动化变量。自动化变量,顾名思义,就是会自动生成内容的变量,具体生成的内容是什么,下面进行详细分析:

自动化变量 代表的意义 $@ 规则中的target $< prerequisite中的第一个目标的名字,如果prerequisite是以模式(%)定义的,
那么$<将是符合模式的一系列文件集。 $? 所有比target新的prerequisite的集合,以空格分隔 $^ 所有prerequisite的集合,以空格分开,如果prerequisite中有多个重复,那么
这个变量会去除重复的prerequisite $* 这个变量表示目标模式中%及其之前的部分,如果目标是dir/a.foo.b ,
并且目标的模式是a.%.b,那么$*的值就是dir/a.foo。

相关函数

  1. Subst()
    用法:$(subst <from> ,<to>,<text>)
    名称:字符串替换函数
    功能:把字符串<text>中的<from>字符串替换成<to>
    返回:函数返回被替换过后的字符串
  2. patsubst
    用法:$(patsubst <pattern>,<replacement>,<text>)
    名称:模式字符串替换函数
    功能:查找<text>中的单词(单词以空格、Tab、或回车、换行符分隔)是否符合模式<pattern>,如果匹配的话,则以<replacement>替换,这里<pattern>可以包括通配符“%”,表示任意长度的字符串,如果<replacement>也包括“%”,那么<replacement>中的这个“%”将是<pattern>中的那个“%”所代表的字符串
    返回:函数返回被替换过的字符串
    示例:$(patsubst %.c %.o x.c.c bar.c)把字符串“x.c.c bar.c”符合模式%.c的单词替换成%.o,返回结果是“x.c.o bar.o”
  3. strip
    用法: $(strip <string>)
    名称:去掉空格函数
    功能:去掉<string>字符串开头和结尾的空格
  4. shell
    功能:它的参数应该是操作系统shell的命令,它和反引号是相同的功能。shell函数把操作系统命令后的输出作为函数返回。
    示例:files := $(shell echo *.c)
  5. findstring
    用法:$(findstring <find>,<in>)
    名称:查找字符串函数
    功能:在字符串<in>中查找<find>字符串
    返回:如果找到,则返回<find>,否则返回空字符串

CFLAGS编译器参数

这里为什么要讲CFLAGS呢?CFLAGS是c语言编译器参数,在makefile文件中经常会用到CFLAGS,所以在这里对CFLAGS也做一些解释。
例如编译c程序的隐含规则命令:(CC)c(CFLAGS) $(CPPFLAGS),其中:

  • $(CC)是c语言编译程序
  • $(CFLAGS)是c语言编译器参数
  • $(CPPFLAGS)是c预处理器参数

这里用$(CFLAGS)代替了gcc的很多选项,比如-w -i等,将这些值定义成一个变量,主要是为了方便书写和管理,如果每次使用相同配置的gcc都要输入一长串的参数值,很容易出现错误。CFLAGS出现的一些常用的值如下:
- -W/-Wall:-W,在编译中开启一些额外的warning信息。-Wall,将所有的警告信息全开
- -w:禁止输出warning消息
- -I: 指定头文件所在的文件夹,使用示例:-I/path/inc
- -L:指定函数库所在的文件夹,使用示例:-L/path/lib
- -l:指定所使用到的函数库,使用示例-llibxxx.a
- -D:打开宏,使用示例:-DLOW_POWER,相当于在所有的文件前面加上#define LOW_POWER 1; -DLOW_POWER=5,相当于#define LOW_POWER 5;
- -U:关闭宏,使用示例:-ULOW_POWER,相当于在所有文件前面加上#undef LOW_POWER
- Wl option:传递option给连接程序
- -share:尽量使用动态库
- -x:设定文件所使用的语言,使后缀名无效,对以后的多个有效.也就是根据约定C语言的后缀名称是.c的,而c++的后缀名是.c或者.cpp,使用示例:-x c filename

参考文档

《跟我一起写Makefile-陈皓》
《GNU+Make项目管理(第三版)》
gcc编译参数

0 0
原创粉丝点击