makefile笔记

本文详细介绍了make和makefile的基本概念、结构、伪目标、变量使用、预定义变量等内容,并通过示例展示了如何构建和维护复杂的编译任务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、make和makefile

1、make是一个应用程序,解析源程序之间的依赖关系,根据依赖关系自动维护编译工作。

2、makefile是一个描述文件,定义了一系列规则来指定各源文件编译的先后顺序。

3、makefile中的描述用于指导make程序如何完成工作,make根据makefile中的规则完成编译输出。

4、最简单的makefile示例:

    hello:

            @echo "hello makefile"

5、make程序使用示例:

make -f mf.txt hello

make以hello作为目标查找rm.txt文件,并执行hello目标的的命令。

6、简化make,直接输入make hello,以hello为目标查找makefile或者Makefile文件,并执行hello处的命令。

或者直接输入make,那么程序直接查找makefile或者Makefile文件中的最顶层目标,并执行。

7、示例:

hello : 
echo "hello makefile"

test : 
echo "test"
pwd

ls

二、makefile的结构

1、makefile用于定义源文件之间的依赖关系

    依赖定义:

    target : prerequistes ;    command1

      '\t'        command2(命令年需要使用tab健缩进4个字节)

2、target:通常为需要生成的目标文件名,make所需执行的命令名称。target可包含多个目标,使用空格对目标名进行分隔

    prerequistes:当前目标所依赖的其他目标或文件。prerequistes可包含多个依赖,使用空格对依赖进行分隔。

    command:完成目标所需要执行的命令。  每个命令行必须以一个tab字符开始。

    续行符\:可以将内容分开写到下一行。

    依赖规则:

    当目标对应的文件不存在,执行对应命令。

    当依赖在时间上早于目标,执行对应命令。

    当依赖关系连续发生时,对比依赖链上的每一个目标。

    小技巧:在命令前加上@,则不回回显命令

   示例1:

    all : test
@echo "make all"

    test :
@echo "make test"

    示例2:包含func.c和main.c两个源文件

    hello.out all : func.o main.o
gcc -o hello.out func.o main.o

    func.o : func.c
gcc -o func.o -c func.c

    main.o : main.c
gcc -o main.o -c main.c  


三、伪目标

1、默认情况下,make认为目标对应着一个文件,make比较目标文件和依赖文件的新旧,决定执不执行。make以文件处理作为第一优先级。

2、通过.PHONY声明伪目标,伪目标不对应任何实际的文件,不管伪目标的依赖是否更新,命令都会被执行

示例:

    .PHONY : rebuild clean all

    rebuild : clean all

     all : hello.out

     clean :

            rm -f *.o hello.out


四、变量和赋值

1、makefile中的变量只代表文本数据,即字符串,并且大小写敏感。

2、变量定义和使用

        定义、CC := gcc

        使用、$(CC)

3、赋值:

    简单赋值(:=):    只针对当前赋值语句有效。

    递归赋值(=) :    赋值操作可能影响多个地方,所有与目标有关的其他变量全部都会改变

    条件赋值(?=)    如果变量已定义,则不改变变量值,如果未定义,则使用当前值

    追加赋值(+=) :    原变量之后追加赋值,原值与新值用空格隔开



五、预定义变量

1、自动变量

    $@:当前规则中触发命令被执行的目标

    $^:当前规则中的所有依赖

    $<:当前规则中的第一个依赖

2、特殊变量

    $(MAKE) : 当前 make解释器的文件名(make)

    $(MAKECMDGOALS): 命令行中指定的目标名(make命令行参数,即输入的make之后的命令)

    $(MAKEFILE_LIST)  :    make所需要处理的makefile文件列表

    $(MAKE_VERSION) :  当前make解释器的版本

    $(CURDIR) :    当前解释器的工作目录

    $(.VARIABLES) :    所有已定义的预定义变量和自定义变量



六、变量高级主题1:

1、 变量值替换:使用指定字符串替换变量值中的后缀字符串

    语法格式: $(var:a=b),替换表达式中不能有任何空格

        示例:

        src := a.cc b.cc c.cc

        obj := $(src:cc=o)

2、 变量模式替换:使用%保留变量值中的指定字符,替换其他字符

    语法格式:$(var:a%b=x%y)

    示例:

    src := a1b.c a2b.c a3b.c

    obj := $(src:a%b=x%y)                                             

3、规则中的模式替换:

    语法:

    targets : target-pattern : perreq-pattern

        command1

        command2 

       .....

    意义:通过target-pattern 从targets中匹配子目标,再通过perreq-pattern从子目标生成依赖,进而构成完整的规则。

    示例:

    OBJS := func.o mmain.o

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

                gcc -o $@   -c $^

    等价于:

    func.o : func.c

            gcc -o $@ -c $^

    main.o: main.c

            gcc -o $@ -c $^

4、命令行变量:运行make时,在命令行定义变量,命令行变量默认覆盖makefile中定义的变量值。

5、override关键字:用于指示makefile中定义的变量不能被命令行变量覆盖。

6、define关键字:用于在makefile中定义多行变量。多行变量的定义从变量名开始到endef结束,可用override修饰。

    示例:

    define foo

    I'M fool

    endef

override define cmd

            @echo "run cmd"

            @ls

endef


七、变量高级主题2

1、环境变量(全局变量)

    makefile中能够直接使用环境变量的值;如果定义了同名变量,环境变量值将被覆盖;运行make时,加上-e,则优先使用环境变量;环境变量可在任何makefile文件中使用。

2、不同makefile中的值传递

    直接在外部定义环境变量进行传递;使用export定义变量进行传递(定义临时环境变量);定义make命令行变量进行传递(推荐使用)

3、目标变量(局部变量):只能在指定目标及其连带规则中使用。

4、模式变量:模式变量是目标变量的扩展,作用域只在符合模式的目标及其连带规则中。


八、条件判断语句

条件判断语句只能用于控制make实际执行的语句,不能控制规则中命令的执行过程。类似与C语言的宏2定义,只在预处理阶段有效,执行阶段无效。

    格式:

    ifeq(arg1,arg2)    :  判断参数是否相等

    ifneq(arg1,arg2) :判断参数是否不想等

    ifdef arg1  :判断变量是否有值

    ifndef arg1:判断变量是否无值


九、函数定义及调用

1、自定义函数:通过define实现自定义函数,自定义函数是一个多行变量,无法直接调用;自定义函数是一种调用过程,没有任何返回值。

    自定义函数语法:

    define func

            @echo “my name is $(0)”    #$(0)表示函数名 $(1)表示函数第一个参数,$(2)表示函数第二个参数。

    endef

    函数调用:

    test :

            $(call func)  #输出为my name is func

2、预定义函数:预定义函数提供了处理文件名、变量和命令的函数。函数在调用的地方被替换为处理结果。

    语法:

    var := $(func_name arg1,arg2.....)

    示例:

    var := $(abspath ./)        (获取当前文件你的绝对路径,并保存到var中)

    test:

            @echo "var==》$(var)"


十、综合应用

1、$(wildcard  _pattern)

    获取当前工作目录中满足_pattern的文件或目录列表。

2、$(addprefix _pattern,_names)

    给名字列表_names中的每个名字增加一个前缀_pattern 。

3、自动获取当前目录下的源文件列表(函数调用)

    SRCS := $(wildcard  *c)

4、根据源文件列表生成目标文件列表(变量的值替换)

    OBJS := $(SRCS:.c=.o)

5、对每一个目标文件加上路径前缀(函数调用)

    OBJS := $(addprefix path/,$(OBJS))

6、规则中的模式替换(目录结构)

工作目录中存在func.c main.c 源文件  

模式替换: 

%o : %c

    gcc -o $@ -c $^

等价于:

func.o: func.c

    gcc -o $@ -c $^

main.o: main.c

    gcc -o $@ -c $^

示例:

CC := gcc
MKDIR := mkdir
RM := rm -fr
DIR_OBJS := objs
DIR_TARGET := target
DIRS := $(DIR_OBJS) $(DIR_TARGET)
TARGET := $(DIR_TARGET)/hello-makefile.out
SRCS := $(wildcard *.c)
OBJS := $(SRCS:.c=.o)
OBJS :=$(addprefix $(DIR_OBJS)/,$(OBJS))
.PHONY: rebuild clean all
$(TARGET) : $(DIRS) $(OBJS)
$(CC) -o $@ $(OBJS)
@echo "Target File ==>$@"
$(DIRS) :
$(MKDIR) $@
$(DIR_OBJS)/%.o : %.c
$(CC) -o $@ -c $^
rebuild: clean all
all : $(TARGET)
clean: 
$(RM) $(DIRS)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值