当前位置 : 主页 > 编程语言 > java >

Makefile 随手记

来源:互联网 收集:自由互联 发布时间:2022-06-23
objects = main.o kbd.o command.o display.o \ insert.osearch.o files.o utils.o edit : $(objects) cc -o edit $(objects) 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 -

objects = main.o kbd.o command.o display.o \
insert.osearch.o files.o utils.o
edit : $(objects)
cc -o edit $(objects)
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
files.o : files.c defs.h buffer.h command.h
cc -c files.c
utils.o : utils.c defs.h
cc -c utils.c
clean :
rm edit $(objects).PHONY : clean

clean :

-rm edit $(objects)

.PHONY意思表示clean是一个“伪目标”。而在rm命令前面加了一个小减号的意思就是,也许某些文件出现问题,但不要管,继续做后面的事。当然,clean的规则不要放在文件的开头,不然,这就会变成make的默认目标。“伪目标”并不是一个文件,只是一个标签,由于“伪目标”不是文件,所以make无法生成它的依赖关系和决定它是否要执行。我们只有通过显示地指明这个“目标”才能让其生效。

Makefile里主要包含了五个东西:显式规则、隐晦规则、变量定义、文件指示和注释。

  • 显式规则。显式规则说明了,如何生成一个或多的的目标文件。这是由Makefile的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。
  • 隐晦规则。由于我们的make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写Makefile,这是由make所支持的。
  • 变量的定义。在Makefile中我们要定义一系列的变量,变量一般都是字符串,这个有点你C语言中的宏,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上。
  • 文件指示。其包括了三个部分,一个是在一个Makefile中引用另一个Makefile,就像C语言中的include一样;另一个是指根据某些情况指定Makefile中的有效部分,就像C语言中的预编译#if一样;还有就是定义一个多行的命令。有关这一部分的内容,我会在后续的部分中讲述。
  • 注释。Makefile中只有行注释,和UNIX的Shell脚本一样,其注释是用“#”字符,这个就像C/C++中的“//”一样。如果你要在你的Makefile中使用“#”字符,可以用反斜框进行转义,如:“#”。

在Makefile中的命令,必须要以[Tab]键开始。

默认的情况下,make命令会在当前目录下按顺序找寻文件名为“GNUmakefile”、“makefile”、“Makefile”的文件,找到了解释这个文件。

在Makefile使用include关键字可以把别的Makefile包含进来,这很像C语言的#include,被包含的文件会原模原样的放在当前文件的包含位置。在include前面可以有一些空字符,但是绝不能是[Tab]键开始。include和可以用一个或多个空格隔开。

如果文件都没有指定绝对路径或是相对路径的话,make会在当前目录下首先寻找,如果当前目录下没有找到,那么,make还会在下面的几个目录下找:

1.如果make执行时,有“-I”或“–include-dir”参数,那么make就会在这个参数所指定的目录下去寻找。
2.如果目录/include(一般是:/usr/local/bin或/usr/include)存在的话,make也会去找。

如果有文件没有找到的话,make会生成一条警告信息,但不会马上出现致命错误。它会继续载入其它的文件,一旦完成makefile的读取,make会再重试这些没有找到,或是不能读取的文件,如果还是不行,make才会出现一条致命信息。如果你想让make不理那些无法读取的文件,而继续执行,你可以在include前加一个减号“-”。如:-include

GNU的make工作时的执行步骤入下:(想来其它的make也是类似)

  • 读入所有的Makefile。
  • 读入被include的其它Makefile。
  • 初始化文件中的变量。
  • 推导隐晦规则,并分析所有规则。
  • 为所有的目标文件创建依赖关系链。
  • 根据依赖关系,决定哪些目标要重新生成。
  • 执行生成命令。
  • 规则包含两个部分,一个是依赖关系,一个是生成目标的方法。

    在Makefile中,规则的顺序是很重要的,因为,Makefile中只应该有一个最终目标,其它的目标都是被这个目标所连带出来的,所以一定要让make知道你的最终目标是什么。

    Makefile文件中的特殊变量“VPATH”就是完成这个功能的,如果没有指明这个变量,make只会在当前的目录中去找寻依赖文件和目标文件。如果定义了这个变量,那么,make就会在当当前目录找不到的情况下,到所指定的目录中去找寻文件了。

    VPATH = src:…/headers

    上面的的定义指定两个目录,“src”和“…/headers”,make会按照这个顺序进行搜索。目录由“冒号”分隔。(当然,当前目录永远是最高优先搜索的地方)

    “$@”表示目标的集合,就像一个数组,“$@”依次取出目标,并执于命令。

    <targets…>: : <prereq-patterns …>

    targets定义了一系列的目标文件,可以有通配符。是目标的一个集合。

    target-parrtern是指明了targets的模式,也就是的目标集模式。

    prereq-parrterns是目标的依赖模式,它对target-parrtern形成的模式再进行一次依赖目标的定义。

    objects = foo.o bar.o



    all: $(objects)



    $(objects): %.o: %.c

    $(CC) -c $(CFLAGS) $< -o $@

    上面的例子中,指明了我们的目标从$object中获取,“%.o”表明要所有以“.o”结尾的目标,也就是“foo.o bar.o”,也就是变量$object集合的模式,而依赖模式“%.c”则取模式“%.o”的“%”,也就是“foobar”,并为其加上“.c”的后缀,于是,我们的依赖目标就是“foo.c bar.c”。而命令中的“Makefile 随手记_依赖关系@”则是自动化变量,“$<”表示所有依赖(也就是“foo.c bar.c”),“$@”表示所有目标(foo.o bar.o)。于是,上面的规则展开后等价于下面的规则:

    foo.o : foo.c

    $(CC) -c $(CFLAGS) foo.c -o foo.o

    bar.o : bar.c

    $(CC) -c $(CFLAGS) bar.c -o bar.o

    自动生成依赖:

    main.o : main.c defs.h

    cc -M main.c

    其输出是:

    main.o : main.c defs.h

    如果你使用GNU的C/C++编译器,你得用“-MM”参数,不然,“-M”参数会把一些标准库的头文件也包含进来。

    每条规则中的命令和操作系统Shell的命令行是一致的。==make会一按顺序一条一条的执行命令,每条命令的开头必须以[Tab]键开头,除非,命令是紧跟在依赖规则后面的分号后的。==在命令行之间中的空格或是空行会被忽略,但是如果该空格或空行是以Tab键开头的,那么make会认为其是一个空命令。

    我们在UNIX下可能会使用不同的Shell,但是make的命令默认是被“/bin/sh”——UNIX的标准Shell解释执行的。除非你特别指定一个其它的Shell。

    如果make执行时,带入make参数“-n”或“–just-print”,那么其只是显示命令,但不会执行命令,这个功能很有利于我们调试我们的Makefile,看看我们书写的命令是执行起来是什么样子的或是什么顺序的。

    通常,make会把其要执行的命令行在命令执行前输出到屏幕上。当我们用“@”字符在命令行前,那么,这个命令将不被make显示出来,最具代表性的例子是,我们用这个功能来像屏幕显示一些信息。

    需要注意的是,如果你要让上一条命令的结果应用在下一条命令时,你应该使用分号分隔这两条命令。比如你的第一条命令是cd命令,你希望第二条命令得在cd之后的基础上运行,那么你就不能把这两条命令写在两行上,而应该把这两条命令写在一行上,用分号分隔。

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

    export<variable …>

    如果你不想让某些变量传递到下级Makefile中,那么你可以这样声明:

    unexport<variable …>

    嵌套执行make:​​ $(MAKE) -C subdir​​

    foo = c
    prog.o : prog.$(foo)
    $(foo)$(foo) -$(foo) prog.$(foo)

    值得一提的是,这种方法,前面的变量不能使用后面的变量,只能使用前面已定义好了的变量。如果是这样:

    y := $(x) bar
    x := foo

    那么,y的值是“bar”,而不是“foo bar”。

    FOO ?= bar

    其含义是,如果FOO没有被定义过,那么变量FOO的值就是“bar”,如果FOO先前被定义过,那么这条语将什么也不做,其等价于:

    ifeq ($(origin FOO), undefined)
    FOO = bar
    endif

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

    这个示例中,我们先定义了一个“Makefile 随手记_Makefile_02(foo)”中所有以“.o”字串“结尾”全部替换成“.c”,所以我们的“$(bar)”的值就是“a.c b.c c.c”。

    我们可以使用“+=”操作符给变量追加值,如:

    objects = main.o foo.o bar.o utils.o
    objects += another.o

    于是,我们的$(objects)值变成:“main.o foo.o bar.o utils.o another.o”(another.o被追加进去了)

    管道符:

    f.o 目标的生成不依赖于 main.o 下面的规则。

    all : main.o
    @echo "rule 1"
    main.o : main.c func.o | f.o
    @echo "rule 2"
    gcc -c main.c -o $@
    func.o : func.c
    @echo "rule 3"
    gcc -c func.c -o $@
    f.o: f.c
    @echo "rule 4"
    gcc -c f.c -o $@
    clean:
    rm -rf *.ojiaming@jiaming-pc:~/Documents/test/temp$ make clean
    rm -rf *.o
    jiaming@jiaming-pc:~/Documents/test/temp$ make
    rule 3
    gcc -c func.c -o func.o
    rule 4
    gcc -c f.c -o f.o
    rule 2
    gcc -c main.c -o main.o
    rule 1
    jiaming@jiaming-pc:~/Documents/test/temp$ rm main.o
    jiaming@jiaming-pc:~/Documents/test/temp$ make
    rule 2
    gcc -c main.c -o main.o
    rule 1
    jiaming@jiaming-pc:~/Documents/test/temp$ rm f.o
    jiaming@jiaming-pc:~/Documents/test/temp$ make
    rule 4
    gcc -c f.c -o f.o
    rule 1

    也可以在 Makefile 中加入Makefile目标,表示当Makefile修改时,亦重新编译,像下面这样:

    $(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) Makefile
    @echo "OBJECTS: $(OBJECTS)"
    @exit -2
    $(CC) $(OBJECTS) $(LDFLAGS) -o $@
    $(SZ) $@


    【文章转自日本站群多IP服务器 http://www.558idc.com/japzq.html提供,感恩】
    上一篇:内核编译错误
    下一篇:没有了
    网友评论