Makefile 笔记

跟着耗子哥学习,基本都是抄他的笔记,侵删 跟我一起写 Makefile(一)_陈皓专栏 【空谷幽兰,心如皓月】-CSDN博客_makefile

编译: 把.c文件变成.o文件

链接: 把.o文件变成可执行文件,比如a.out

make file 规则

target ... : prerequisites ...
            command
            ...
            ...

target 是目标文件,可以是.o, 也可以是执行文件,

prerequisite 是前置条件,要生产target,必须满足前置条件

command 是make要执行的shell命令,在Makefile中的命令,必须要以[Tab]键开始。

典型的make file如下

edit : main.o kbd.o command.o display.o /
           insert.o search.o files.o utils.o
            cc -o edit main.o kbd.o command.o display.o /
                       insert.o search.o files.o utils.o

    main.o : main.c defs.h
            cc -c main.c
    kbd.o : kbd.c defs.h command.h
            cc -c kbd.c
    command.o : command.c defs.h command.h
            cc -c command.c
    display.o : display.c defs.h buffer.h
            cc -c display.c
    insert.o : insert.c defs.h buffer.h
            cc -c insert.c
    search.o : search.c defs.h buffer.h
            cc -c search.c

clean : main.o kbd.o command.o display.o /
           insert.o search.o files.o utils.o
            cc -o edit main.o kbd.o command.o display.o /
                       insert.o search.o files.o utils.o

可以看到edit和clean的是一样的,如果我们要修改,那么就得改两处,为了不这样:

可以定义变量:

objects = main.o kbd.o command.o display.o /
           insert.o search.o files.o utils.o
            cc -o edit main.o kbd.o command.o display.o /
                       insert.o search.o files.o utils.o

而clean改成

clean: rm edit $(objects)

约定俗成

make的第一个可执行命令,为默认的执行命令

clean一般在make最末尾

自动推导

main.o 会自动找寻main.c依赖,所以无需在Makefile显示声明

引用其它的Makefile

用法为include <filename> 

    include foo.make *.mk $(bar)

    等价于:

    include foo.make a.mk b.mk c.mk e.mk f.mk

make中有一步,为所有的目标文件创建依赖关系链,我觉得这就是所谓的链接?

跟我一起写 Makefile(四)_陈皓专栏 【空谷幽兰,心如皓月】-CSDN博客

看到vpath,其他没咋看

伪目标

比如clean,其实就是不生成文件,但是确实会执行的指令,这个指令可能是其他指令的集合

“伪目标”,向make说明,不管是否有这个文件,这个目标就是“伪目标”。

    .PHONY : clean

只要有这个声明,不管是否有“clean”文件,要运行“clean”这个目标,只有“make clean”这样。于是整个过程可以这样写:

     .PHONY: clean
    clean:
            rm *.o temp

(五)多目标及自动依赖性

总而言之,这个模式要做的事就是在编译器生成的依赖关系中加入[.d]文件的依赖,即把依赖关系:

    main.o : main.c defs.h

转成:

    main.o main.d : main.c defs.h

(六)命令执行

@echo 显示命令

执行命令:需要注意的是,如果你要让上一条命令的结果应用在下一条命令时,你应该使用分号分隔这两条命令。

exec: 

        cd /home/hchen; pwd

忽略命令出错

前面加个"-"号

clean:
            -rm -f *.o

嵌套执行make

subsystem:
            cd subdir && $(MAKE)

其等价于:

    subsystem:
            $(MAKE) -C subdir

这两个例子的意思都是先进入“subdir”目录,然后执行make命令。

如果你要传递变量到下级Makefile中,那么你可以使用这样的声明:

        variable = value
        export variable

(七)变量

$(object)是求object的值

最好使用这种定义: x := foo

dir := /foo/bar    # directory to put the frobs in

后面采用“#”注释符来表示变量定义的终止,/foo/bar后面还跟了4个空格,如果我们这样使用这样变量来指定别的目录——“$(dir)/file”那么就完蛋了。

两种变量的高级使用方法

第一种是变量值的替换。

我们可以替换变量中的共有的部分,其格式是“$(var:a=b)”或是“${var:a=b}”,其意思是,把变量“var”中所有以“a”字串“结尾”的“a”替换成“b”字串。这里的“结尾”意思是“空格”或是“结束符”

foo := a.o b.o c.o
    bar := $(foo:.o=.c)

“$(bar)”的值就是“a.c b.c c.c”。

第二种高级用法是——“把变量的值再当成变量”。

先看一个例子:

    x = y
    y = z
    a := $($(x))

在这个例子中,$(x)的值是“y”,所以$($(x))就是$(y),于是$(a)的值就是“z”。

override

用来覆盖命令行参数的值

语法是:

override <variable> = <value>

override <variable> := <value>

(八)变量二

(九)函数

调用语法:

$(<function> <arguments>)

示例:

 comma:= ,
    empty:=
    space:= $(empty) $(empty)
    foo:= a b c
    bar:= $(subst $(space),$(comma),$(foo))

字符函数

$(subst <from>,<to>,<text>)

    名称:字符串替换函数——subst。
    功能:把字串<text>中的<from>字符串替换成<to>。

$(strip <string>)

    名称:去空格函数——strip。
    功能:去掉<string>字串中开头和结尾的空字符。

$(filter <pattern...>,<text>)

    名称:过滤函数——filter。

sources := foo.c bar.c baz.s ugh.h
        foo: $(sources)
                cc $(filter %.c %.s,$(sources)) -o foo

$(filter %.c %.s,$(sources))返回的值是“foo.c bar.c baz.s”。

$(word <n>,<text>)

    名称:取单词函数——word。
    功能:取字符串<text>中第<n>个单词。(从一开始)

示例:$(word 2, foo bar baz)返回值是“bar”。

$(words <text>)

    名称:单词个数统计函数——words。
    功能:统计<text>中字符串中的单词个数。
    返回:返回<text>中的单词数。
    示例:$(words, foo bar baz)返回值是“3”。

文件名操作函数

$(dir <names...>)

名称:取目录函数——dir。

示例: $(dir src/foo.c hacks)返回值是“src/ ./”。

$(notdir <names...>)

名称:取文件函数——notdir。

$(notdir src/foo.c hacks)返回值是“foo.c hacks”。

$(basename <names...>)

 名称:取前缀函数——basename。

 示例:$(basename src/foo.c src-1.0/bar.c hacks)返回值是“src/foo src-1.0/bar hacks”。

(十)函数二

foreach if

call 修改参数顺序调用,并返回的函数
    reverse =  $(2) $(1)

    foo = $(call reverse,a,b)

$(origin <variable>) 变量来源于哪里。比如envirment,环境变量

 shell函数 看不下去了

控制函数 error和warning,error会导致退出,warning只是打印

(十一)make的运行

make的退出码

0 成功 1失败 

当前目录下依次找三个文件——“GNUmakefile”、“makefile”和“Makefile”。其按顺序找这三个文件,一旦找到,就开始读取这个文件并执行。

指定makefile

我们也可以给make命令指定一个特殊名字的Makefile,例如,我们有个makefile的名字是“hchen.mk”,那么,我们可以这样来让make来执行这个文件:

    make –f hchen.mk

指定目标

有一个make的环境变量叫“MAKECMDGOALS”,

sources = foo.c bar.c
    ifneq ( $(MAKECMDGOALS),clean)
    include $(sources:.c=.d)
    endif

基于上面的这个例子,只要我们输入的命令不是“make clean”,那么makefile会自动包含“foo.d”和“bar.d”这两个makefile。

还有约定俗成的指定目标如下:

“all”
        这个伪目标是所有目标的目标,其功能一般是编译所有的目标。
     “clean”
        这个伪目标功能是删除所有被make创建的文件。
     “install”
        这个伪目标功能是安装已编译好的程序,其实就是把目标执行文件拷贝到指定的目标中去。
     “print”
        这个伪目标的功能是例出改变过的源文件。
     “tar”
        这个伪目标功能是把源程序打包备份。也就是一个tar文件。
     “dist”
        这个伪目标功能是创建一个压缩文件,一般是把tar文件压成Z文件。或是gz文件。
     “TAGS”
        这个伪目标功能是更新所有的目标,以备完整地重编译使用。
     “check”和“test”
        这两个伪目标一般用来测试makefile的流程。

make的参数

-n -q -w

-debug等等,详细介绍debug

“—debug[=<options>]”
输出make的调试信息。它有几种不同的级别可供选择,如果没有参数,那就是输出最简单的调试信息。下面是<options>的取值:
    a —— 也就是all,输出所有的调试信息。(会非常的多)
    b —— 也就是basic,只输出简单的调试信息。即输出不需要重编译的目标。
    v —— 也就是verbose,在b选项的级别之上。输出的信息包括哪个makefile被解析,不需要被重编译的依赖文件(或是依赖目标)等。
    i —— 也就是implicit,输出所以的隐含规则。

(十二)隐含规则

自动推导,比如编译器会自动根据c生成对应的o文件,如果c没有找到,就会再根据p(Pascal)生成o文件

1、编译C程序的隐含规则。
“<n>.o”的目标的依赖目标会自动推导为“<n>.c”,并且其生成命令是“$(CC) –c $(CPPFLAGS) $(CFLAGS)”

2、编译C++程序的隐含规则。
“<n>.o”的目标的依赖目标会自动推导为“<n>.cc”或是“<n>.C”,并且其生成命令是“$(CXX) –c $(CPPFLAGS) $(CFLAGS)”。(建议使用“.cc”作为C++源文件的后缀,而不是“.C”)
 

隐含规则中包含一些变量,比如cc,CFLAGS等

一个目标可能被一系列的隐含规则所作用。例如,一个[.o]的文件生成,可能会是先被Yacc的[.y]文件先成[.c],然后再被C的编译器生成。我们把这一系列的隐含规则叫做“隐含规则链”。

隐含规则中间的,叫中间目标,中间目标文件一般会被删除,当然你可以通过参数指定不删除

(十三)模式规则

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

其中,"$@"表示所有的目标的挨个值,"$<"表示了所有依赖目标的挨个值。这些奇怪的变量我们叫"自动化变量",后面会详细讲述。

下面的这个例子中有两个目标是模式的:

    %.tab.c %.tab.h: %.y
            bison -d $<

这条规则告诉make把所有的[.y]文件都以"bison -d <n>.y"执行,然后生成"<n>.tab.c"和"<n>.tab.h"文件。

自动化变量

$@

$%等

如果一个目标是"foo.a(bar.o)",那么,"$%"就是"bar.o","$@"就是"foo.a"。

模式的匹配

因为"%"代表一个或多个字符,所以在定义好了的模式中,我们把"%"所匹配的内容叫做"茎",例如"%.c"所匹配的文件"test.c"中"test"就是"茎"。

如有一个模式"e%t",文件"src/eat"匹配于该模式,于是"src/a"就是其"茎",如果这个模式定义在依赖目标中,而被依赖于这个模式的目标中又有个模式"c%r",那么,目标就是"src/car"。

后面的看不下去了。。。。

(十四)函数库文件

archive(member)

这个不是一个命令,而一个目标和依赖的定义。

如果我们使用"make foo.a(bar.o)"

make执行的命令大致如下:

    cc -c bar.c -o bar.o
    ar r foo.a bar.o
    rm -f bar.o

你还可以在Makefile中书写其它的命令,如:tar、awk、mail、sed、cvs、compress、ls、rm、yacc、rpm、ftp……等等,等等,来完成诸如"程序打包"、"程序备份"、"制作程序安装包"、"提交代码"、"使用程序模板"、"合并文件"等等五花八门的功

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值