c语言sscanf函数的用法是什么
300
2022-12-01
Mikefile文件的工作原理
我们写的C代码都要编译后才能运行,那么写出来的C代码怎么组织编译呢?因为有些代码可能要依赖其他的代码,编译的顺序就要有个先后。Makefile就像一张编译的清单,它可以将这些依赖关系表达清楚,让make编译工具按我们所想的去编译我们的源代码。
所以Makefile就是一份告诉make编译工具如何编译我们源代码的文件。编写一份make编译工具能看得懂的Makefile文件,以下这些知识,是我们应该要掌握的。现在就开始吧。
基本知识
规则:是Makefile用来告知make如何编译的。通常,一条规则包括三部分:
目标:先决条件(有人喜欢说是依赖) 执行的命令
执行的命令用先决条件里提供的资源(当然就是我们的源文件或其他已经生成的二进制文件)产出目标,产出的是一个二进制文件。目标像将要做的一道菜,先决条件就是组成这道菜的材料,执行的命令就是做出这道菜的方法。执行时,执行的命令用材料,做出这道菜。以下是个例子:
hello:hello.c gcc hello.c -o hello
这里,我们的目标是hello二进制文件,hello.c是要提供的先决条件,然后gcc命令编译hello.c,产出hello二进制文件。 目标也可以是虚拟的,不一定就是个二进制文件,如:
say_hello: @echo "Hello world"
这个虚拟目标say_hello只是输出一些信息而已,因此它可以没有先决条件,也不会产出任何二进制文件,这在Makefile里是允许的。 提个醒:@echo 和echo的作用是一样的,唯一不同的是有@的话,只会输出“Hello world”,否则还会输出打印的命令,如:
$ makeecho "Hello world"
一般来说,一个C项目的Makefile都有很多规则,这种情况下执行make命令时,默认只执行第一个规则,如:
say_hello: @echo "Hello World"generate: @echo "Creating text files..."clean: @echo "Cleaning up..."
$ makeHello World
确实只有第一个规则会被执行,其他的都没有被执行。如果我们不想Makefile的第一个规则成为默认执行的规则,可以使用.DEFAULT_GOAL来设定,从而改变默认执行的规则,如:
say_hello: @echo "Hello World"generate: @echo "Creating text files..."clean: @echo "Cleaning up..." .DEFAULT_GOAL :=
$ makeCreating text files...
generate规则就会在make执行时,默认被执行。
make命令也可以直接执行对应的规则,如执行clean:
$ make clean
.DEFAULT_GOAL 只能执行一个目标,有没有办法执行多个规则呢?当然!我们可以用一个虚拟目标all,来同时指定要执行的目标,但这一行要放在Makefile文件的最前面,原因是make执行会默认执行第一行,如:
all: say_hello generatesay_hello: @echo "Hello World"generate: @echo "Creating text files..."clean: @echo "Cleaning up..."
因为all say_hello generate clean都是虚拟目标,如因为它们都不支真正产出二制文件,在这个例子里,因此最好加上.PHONY来标识一下。
.PHONY: all say_hello generate cleanall: say_hello generatesay_hello: @echo "Hello World"generate: @echo "Creating text files..."clean: @echo "Cleaning up..."
.PHONY 的意思就是虚假的意思,make不会管文件或文件名是不是存在,直接执行命令。
$ makeHello WorldCreating empty text files...
执行make时,say_hello和generate会被执行。
进阶
在Makefile里可以使用变量,然后进行引用,这样用到的地方只需要引用变量即可,省去大量的冗余代码。如:
CC =
以面定义了CC变量,代表gcc命令,引用方式可以是以两种方式中的任意一种(${变量名},$(变量名)):
hello: hello.c ${CC} hello.c -o hello
hello: hello.c $(CC) hello.c -o hello
用=定义方式变量不安全,一不小心就会引发无限循环递归调用的问题,如:
CC = gccCC = ${CC}all: @echo ${CC}
错误如下:
$ makeMakefile:8: *** Recursive variable 'CC' references itself (eventually). Stop.
为了避免这种问题我们应该将=换成:=:
CC :=
最后,结合一个从别人那里复制来的例子,记录一下Makefile的了解一下模式和函数的使用:
.PHONY = all cleanCC := gcc # compiler to useLINKERFLAG = -lmSRCS := $(wildcard *.c)BINS := $(SRCS:%.c=%)all: ${BINS}%: %.o @echo "Checking.." ${CC} ${LINKERFLAG} $< -o $@%.o: %.c @echo "Creating object.." ${CC} -c $ 以#开头的行都是注释SRCS := $(wildcard *.c)这一句的$(wildcard pattern)是用于文件名的函数之一。它的意思是所有以.c结尾的文件名都会匹配上,然后这些文件就会存在SRCS变量中。BINS := $(SRCS:%.c=%)这一句里的%号就是我们要引用的部分,这一句的意思是将SRCS里存储的文件名,不包括.c部分,都提取出来存到BINS变量中。如SRCS中有hello.c那么BINS中就会有hello。all: ${BINS}这一句也很有意思,all这个虚拟目标会将BINS存在的值作为一个目标去调用。这跟我们前面讲的是一个道理。 %: %.o @echo "Checking.." ${CC} ${LINKERFLAG} $< -o $@ 在上面这几行中,我们假设BINS变量中有个值为hello,那么%就会匹配到hello,那么这条规则展开会就如下所示: hello: hello.o @echo "Checking.." gcc -lm hello.o -o hello 由此可见,$<代表的就是先决条件,$@代表的就是目标。 %.o: %.c @echo "Creating object.." ${CC} -c $< 同理,上面展开后,如下所示: hello.o: hello.c @echo "Creating object.." gcc -c hello.c 我觉得讲到这,也差不多了。有问题随时都可以交流。
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~