交叉开发--------1.4Makefile

本文详细介绍了Makefile的基本概念、语法结构,包括变量的赋值与使用、函数和调用、依赖关系以及常见操作,如自定义函数、shell命令调用和内置函数wildcard和patsubst的应用。
摘要由CSDN通过智能技术生成

目录

前言:我们从几个方面学习Makefile(智能化的自动编译工具)

1.Makefile是什么

2.了解Makefile中的一些语法(文件格式)

3.Makefile中的变量

    3.1  makefile中变量的赋值和使用

            1.简单赋值 :=(不会向上展开)

          2.递归赋值  =(会向上展开) 

            3.追加赋值  +=

            4.条件赋值  ?=

                3.2  自动变量 

                3.3 Makefile中的注释信息

4.Makefile中的函数和命令

    1.Makefile中运行自定义函数并且调用函数(类似与shell中函数)        2.Makefile中调用shell命令

    3.makefile中调用内置的函数


前言:我们从几个方面学习Makefile(智能化的自动编译工具)


    1.Makefile是什么?
    2.Makefile能做什么?
    3.了解Makefile中的一些语法,能够编写/修改简单的Makefile(一般的Makefile都是自动生成的)


1.Makefile是什么


    Makefile是make工具的配置文件,指导make如何去编译工程的文件

    什么是make呢?
        sudo apt install make 
        make是一个智能化的自动编译工程的管理工具(命令),它可以决定在一个工程中哪些文件需要被编译,哪些文件先编译,哪些文件后编译,以及如何去链接编译之后的文件
        make的功能之所以强大,是因为Makefile文件告诉了make如何去工作,以及如何产生目标文件
        把make的规则写入到Makefile文件中,make每一次编译都会更根据Makefile文件进行编译
        所以make的正常工作,是离不开makefile文件的

2.了解Makefile中的一些语法(文件格式)


    一个最简单的Makefile是由一些"目标和规则"组成的

    大概形式如下:
    TARGET:PREREQUISITES
    <Tab键>RECIPE
    <Tab键>RECIPE
    <Tab键>RECIPE
    .....
    TARGET2:PREREQUISITES
    <Tab键>RECIPE
    <Tab键>RECIPE
    <Tab键>RECIPE
    .....

    TARGET:是这一次make的目标名称,你这个Makefile的目的是什么
        一个Makefile中可以有很多个目标
        默认完成的是第一个目标,其他目标也叫做"伪目标"

    PREREQUISITES:依赖,完成前面的目标,需要依赖哪些文件或者库...(也可以为空)
        在Make的时候,第一步会检查当前目标依赖的文件是否存在
        如果存在:
            则按照目标下面的RECIPE命令列表生成对应的目标
        如果不存在:
            就搜索整个Makefile中,查看是否有以"依赖文件"为目标名的目标
            如果没有就报错,如果有,就先生成以"依赖文件"为目标名的目标,以此递归

    RECIPE:生成上面的目标需要执行的命令列表(前面必须有一个tab键)

    例子:
    现实生活中的Makefile,目标是西e

    TomatoFireEgg:Tomato Eggs
        echo "油,搞里头"
        echo "鸡蛋,搞里头"
        echo "西红柿,搞里头"
        echo "搞里头"
        echo "翻炒一下"

    Tomato:
        echo "生成一个Tomato"

    Eggs:KUN
        echo "Kun 生了一个egg"

    KUN:
        echo "唱跳两年半!"


    make的时候,默认是完成第一个目标!

    make的用法:
        make  会自动的取当前目录下面的Makefile中完成"目标"

        make + 目标名
            如果没有加目标,默认生成Makefile中的第一个目标

        make -C  目录 
            到指定的目录中去查找Makefile文件并且生成目标

    make在执行的时候,会自动的把执行过的命令打印到终端上面
    make是非常智能的,它能够根据文件的修改时间,去判断哪些文件需要先编译,哪些文件不需要被重新编译
    如:

    CC:=gcc 
    Graph:graph.o LKqueue.o main.o
        $(CC) graph.o LKqueue.o main.o -o Graph 

    graph.o:
        $(CC) -c graph.c -o graph.o
    LKqueue.o:
        $(CC) -c LKqueue.c -o LKqueue.o
    main.o:
        $(CC) -c main.c -o main.o

    clean:
        rm *.o
        rm Graph    


    我们的工程中,有很多C文件的编译格式是类似的,如果工程中增加一个源文件,就需要去修改Makefile文件,增加编译规则,这其实很麻烦
    我们能不能使用一些变量去表示Makefile中的文件列表呢?

3.Makefile中的变量


    Makefile中可以自己定义变量,也可以使用Makefile中自带的变量(环境变量)
    自定义变量:没有类型,都是字符串,而且变量名可以随意指定

    3.1  makefile中变量的赋值和使用


        变量可以不需要预先定义,和shell一样
        如果变量名没有预先定义并且赋值,则变量的值为空
        变量的定义方法:
            变量名
        如何使用变量:
            $(变量名)

        变量的定义不能放到指令列表中(一般放到Makefile的最前面)    
        在Makefile中给变量赋值有几种情况:


            1.简单赋值 :=(不会向上展开)

                B:=$(A)
                A:=12345
                
                B为空
                A为12345
                ---------------
                A:=12345
                B:=$(A)
                C:=A 

                $(A)    12345
                $(B)    12345
                $(C)    A


          2.递归赋值  =(会向上展开) 

                B=$(A)
                A=12345
                
                $(A)    12345
                $(B)    12345

                注意不要写成递归调用自己
                B=$(A)
                A=$(B)

            3.追加赋值  +=


                A:=123
                A+=456

                $(A)  123456


            4.条件赋值  ?=


                当变量以前没有定义或者没有值的时候,我们才会给他赋值

                A?=hello
                    因为A以前没有定义并且没有值,所有A为hello
                
                B:=123
                B?=ABC 
                    $(B) 123

            
    3.2  自动变量 


        系统已经帮我们定义好了的变量,我们只需要使用即可
        自动变量:make中的内置变量,make赋予这些变量一些特殊的含义
            $@  目标的完整名字
                写在哪一个目标下面,就表示哪一个目标的名字
            
            $+  所有依赖文件的名字,以空格隔开,可能包含重复的依赖名
                写在哪一个目标下面,就表示哪一个目标的依赖

            $^  所有依赖文件的名字,以空格隔开,不会包含重复的依赖名
                写在哪一个目标下面,就表示哪一个目标的依赖

            $<  第一个依赖文件的名字
                main:a.c b.c 
                    echo $<   -----> a.c 

            $?  所有时间戳比目标文件新的依赖文件名称(在make的时候,需要重新编译的文件)
                在生成目标文件之后,你又修改了的依赖文件


            
    3.3 Makefile中的注释信息


        以#开头的行是注释
        如:

        #目标名称
        TARGET:=Graph
        #头文件路径
        INC:=../inc 
        #库文件的路径
        LIB:= -lfind_max
        LIB_PATH:= -L../lib 
        #编译器名称
        CC:=gcc 
        $(TARGET):graph.o LKqueue.o main.o
            $(CC) $^ -o $@  -I$(INC) $(LIB) $(LIB_PATH)
        graph.o:graph.c
            $(CC) -c $^ -o $@
        LKqueue.o:LKqueue.c
            $(CC) -c $^ -o $@
        main.o:main.c
            $(CC) -c $^ -o $@
        
        clean:
            rm *.o
            rm Graph

    如果在上面的工程中,增加了一个C的源文件,可能需要修改Makefile
    修改的时候,也是增加一条关于.c ----->.o的规则 

    所有的.c----->.o的规则都是一样的,这本身也是一种规则,我们可以创建一个默认的规则,把上面的.c----->.o写成一个通用的形式(在增加C源文件之后,可以不需要修改Makefile)

    Makefile中的通配符
        %       表示任意一个文件名(不包括扩展名)
        %.o     表示任意一个以.o结尾的文件
        %.c     表示任意一个以.c结尾的文件
        同名的.o一般会依赖于同名的.c 
    =========>

    #目标名称
    TARGET:=Graph
    CC:=gcc 
    $(TARGET):graph.o Lkqueue.o main.o
        $(CC) $^ -o $@ 

    %.o:%.c 
        $(CC) -c $< -o $@
    clean:
        rm *.o
        rm $(TARGET)


    我们也可以自动的在指定的工程目录中去查找*.c/*.cpp文件
    使用内置的函数即可

4.Makefile中的函数和命令


    1.Makefile中运行自定义函数并且调用函数(类似与shell中函数)
    
    2.Makefile中调用shell命令


        格式:
            $(shell  命令名称  参数列表)
        如果你需要使用shell命令或者函数的结果
        =====>
        变量名=$(shell  命令名称  参数列表)    /   $(函数名  函数的参数列表)
        如:
        Date=$(shell  date)
        PWD=$(shell pwd)

    3.makefile中调用内置的函数


        格式:
        $(函数名  函数的参数列表)
        我们简单的了解几个常用的函数和使用方式即可
        wildcard:文件名展开函数
            展开指定的目录下面符合wildcard参数描述的文件名称,获取的文件名称之间使用空格隔开
            例子:
            CSRCS    表示C源文件列表
            CSRCS:=$(wildcard *.c)
            在当前的目录下面查找所有的以.c结尾的文件名,然后赋值给 CSRCS
        通过这种方式,我们就可以获取到所有的源文件名称

        patsubst:模式字符串替换函数
        把指定的字符串中符合某一个模式的字符串,替换为指定的字符串(可以使用通配符)
            例子:
            CSRCS:=$(wildcard *.c)
            OBJS:=$(patsubst  %.c,%.o,$(CSRCS))
            把$(CSRCS)中以.c结尾的字符串的文件名称,替换为同名的以.o结尾的文件名

        我们一般可以认识和使用一个简单通用的makefile即可

        
 

  • 20
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值