精华内容
下载资源
问答
  • Linux Make 命令

    2016-12-13 22:49:08
    但是实际上 ,任何只要某个文件有变化,就要重新构建的项目,都可以用Make构建。本文介绍Make命令的用法,从简单的讲起,不需要任何基础,只要会使用命令行,就能看懂。我的参考资料主要是Isaac Schlueter的

    代码变成可执行文件,叫做编译(compile);先编译这个,还是先编译那个(即编译的安排),叫做构建(build)。

    Make是最常用的构建工具,诞生于1977年,主要用于C语言的项目。但是实际上 ,任何只要某个文件有变化,就要重新构建的项目,都可以用Make构建。

    本文介绍Make命令的用法,从简单的讲起,不需要任何基础,只要会使用命令行,就能看懂。我的参考资料主要是Isaac Schlueter的《Makefile文件教程》和《GNU Make手册》。

    一、Make的概念

    Make这个词,英语的意思是”制作”。Make命令直接用了这个意思,就是要做出某个文件。比如,要做出文件a.txt,就可以执行下面的命令。

    $ make a.txt

    但是,如果你真的输入这条命令,它并不会起作用。因为Make命令本身并不知道,如何做出a.txt,需要有人告诉它,如何调用其他命令完成这个目标。

    比如,假设文件 a.txt 依赖于 b.txt 和 c.txt ,是后面两个文件连接(cat命令)的产物。那么,make 需要知道下面的规则。

    a.txt: b.txt c.txt
    cat b.txt c.txt > a.txt

    也就是说,make a.txt 这条命令的背后,实际上分成两步:第一步,确认 b.txt 和 c.txt 必须已经存在,第二步使用 cat 命令 将这个两个文件合并,输出为新文件。

    像这样的规则,都写在一个叫做Makefile的文件中,Make命令依赖这个文件进行构建。Makefile文件也可以写为makefile, 或者用命令行参数指定为其他文件名。

    $ make -f rules.txt
    # 或者
    $ make --file=rules.txt

    上面代码指定make命令依据rules.txt文件中的规则,进行构建。

    总之,make只是一个根据指定的Shell命令进行构建的工具。它的规则很简单,你规定要构建哪个文件、它依赖哪些源文件,当那些文件有变动时,如何重新构建它。

    二、Makefile文件的格式

    构建规则都写在Makefile文件里面,要学会如何Make命令,就必须学会如何编写Makefile文件。

    2.1 概述

    Makefile文件由一系列规则(rules)构成。每条规则的形式如下。

    <target> : <prerequisites>
    [tab]  <commands>

    上面第一行冒号前面的部分,叫做”目标”(target),冒号后面的部分叫做”前置条件”(prerequisites);第二行必须由一个tab键起首,后面跟着”命令”(commands)。

    “目标”是必需的,不可省略;”前置条件”和”命令”都是可选的,但是两者之中必须至少存在一个。

    每条规则就明确两件事:构建目标的前置条件是什么,以及如何构建。下面就详细讲解,每条规则的这三个组成部分。

    2.2 目标(target)

    一个目标(target)就构成一条规则。目标通常是文件名,指明Make命令所要构建的对象,比如上文的 a.txt 。目标可以是一个文件名,也可以是多个文件名,之间用空格分隔。

    除了文件名,目标还可以是某个操作的名字,这称为”伪目标”(phony target)。

    clean:
    rm *.o

    上面代码的目标是clean,它不是文件名,而是一个操作的名字,属于”伪目标 “,作用是删除对象文件。

    $ make  clean

    但是,如果当前目录中,正好有一个文件叫做clean,那么这个命令不会执行。因为Make发现clean文件已经存在,就认为没有必要重新构建了,就不会执行指定的rm命令。

    为了避免这种情况,可以明确声明clean是”伪目标”,写法如下。

    .PHONY: clean
    clean:
    rm *.o temp

    声明clean是”伪目标”之后,make就不会去检查是否存在一个叫做clean的文件,而是每次运行都执行对应的命令。像.PHONY这样的内置目标名还有不少,可以查看手册。

    如果Make命令运行时没有指定目标,默认会执行Makefile文件的第一个目标。

    $ make

    上面代码执行Makefile文件的第一个目标。

    2.3 前置条件(prerequisites)

    前置条件通常是一组文件名,之间用空格分隔。它指定了”目标”是否重新构建的判断标准:只要有一个前置文件不存在,或者有过更新(前置文件的last-modification时间戳比目标的时间戳新),”目标”就需要重新构建。

    result.txt: source.txt
    cp source.txt result.txt

    上面代码中,构建 result.txt 的前置条件是 source.txt 。如果当前目录中,source.txt 已经存在,那么make result.txt可以正常运行,否则必须再写一条规则,来生成 source.txt 。

    source.txt:
        echo "this is the source" > source.txt

    上面代码中,source.txt后面没有前置条件,就意味着它跟其他文件都无关,只要这个文件还不存在,每次调用make source.txt,它都会生成。

    $ make result.txt
    $ make result.txt

    上面命令连续执行两次make result.txt。第一次执行会先新建 source.txt,然后再新建 result.txt。第二次执行,Make发现 source.txt 没有变动(时间戳晚于 result.txt),就不会执行任何操作,result.txt 也不会重新生成。

    如果需要生成多个文件,往往采用下面的写法。

    source: file1 file2 file3

    上面代码中,source 是一个伪目标,只有三个前置文件,没有任何对应的命令。

    $ make source

    执行make source命令后,就会一次性生成 file1,file2,file3 三个文件。这比下面的写法要方便很多。

    $ make file1
    $ make file2
    $ make file3

    2.4 命令(commands)

    命令(commands)表示如何更新目标文件,由一行或多行的Shell命令组成。它是构建”目标”的具体指令,它的运行结果通常就是生成目标文件。

    每行命令之前必须有一个tab键。如果想用其他键,可以用内置变量.RECIPEPREFIX声明。

    .RECIPEPREFIX = >
    all:
    > echo Hello, world

    上面代码用.RECIPEPREFIX指定,大于号(>)替代tab键。所以,每一行命令的起首变成了大于号,而不是tab键。

    需要注意的是,每行命令在一个单独的shell中执行。这些Shell之间没有继承关系。

    var-lost:
    export foo=bar
    echo "foo=[$$foo]"

    上面代码执行后(make var-lost),取不到foo的值。因为两行命令在两个不同的进程执行。一个解决办法是将两行命令写在一行,中间用分号分隔。

    var-kept:
        export foo=bar; echo "foo=[$$foo]"

    另一个解决办法是在换行符前加反斜杠转义。

    var-kept:
    export foo=bar; \
    echo "foo=[$$foo]"

    最后一个方法是加上.ONESHELL:命令。

    .ONESHELL:var-kept:
        export foo=bar; 
        echo "foo=[$$foo]"

    三、Makefile文件的语法

    3.1 注释

    井号(#)在Makefile中表示注释。

    # 这是注释
    result.txt: source.txt
    # 这是注释
    cp source.txt result.txt # 这也是注释

    3.2 回声(echoing)

    正常情况下,make会打印每条命令,然后再执行,这就叫做回声(echoing)。

    test:
    # 这是测试
    执行上面的规则,会得到下面的结果。

    $ make test# 这是测试

    在命令的前面加上@,就可以关闭回声。

    test:
        @# 这是测试

    现在再执行make test,就不会有任何输出。

    由于在构建过程中,需要了解当前在执行哪条命令,所以通常只在注释和纯显示的echo命令前面加上@。

    test:
        @# 这是测试    @echo TODO

    3.3 通配符

    通配符(wildcard)用来指定一组符合条件的文件名。Makefile 的通配符与 Bash 一致,主要有星号()、问号(?)和 […] 。比如, .o 表示所有后缀名为o的文件。

    clean:
            rm -f *.o

    3.4 模式匹配

    Make命令允许对文件名,进行类似正则运算的匹配,主要用到的匹配符是%。比如,假定当前目录下有 f1.c 和 f2.c 两个源码文件,需要将它们编译为对应的对象文件。

    %.o: %.c

    等同于下面的写法。

    f1.o: f1.c
    f2.o: f2.c

    使用匹配符%,可以将大量同类型的文件,只用一条规则就完成构建。

    3.5 变量和赋值符

    Makefile 允许使用等号自定义变量。

    txt = Hello World
    test:
        @echo $(txt)

    上面代码中,变量 txt 等于 Hello World。调用时,变量需要放在 $( ) 之中。

    调用Shell变量,需要在美元符号前,再加一个美元符号,这是因为Make命令会对美元符号转义。

    test:
        @echo $$HOME

    有时,变量的值可能指向另一个变量。

    v1 = $(v2)

    上面代码中,变量 v1 的值是另一个变量 v2。这时会产生一个问题,v1 的值到底在定义时扩展(静态扩展),还是在运行时扩展(动态扩展)?如果 v2 的值是动态的,这两种扩展方式的结果可能会差异很大。

    为了解决类似问题,Makefile一共提供了四个赋值运算符 (=、:=、?=、+=),它们的区别请看

    StackOverflow。
    VARIABLE = value
    # 在执行时扩展,允许递归扩展。
    
    VARIABLE := value
    # 在定义时扩展。
    
    VARIABLE ?= value
    # 只有在该变量为空时才设置值。
    
    VARIABLE += value
    # 将值追加到变量的尾端。

    3.6 内置变量(Implicit Variables)

    Make命令提供一系列内置变量,比如,(CC)使(MAKE) 指向当前使用的Make工具。这主要是为了跨平台的兼容性,详细的内置变量清单见手册。

    output:
        $(CC) -o output input.c

    3.7 自动变量(Automatic Variables)

    Make命令还提供一些自动变量,它们的值与当前规则有关。主要有以下几个。

    (1)$@

    $@指代当前目标,就是Make命令当前构建的那个目标。比如,make foo的 $@ 就指代foo。
    a.txt b.txt: 
        touch $@
    等同于下面的写法。
    a.txt:
        touch a.txt
    b.txt:
        touch b.txt

    (2)$<

    $< 指代第一个前置条件。比如,规则为 t: p1 p2,那么$< 就指代p1。
    a.txt: b.txt c.txt
        cp $< $@ 
    等同于下面的写法。
    a.txt: b.txt c.txt
        cp b.txt a.txt 

    (3)$?

    ?t:p1p2p2t?就指代p2。

    (4)$^

    t:p1p2^ 就指代 p1 p2 。

    (5)$*

    * 就表示 f1。

    (6)(@D)(@F)

    (@D)(@F) 分别指向 @@是 src/input.c,那么(@D)src(@F) 的值为 input.c。

    (7)(<D)(

    dest/%.txt: src/%.txt
        @[ -d dest ] || mkdir dest
        cp $< $@

    上面代码将 src 目录下的 txt 文件,拷贝到 dest 目录下。首先判断 dest 目录是否存在,如果不存在就新建,然后,<src/@ 指代目标文件(dest/%.txt)。

    3.8 判断和循环

    Makefile使用 Bash 语法,完成判断和循环。

    ifeq ($(CC),gcc)
      libs=$(libs_for_gcc)else
      libs=$(normal_libs)endif

    上面代码判断当前编译器是否 gcc ,然后指定不同的库文件。

    LIST = one two three
    all:
    for i in $(LIST); do \
    echo $$i; \
    done
    # 等同于
    
    all:a
    for i in one two three; do \
    echo $i; \
    done
    上面代码的运行结果。
    one
    two
    three

    3.9 函数

    Makefile 还可以使用函数,格式如下。

    $(function arguments)# 或者${function arguments}

    Makefile提供了许多内置函数,可供调用。下面是几个常用的内置函数。

    (1)shell 函数

    shell 函数用来执行 shell 命令

    srcfiles := $(shell echo src/{00..99}.txt)

    (2)wildcard 函数

    wildcard 函数用来在 Makefile 中,替换 Bash 的通配符。

    srcfiles := $(wildcard src/*.txt)

    (3)subst 函数

    subst 函数用来文本替换,格式如下。

    $(subst from,to,text)

    下面的例子将字符串”feet on the street”替换成”fEEt on the strEEt”。

    $(subst ee,EE,feet on the street)

    下面是一个稍微复杂的例子。

    comma:= ,
    empty:=
    # space变量用两个空变量作为标识符,当中是一个空格
    space:= $(empty) $(empty)
    foo:= a b c
    bar:= $(subst $(space),$(comma),$(foo))
    # bar is now `a,b,c'.

    (4)patsubst函数

    patsubst 函数用于模式匹配的替换,格式如下。

    $(patsubst pattern,replacement,text)

    下面的例子将文件名”x.c.c bar.c”,替换成”x.c.o bar.o”。

    $(patsubst %.c,%.o,x.c.c bar.c)

    (5)替换后缀名

    替换后缀名函数的写法是:变量名 + 冒号 + 后缀名替换规则。它实际上patsubst函数的一种简写形式。

    min: $(OUTPUT:.js=.min.js)

    上面代码的意思是,将变量OUTPUT中的后缀名 .js 全部替换成 .min.js 。

    四、Makefile 的实例

    (1)执行多个目标

    .PHONY: cleanall cleanobj cleandiff
    
    cleanall : cleanobj cleandiff
    rm program
    
    cleanobj :
    rm *.o
    
    cleandiff :
    rm *.diff

    上面代码可以调用不同目标,删除不同后缀名的文件,也可以调用一个目标(cleanall),删除所有指定类型的文件。

    (2)编译C语言项目

    edit : main.o kbd.o command.o display.o
    cc -o edit main.o kbd.o command.o display.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
    cc -c display.c
    
    clean :
    rm edit main.o kbd.o command.o display.o
    
    .PHONY: edit clean

    今天,Make命令的介绍就到这里。

    展开全文
  • 怎么使用make、makefile3.1依赖关系和依赖方法3.2构建多工程简洁方法4.make、makefile原理5.编译器如何知道生成的软件需要重新编译 1.make、makefile是什么 make是一个命令,makefile是一个文件,通常该文件会在当前...

    1.make、makefile是什么

    make是一个命令,makefile是一个文件,通常该文件会在当前的工作目录下存放
    makefile中保存依赖关系和依赖方法

    2.为什么要存在make和makefile

    在vs编辑器中,我们创建多文件的时候是不需要自己管理的,vs自动进行项目管理。
    在Linux中,维护项目关系的工作需要让make和makefile来完成;
    在这里插入图片描述

    3.怎么使用make、makefile

    3.1依赖关系和依赖方法

    依赖关系:决定了能不能这样做,表明依赖对象(比如,你可以取商店买东西,不能去马路上买东西)
    依赖方法:决定了如何做,去做什么

    在这里插入图片描述
    在这里插入图片描述

    3.2构建多工程简洁方法

    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    4.make、makefile原理

    在这里插入图片描述

    5.编译器如何知道生成的软件需要重新编译

    是根据文件的修改时间来确定的,因为用户不可能同时修改多个问题,所有文件的修改总是有先后顺序的,又因为,源文件和可执行程序的时间总是交叉的(现有源文件才有可执行程序,运行程序的时候,源文件早已存在)
    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • Linux Make 命令教程

    2019-04-20 22:06:39
    作者丨阮一峰的网络日志 www.ruanyifeng.com/blog/2015/02/make.html 代码变成可执行文件,叫做编译...但是实际上 ,任何只要某个文件有变化,就要重新构建的项目,都可以用Make构建。 本文介绍Make命令的用...

    作者丨阮一峰的网络日志
    www.ruanyifeng.com/blog/2015/02/make.html

    代码变成可执行文件,叫做编译(compile);先编译这个,还是先编译那个(即编译的安排),叫做构建(build)。

    Make是最常用的构建工具,诞生于1977年,主要用于C语言的项目。但是实际上 ,任何只要某个文件有变化,就要重新构建的项目,都可以用Make构建。

    本文介绍Make命令的用法,从简单的讲起,不需要任何基础,只要会使用命令行,就能看懂。我的参考资料主要是Isaac Schlueter的《Makefile文件教程》和《GNU Make手册》。

    一、Make的概念

    Make这个词,英语的意思是"制作"。Make命令直接用了这个意思,就是要做出某个文件。比如,要做出文件a.txt,就可以执行下面的命令。

    $ make a.txt
    

    但是,如果你真的输入这条命令,它并不会起作用。因为Make命令本身并不知道,如何做出a.txt,需要有人告诉它,如何调用其他命令完成这个目标。

    比如,假设文件 a.txt 依赖于 b.txt 和 c.txt ,是后面两个文件连接(cat命令)的产物。那么,make 需要知道下面的规则。

    a.txt: b.txt c.txt
    cat b.txt c.txt > a.txt
    

    也就是说,make a.txt 这条命令的背后,实际上分成两步:第一步,确认 b.txt 和 c.txt 必须已经存在,第二步使用 cat 命令 将这个两个文件合并,输出为新文件。

    像这样的规则,都写在一个叫做Makefile的文件中,Make命令依赖这个文件进行构建。Makefile文件也可以写为makefile, 或者用命令行参数指定为其他文件名。

    $ make -f rules.txt
    # 或者
    $ make --file=rules.txt
    

    上面代码指定make命令依据rules.txt文件中的规则,进行构建。

    总之,make只是一个根据指定的Shell命令进行构建的工具。它的规则很简单,你规定要构建哪个文件、它依赖哪些源文件,当那些文件有变动时,如何重新构建它。

    二、Makefile文件的格式

    构建规则都写在Makefile文件里面,要学会如何Make命令,就必须学会如何编写Makefile文件。

    2.1 概述

    Makefile文件由一系列规则(rules)构成。每条规则的形式如下。

    <target> : <prerequisites>
    [tab]  <commands>
    

    上面第一行冒号前面的部分,叫做"目标"(target),冒号后面的部分叫做"前置条件"(prerequisites);第二行必须由一个tab键起首,后面跟着"命令"(commands)。

    "目标"是必需的,不可省略;"前置条件"和"命令"都是可选的,但是两者之中必须至少存在一个。

    每条规则就明确两件事:构建目标的前置条件是什么,以及如何构建。下面就详细讲解,每条规则的这三个组成部分。

    2.2 目标(target)

    一个目标(target)就构成一条规则。目标通常是文件名,指明Make命令所要构建的对象,比如上文的 a.txt 。目标可以是一个文件名,也可以是多个文件名,之间用空格分隔。

    除了文件名,目标还可以是某个操作的名字,这称为"伪目标"(phony target)。

    clean:
    rm *.o
    

    上面代码的目标是clean,它不是文件名,而是一个操作的名字,属于"伪目标 ",作用是删除对象文件。

    $ make  clean
    

    但是,如果当前目录中,正好有一个文件叫做clean,那么这个命令不会执行。因为Make发现clean文件已经存在,就认为没有必要重新构建了,就不会执行指定的rm命令。

    为了避免这种情况,可以明确声明clean是"伪目标",写法如下。

    .PHONY: clean
    clean:
    rm *.o temp
    

    声明clean是"伪目标"之后,make就不会去检查是否存在一个叫做clean的文件,而是每次运行都执行对应的命令。像.PHONY这样的内置目标名还有不少,可以查看手册。

    如果Make命令运行时没有指定目标,默认会执行Makefile文件的第一个目标。

    $ make
    

    上面代码执行Makefile文件的第一个目标。

    2.3 前置条件(prerequisites)

    前置条件通常是一组文件名,之间用空格分隔。它指定了"目标"是否重新构建的判断标准:只要有一个前置文件不存在,或者有过更新(前置文件的last-modification时间戳比目标的时间戳新),"目标"就需要重新构建。

    result.txt: source.txt
    cp source.txt result.txt
    

    上面代码中,构建 result.txt 的前置条件是 source.txt 。如果当前目录中,source.txt 已经存在,那么make result.txt可以正常运行,否则必须再写一条规则,来生成 source.txt 。

    source.txt:
        echo "this is the source" > source.txt
    

    上面代码中,source.txt后面没有前置条件,就意味着它跟其他文件都无关,只要这个文件还不存在,每次调用make source.txt,它都会生成。

    $ make result.txt
    $ make result.txt
    

    上面命令连续执行两次make result.txt。第一次执行会先新建 source.txt,然后再新建 result.txt。第二次执行,Make发现 source.txt 没有变动(时间戳晚于 result.txt),就不会执行任何操作,result.txt 也不会重新生成。

    如果需要生成多个文件,往往采用下面的写法。

    source: file1 file2 file3
    

    上面代码中,source 是一个伪目标,只有三个前置文件,没有任何对应的命令。

    $ make source
    

    执行make source命令后,就会一次性生成 file1,file2,file3 三个文件。这比下面的写法要方便很多。

    $ make file1
    $ make file2
    $ make file3
    

    2.4 命令(commands)

    命令(commands)表示如何更新目标文件,由一行或多行的Shell命令组成。它是构建"目标"的具体指令,它的运行结果通常就是生成目标文件。

    每行命令之前必须有一个tab键。如果想用其他键,可以用内置变量.RECIPEPREFIX声明。

    .RECIPEPREFIX = >
    all:
    > echo Hello, world
    

    上面代码用.RECIPEPREFIX指定,大于号(>)替代tab键。所以,每一行命令的起首变成了大于号,而不是tab键。

    需要注意的是,每行命令在一个单独的shell中执行。这些Shell之间没有继承关系。

    var-lost:
    export foo=bar
    echo "foo=[$$foo]"
    
    

    上面代码执行后(make var-lost),取不到foo的值。因为两行命令在两个不同的进程执行。一个解决办法是将两行命令写在一行,中间用分号分隔。

    另一个解决办法是在换行符前加反斜杠转义。

    var-kept:
    export foo=bar; \
    echo "foo=[$$foo]"
    

    最后一个方法是加上.ONESHELL:命令。

    .ONESHELL:var-kept:
        export foo=bar;
        echo "foo=[$$foo]"
    

    三、Makefile文件的语法

    3.1 注释

    井号(#)在Makefile中表示注释。

    # 这是注释
    result.txt: source.txt
    # 这是注释
    cp source.txt result.txt # 这也是注释
    

    3.2 回声(echoing)

    正常情况下,make会打印每条命令,然后再执行,这就叫做回声(echoing)。

    test:
    # 这是测试
    

    执行上面的规则,会得到下面的结果。

    $ make test# 这是测试
    

    在命令的前面加上@,就可以关闭回声。

    test:
        @# 这是测试
    

    现在再执行make test,就不会有任何输出。

    由于在构建过程中,需要了解当前在执行哪条命令,所以通常只在注释和纯显示的echo命令前面加上@。

    test:
        @# 这是测试    @echo TODO
    

    3.3 通配符

    通配符(wildcard)用来指定一组符合条件的文件名。Makefile 的通配符与 Bash 一致,主要有星号(*)、问号(?)和 […] 。比如, *.o 表示所有后缀名为o的文件。

    clean:
            rm -f *.o
    

    3.4 模式匹配

    Make命令允许对文件名,进行类似正则运算的匹配,主要用到的匹配符是%。比如,假定当前目录下有 f1.c 和 f2.c 两个源码文件,需要将它们编译为对应的对象文件。

    %.o: %.c
    

    等同于下面的写法。

    f1.o: f1.c
    f2.o: f2.c
    
    

    使用匹配符%,可以将大量同类型的文件,只用一条规则就完成构建。

    3.5 变量和赋值符

    Makefile 允许使用等号自定义变量。

    txt = Hello World
    test:
        @echo $(txt)
    

    上面代码中,变量 txt 等于 Hello World。调用时,变量需要放在 $( ) 之中。

    调用Shell变量,需要在美元符号前,再加一个美元符号,这是因为Make命令会对美元符号转义。

    test:
        @echo $$HOME
    

    有时,变量的值可能指向另一个变量。

    v1 = $(v2)
    
    

    上面代码中,变量 v1 的值是另一个变量 v2。这时会产生一个问题,v1 的值到底在定义时扩展(静态扩展),还是在运行时扩展(动态扩展)?如果 v2 的值是动态的,这两种扩展方式的结果可能会差异很大。

    为了解决类似问题,Makefile一共提供了四个赋值运算符 (=、:=、?=、+=),它们的区别请看StackOverflow。

    VARIABLE = value
    # 在执行时扩展,允许递归扩展。
    
    VARIABLE := value
    # 在定义时扩展。
    
    VARIABLE ?= value
    # 只有在该变量为空时才设置值。
    
    VARIABLE += value
    # 将值追加到变量的尾端。
    

    3.6 内置变量(Implicit Variables)

    Make命令提供一系列内置变量,比如,(CC)使(CC) 指向当前使用的编译器,(MAKE) 指向当前使用的Make工具。这主要是为了跨平台的兼容性,详细的内置变量清单见手册。

    output:
        $(CC) -o output input.c
    

    3.7 自动变量(Automatic Variables)

    Make命令还提供一些自动变量,它们的值与当前规则有关。主要有以下几个。

    (1)$@

    $@指代当前目标,就是Make命令当前构建的那个目标。比如,make foo的 $@ 就指代foo。

    a.txt b.txt:
        touch $@
    

    等同于下面的写法。

    a.txt:
        touch a.txt
    b.txt:
        touch b.txt
    
    

    (2)$<

    &lt;t:p1p2&lt; 指代第一个前置条件。比如,规则为 t: p1 p2,那么< 就指代p1。

    a.txt: b.txt c.txt
        cp $< $@
    
    

    等同于下面的写法。

    a.txt: b.txt c.txt
        cp b.txt a.txt
    
    

    (3)$?

    ?t:p1p2p2t? 指代比目标更新的所有前置条件,之间以空格分隔。比如,规则为 t: p1 p2,其中 p2 的时间戳比 t 新,?就指代p2。

    (4)$^

    $^ 指代所有前置条件,之间以空格分隔。比如,规则为 t: p1 p2,那么 $^ 就指代 p1 p2 。

    (5)$*

    * 指代匹配符 % 匹配的部分, 比如% 匹配 f1.txt 中的f1 ,* 就表示 f1。

    (6)$(@D) 和 $(@F)

    $(@D) 和 $(@F) 分别指向 @@ 的目录名和文件名。比如,@是 src/input.c,那么(@D)src(@D) 的值为 src ,(@F) 的值为 input.c。

    (7)$(<D) 和 $(<F)

    $(<D) 和 $(<F) 分别指向 $< 的目录名和文件名。

    所有的自动变量清单,请看手册。下面是自动变量的一个例子。

    dest/%.txt: src/%.txt
        @[ -d dest ] || mkdir dest
        cp $< $@
    

    上面代码将 src 目录下的 txt 文件,拷贝到 dest 目录下。首先判断 dest 目录是否存在,如果不存在就新建,然后,$< 指代前置文件(src/%.txt), $@ 指代目标文件(dest/%.txt)。

    3.8 判断和循环

    Makefile使用 Bash 语法,完成判断和循环。

    ifeq ($(CC),gcc)
      libs=$(libs_for_gcc)else
      libs=$(normal_libs)endif
    

    上面代码判断当前编译器是否 gcc ,然后指定不同的库文件。

    LIST = one two three
    all:
    for i in $(LIST); do \
    echo $$i; \
    done
    
    

    #等同于

    all:a
    for i in one two three; do \
    echo $i; \
    done
    

    上面代码的运行结果。

    one
    two
    three
    

    3.9 函数

    Makefile 还可以使用函数,格式如下。

    $(function arguments)# 或者${function arguments}
    

    Makefile提供了许多内置函数,可供调用。下面是几个常用的内置函数。

    (1)shell 函数

    shell 函数用来执行 shell 命令

    srcfiles := $(wildcard src/*.txt)
    

    (2)wildcard 函数

    wildcard 函数用来在 Makefile 中,替换 Bash 的通配符。

    srcfiles := $(wildcard src/*.txt)
    
    

    (3)subst 函数

    subst 函数用来文本替换,格式如下。

    $(subst from,to,text)
    

    下面的例子将字符串"feet on the street"替换成"fEEt on the strEEt"。

    $(subst ee,EE,feet on the street)
    

    下面是一个稍微复杂的例子。

    comma:= ,
    empty:=
    # space变量用两个空变量作为标识符,当中是一个空格
    space:= $(empty) $(empty)
    foo:= a b c
    bar:= $(subst $(space),$(comma),$(foo))
    # bar is now `a,b,c'.
    

    (4)patsubst函数

    patsubst 函数用于模式匹配的替换,格式如下。

    $(patsubst pattern,replacement,text)
    
    

    下面的例子将文件名"x.c.c bar.c",替换成"x.c.o bar.o"。

    $(patsubst %.c,%.o,x.c.c bar.c)
    

    (5)替换后缀名

    替换后缀名函数的写法是:变量名 + 冒号 + 后缀名替换规则。它实际上patsubst函数的一种简写形式。

    min: $(OUTPUT:.js=.min.js)
    
    

    上面代码的意思是,将变量OUTPUT中的后缀名 .js 全部替换成 .min.js 。

    四、Makefile 的实例

    (1)执行多个目标

    PHONY: cleanall cleanobj cleandiff
    
    cleanall : cleanobj cleandiff
    rm program
    
    cleanobj :
    rm *.o
    
    cleandiff :
    rm *.diff
    

    上面代码可以调用不同目标,删除不同后缀名的文件,也可以调用一个目标(cleanall),删除所有指定类型的文件。

    (2)编译C语言项目

    edit : main.o kbd.o command.o display.o
    cc -o edit main.o kbd.o command.o display.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
    cc -c display.c
    
    clean :
    rm edit main.o kbd.o command.o display.o
    
    .PHONY: edit clean
    
    展开全文
  • 一个工程中的源文件不计其数,按类型、功能、模块分别放在若干目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至进行更复杂的功能操作。 makefile...

    背景知识

    • 会写makefile,从侧面说明了这个人具备了一定完成大型工程的能力,这足以说明makefile的重要性。
    • 一个工程中的源文件不计其数,按类型、功能、模块分别放在若干目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至进行更复杂的功能操作。
    • makefile带来的好处就是“自动化编译”,一旦写好了makefile,只要make一下,整个工程完全自动编译,极大的提高了软件开发的效率。
    • make是一个命令工具,是一个解释makefile中指令的命令工具。make是一条命令,makefile是一个文件,两个搭配使用,完成项目的自动化构建。

    实例代码

    1.写一个简单的C代码:test.c

    2.创建一个Makefile,然后编写Makefile

    依赖关系

    • 上面的文件test,依赖test.o
    • test.o依赖test.s
    • test.s依赖test.i
    • test.i依赖test.c

    依赖方法

    • gcc test.* -option test.*,就是与之对应的依赖关系。

    make的工作原理

    1. 当我们输入make命令后,make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
    2. 如果找到,它会找文件中的第一个目标文件(target),如上面的例子,它会找到“test”这个文件,并把这个文件作为最终的目标文件。
    3. 如果test文件不存在,或test所依赖的后面的test.o文件的文件修改时间要比test这个文件新,那么,它就会执行后面所定义的命令来生成test这个文件。
    4.  如果test所依赖的test.o文件不存在,那么make会在当前文件中找目标为test.o文件的依赖性,如果
      找到则再根据那一个规则生成test.o文件。(这有点像一个堆栈的过程)
    5. 当然,如果C文件和H文件是存在的话,make会生成test.o文件,然后再用test.o文件声明make的终极任务,也就是执行文件test
    6. 这就是整个make的依赖性,make会一层又一层的去寻找文件袋依赖关系,直到最终编译出第一个目标文件。在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,
      而对于所定义的命令的错误,或是编译不成功,make根本不理。

    项目清理

    • 项目是需要清理的,像clean这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,不过,我们可以显示要make执行。即命令——“make clean”,以此来清除所有的目标文件,以便重编译。
    • 但是一般我们这种clean的目标文件,我们将它设置为伪目标,用 .PHONY 修饰,伪目标的特性是,总是被
      执行的。

    总结Makefile的一些使用技巧

    一个多文件项目的Makefile文件,以C语言为例
    
    1.定义编译器、连接器
        CC=gcc
        LD=gcc
    2.通配符函数表示目录下所有.c文件,相当于SRCS=test.c a.c b.c ...
        SRCS=$(wildcard *.c)
    
    3.通配符函数把列表中的.c全部替换为.o,相当于:OBJS=test.o a.o b.o ...
        OBJS=$(patsubst %c,%o,$(SRCS))
    
    4.可执行文件的名字
        TARGET=test
    
    5.要生成的目标文件
        all:$(TARGET)
    
    6.PHONY伪目标
    .PHONY:all clean
    
    7.依赖关系:冒号后面为依赖的文件,相当于test:test.o
    
    8.规则:$@表示目标文件,$^表示所有依赖文件,$<表示第一个依赖文件
    $(TARGET):$(OBJS)
    $(LD) -o $@ $^
       
    9.上一句目标文件依赖的所有.o文件,这句表示所有.o都由相应名字的.c文件自动生成
        %o:%c
        $(CC) -c $^
    
    10.make clean删除所有.o和目标文件
        clean:
        rm -f $(OBJS) $(TARGET)
    
    
    

    分享一个关于Makefile详细介绍的文章以供学习

    https://www.cnblogs.com/mfryf/p/3305778.html

    小程序之进度条


    首先我们要明白换行(\n)回车(\r)的概念,这里我们可以参考别人的总结

    https://www.pythontab.com/html/2017/linuxkaiyuan_0115/1116.html

    缓冲区

    缓冲区分为三种:空缓冲、行缓冲、全缓冲

    空缓冲:没有缓冲,也就是信息在输入输出的时候,立刻输入或输出。例如:标准错误流stderr。

    行缓冲:当输入输出的时候,遇到换行才执行I/O操作。

    全缓冲:当输入输出写满缓冲区才执,行I/O操作。

    1.

    #include<stdio.h>
    #include<unistd.h>
    
    in main()
    {
        printf("hello Makefile!");
        sleep(3);
        return 0;
    }

    现象:经过3秒,hello Makefile!打印在屏幕上,没有换行

    2.

    #include<stdio.h>
    #include<unistd.h>
    
    in main()
    {
        printf("hello Makefile!\n");
        sleep(3);
        return 0;
    }

    现象:立即显示hello Makefile!,换行,然后停了3秒钟之后结束。(这是行缓冲,遇到换行直接进行I/O操作)

    3.

    #include<stdio.h>
    #include<unistd.h>
    
    in main()
    {
        printf("hello Makefile!\n");
        fprintf(stderr,"hehe\n");
        sleep(3);
        return 0;
    }

    现象:第一行是行缓冲,直接输出 hello Makefile!;第二行是空缓冲,也直接输出hehe;然后停三秒结束。

    4.

    #include<stdio.h>
    #include<unistd.h>
    
    in main()
    {
        printf("hello Makefile!\n");
        fflush(stdout);
        sleep(3);
        return 0;
    }

    现象:立即显示hello Makefile!,换行,然后停了3秒钟之后结束。(和第二种情况现象一样)

    实现进度条

    实现进度条使用的输出函数是printf函数,printf输出函数是一个行缓冲函数,先写到缓冲区,满足条件就将缓冲区的数据刷到对应文件中。满足下列条件之一,缓冲区都会刷新:

    • 缓冲区填满
    • 写入的字符中有‘\n’或‘\r’
    • 调用fflush刷新缓冲区
    • 调用scanf从缓冲区获取数据时,也会刷新缓冲区

    实现进度条用的是行缓冲(printf),所以我们需要使用缓冲区刷新函数fflush来输出,否则我们看到的进度条将是一段一段的输出。

    着重区分‘\n’和‘\r’

    '\n':表示换行,将光标指向下一行的开头位置。

    '\r':表示回车,即每次回到行首。

    代码实现:

    #include<stdio.h>
    #include<string.h>
    
    int main()
    {
        int i=0;
        char bar[102];
        memset(bar,'\0',sizeof(bar)*sizeof(char));
        const char*lable="|/-\\";//这里的两个\\表示一个\
        while(i<=100)
        {
            printf("[%-100s][%d%%][%c]\r",bar,i,lable[i%4]);//这里要注意一些转义字符,%%输出的就是%.
            //其中[%-100s]表示以字符串输出,有100个字符位,从左往右输出,如果不加-,即从右往左输出。
            //后面加一个\r回车,即将光标移到行首,接下输出的字符将覆盖行首的字符,所以会看到连续的#出现
            fflush(stdout);
            bar[i++]='#';
            usleep(100000);
        }
        printf("\n");
        return 0;
    }

    现象:

     

    使用git命令行在GitHub上创建项目


    第一步:注册账号

    比较简单,直接在官网上根据提示注册账号,需要进行邮箱校验。

    第二步:创建项目

    1.登录成功后,进入个人主页,点击下方的New repository按钮新建项目

    2.跳转页面后,点击下方的Create repository按钮确认创建。

    3.在创建好的项目页面中复制项目的链接,以备接下来进行下载。

    第三步:下载到本地

    创建好一个放置代码的目录

    git clone [url] url是刚才创建项目页面中的项目链接

    三板斧第一招:git add

    将代码放到刚才创建好的目录中

    git add [文件名]    将需要用git管理的文件告知git

    三板斧第二招:git commit

    提交改动到本地

    git commit -m "提交说明"

    三板斧第三招:git push

    同步到远端服务器上

    git push

    首次推送到服务器需要填入用户密码,后面可以配置免密提交,参考博客:

    https://blog.csdn.net/camillezj/article/details/55103149

    展开全文
  • make/Makefile1....一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的 规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于
  • make/Makefile:项目自动化构建工具 Makefile Makefile是一个文本文件,记录项目的构建规则流程 Makefile的编写规则 目标对象:依赖对象 /t(缩进)具体的执行指令 例如: test.exe为目标对象 test.c为依赖...
  • 一个工程中的源文件不计其数,其按类型,功能,模块分别放在若干个目录中,Makefile定义了一系列的规则来制定,哪些文件先编译,哪些文件后编译,哪些文件需要重新编译。甚至于进行更复杂的功能操作。 Makefile带来...
  • 2.一个工程的源文件很多,按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先 编译哪些文件后编译,哪些文件需要重新编译,甚至进行更复杂的功能操作 3.makefile带来的...
  •  · 一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,Makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至进行更复杂的功能操作。...
  • 在开发一个项目或者造轮子之前,第一步永远是搭建开发环境,而在Linux下搭建Pixhawk时,总是因为各种各样的奇葩错误导致搭建失败,这次趁着硬盘崩了,重新搭建环境并记录下来,如果有错误或者补充可以在评论区提醒我...
  • 一个工程的源文件不计其数,其按类型,功能,模块分别放在若干个目录里,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要重新编译,甚至于执行更复杂的功能。    3. makefile的好处就是...
  • 一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 ...
  • 项目自动化构建工具背景make/Makefile:项目自动化构建工具依赖关系依赖方法原理makefile的编写规则:make的解释执行规则:.PHONY的使用 背景 会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的...
  • 详解Linuxmake命令的使用代码变成...但是实际上 ,任何只要某个文件有变化,就要重新构建的项目,都可以用Make构建。一、Make的概念Make这个词,英语的意思是"制作"。Make命令直接用了这个意思,就是要做出某个文...
  •   在现实生活中我们进行某一项功能往往不能仅仅依赖于一个文件的代码进行操作,需要多个不同的版块进行组合实现,这个时候需要构建成一个项目,将所有的模块打包组合...哪些文件需要后编译,哪些文件需要重新编译,甚
  • make命令以及makefile使用RCS与CVS进行源代码控制编写手册页使用patch与tar发布软件开发环境多源代码的问题当我们编写小程序时,许多人都是简单的在编辑后通过重新编译所有的文件重新构建我们的程序。然而,对于大...
  • 一、 概念介绍: 1. 构建:指定代码文件的编译顺序和编译的安排。... 当某个文件发生变化时,就可以用 make 重新构建。 3. Makefile/makefile:make 命令默认依赖的构建文件,可用用 make -f 文件名 或 make --...
  • Linuxmake及makefile文件格式

    千次阅读 2015-03-04 20:18:05
    但是实际上 ,任何只要某个文件有变化,就要重新构建的项目,都可以用Make构建。 本文介绍Make命令的用法,从简单的讲起,不需要任何基础,只要会使用命令行,就能看懂。我的参考资料主要是Isaac Sc
  • linux编程之make的使用

    2016-09-17 15:25:07
    Linux环境下编写代码使用GUN的make可以比较方便的构建自己的项目。通常一个应用程序会包含许多文件,当只有一个源文件的时候,当然还是选择手动编译链接,当应用程序有相当多的文件的时候,通过gcc手动编译就显得...
  • 主线Linux内核上的Raspberry Pi Official 7“触摸屏 主线内核包括用于7英寸触摸屏的面板驱动程序。存在使它可用。已计划覆盖,但仍然找不到它。此外,主线内核中不包括触摸输入和背光驱动程序。 事实证明,从树外...
  • 用于构建 gnu 自动工具的 conda 配方——如果您需要在 conda 构建中重新构建配置脚本,则非常方便。 为什么?? 在大多数情况下,“官方”源代码压缩包应该包含一个随时可用的配置脚本,因此您可以使用标准进行...
  • 但是实际上 ,任何只要某个文件有变化,就要重新构建的项目,都可以用Make构建。 本文介绍Make命令的用法,从简单的讲起,不需要任何基础,只要会使用命令行,就能看懂。我的参考资料主要是Isaac Sc
  • Linux下GNU的make&makefile

    2021-03-13 19:34:59
    make&makefileWhat二级目录三级目录 What 一个工程的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,...通过make解释makefile == 项目自动化构建。 makefile文件
  • 故事结束时,可以使用一个命令行进行往返,复制到另一台主机,安装该主机并重新启动主机(也许不是第一次尝试好吗?:)与内核附带的脚本的比较(大约在2012年) ):1)gmil在多个版本上都可以工作或尝试在其中...
  • 手把手教你构建自己的Linux系统.pdf

    热门讨论 2015-02-01 09:07:32
    5.4.3 重新启动进入新系统 246 5.5 如何提高成功率以及部分常见问题的解决方法 247 5.5.1 制作前的准备 247 5.5.2 制作中的常见问题 248 5.5.3 制作后的疑问 255 第6章 LiveCD/DVD的制作 257 6.1 Live...
  • 现在它是真正的跨平台-该项目不仅可以在一组有限的Orange Pi / Raspberry Pi板上运行,而且可以在几乎所有Linux上运行。 基本系统要求很简单- SystemD,网络管理和Python3。 您可以在文档中找到系统要求的完整列表...
  • 鲍勃了解对象之间的关系,因此,如果某项发生更改,那么它将重新构建它以及与之相关的所有内容。 工业标准。 对象依赖关系是使用标准的makefile语法指定的,而实际的构建引擎是就像数万个Linux和Unix软件项目一样...
  • 6.重新编译内核使其识别ext4文件系统7.第二次测试启动8.使用bash程序模拟init9.第三次测试启动6.重新编译内核使其识别ext4文件...[root@centos6linux]#makemenuconfig //选择ext4文件驱动 Filesystems---> <...
  • 系统:Ubuntu 开发环境:Qt 构建项目时,出现错误警告 “make: 警告:检测到时钟错误。您的创建可能是不完整的” 。 解决方法: 修改时间戳;执行以下命令: ...find ....重新构建程序,成功。 ...
  • 按照书上操作即可,遇到编译错误,我采取的方法是把解压的文件全部删除,然后重新执行,确定每步命令的正确。 其中提到了几个命令 CC make中常用到的环境变量,CC指定使用C程序的编译器,CXX指定使用C++的...

空空如也

空空如也

1 2 3 4 5 ... 8
收藏数 144
精华内容 57
关键字:

linuxmake重新构建

linux 订阅