makefile初探

本文介绍了Makefile的基本概念,包括目标、依赖文件和命令的规则,以及变量的使用。文章还探讨了如何利用自动变量简化编译指令,并通过模式规则批量处理类似任务。此外,提到了Makefile中的函数如wildcard和patsubst,以及如何处理带路径的文件编译情况。
摘要由CSDN通过智能技术生成

makefile初探

1、Makefile语法规则:

  • 一条规则:

    目标:依赖文件列表
      <tab>命令列表
    
  • Makefile基本三要素:

    • 目标:通常是要产生的文件名称,可以是可执行文件或其他对象文件,也可以是动作名称
    • 依赖文件:1)用来输入从而产生目标的文件;2)一个目标通常有几个依赖文件(也可以没有)
    • 命令:1)make执行的动作,一个规则可以包含多个命令,每个命令占一行。
  • Makefile规则:

    • make命令会在当前目录下找到名为Makefile或makefile的文件
    • 与make命令执行相关联的是系统维护的文件时间戳,当依赖文件(prerequisties)的时间戳比目标文件(target)要新时,make会执行target下的命令重新生成target,详细参考这里(Makefile Tutorial By Example)
    • 如果关联的依赖文件不存在,那么会继续寻找目标为依赖文件的规则,找到后执行对应的命令生成所需依赖文件,最后完成目标文件生成。

2、make命令格式:

  • make [-f file] [options] [targets]
  • -f 指定文件作为makefile输入文件。
  • [options]:
    • -n : 只打印要执行的命令但不执行。
    • -s : 执行但不显示执行的命令。
  • [targets]:
    • 如果make如果没有指定目标,make默认实现makefile文件内第一个目标,然后退出。
    • 指定了make要实现的目标,目标可以是一个或多个,多个目标间用空格隔开。

3、Makefile变量:

  • 变量定义:

    • 变量名=变量值 或者 变量名:=变量值
    • cpp := main.cpp
      obj = main.o
      
  • 变量引用:

    • 在使用变量时,需要在变量名前加 $ 并用()或{}包裹起来。

    • cpp := main.cpp
      obj = main.o
      
      $(obj) : ${cpp}
      	g++ -c $(cpp) -o $(obj) # 等价于: g++ -c main.cpp -o main.o
          
      complie : $(obj)
      
    • makefile的变量名:

      • 变量名区分大小写

      • 变量一般在makefile的头部定义。

      • makefile提供的一些变量供用户直接使用,可以直接对其赋值。

      • CC=gcc
        CPPFLAGS:C预处理选项:-E
        CFLAGS:c编译器选项 -Wall -g -c
        LDFLAGS:链接器选项 -L -l
        
    • 示例:

    • 假设写了加减乘除四个函数分别写在 add.c sub.c mul.c div.c 和一个调用四则运算的程序test.c则使用make编译如下:

    • 首先是makefile文件:

      • TARGET:=test # 定义编译完生成的可执行文件名为 test
        OBJS=add.o sub.o mul.o div.o test.o
        
        # SOURCE=add.c sub.c mul.c div.c test.c
        
        $(TARGET):$(OBJS)
        	gcc $(OBJS) -o $(TARGET)
        
        #错误,gcc -c add.c sub.c mul.c div.c test.c -o add.o sub.o mul.o div.o test.o只生成了add.o一个文件,后面的文件都没有生成,所以要分开写。
        # $(OBJS):$(SOURCE)
        # 	gcc -c $(SOURCE) -o $(OBJS)
        
        add.o:add.c
        	gcc -c add.c -o add.o
        
        sub.o:sub.c
        	gcc -c sub.c -o sub.o
        
        mul.o:mul.c
        	gcc -c mul.c -o mul.o
        
        div.o:div.c
        	gcc -c div.c -o div.o
        
        test.o:test.c
        	gcc -c test.c -o test.o
        clean:
        	rm -rf $(OBJS)
        
      • 第一次出错的结果:

        在这里插入图片描述

      • 分开写后运行成果的结果:
        在这里插入图片描述

      • 执行编译完的可执行文件test的结果:

        在这里插入图片描述

      • 修改test.c文件后,再次执行make命令结果为:
        在这里插入图片描述

        • 可以看到,只改变了test.c文件后执行make命令,只有test.o和 TARGET 两个目标的命令重新执行
      • 重新执行test可执行文件后:

        在这里插入图片描述

4、自动变量与模式规则:

  • 上面的写法太过复杂,自动变量与模式规则可以替我们简化写法:

  • 自动变量:

    • $@ : 表示目标(target)的完整名称。

    • $< : 第一个依赖文件的名称。

    • $^ : 所有的依赖文件,以空格分开,不包含重复的依赖文件

    • 注意: 自动变量只能在规则的命令中使用。

    • 示例:

      • TARGET:=test
        OBJS=add.o sub.o mul.o div.o test.o
        CC=gcc
        
        $(TARGET):$(OBJS)
        	# gcc $(OBJS) -o $(TARGET)
        	$(CC) $^ -o $@ #使用自动变量改写上面的写法
        	echo $@ # 打印目标
        	echo $^ # 打印所有依赖
        	echo $< # 打印第一个依赖
        add.o:add.c
        	# gcc -c add.c -o add.o
        	$(CC) -c $< -o $@
        	# 等价于 $(CC) -c $^ -o $@
        
        sub.o:sub.c
        	# gcc -c sub.c -o sub.o
        	$(CC) -c $< -o $@
        
        mul.o:mul.c
        	# gcc -c mul.c -o mul.o
        	$(CC) -c $< -o $@
        
        div.o:div.c
        	# gcc -c div.c -o div.o
        	$(CC) -c $< -o $@
        
        test.o:test.c
        	# gcc -c test.c -o test.o
        	$(CC) -c $< -o $@
        
        clean:
        	rm -rf $(OBJS)
        
    • 结果:

      在这里插入图片描述

    • 上面的各个子依赖的部分执行的命令都很相似,都是将源文件编译为二进制文件(*.o)。所以makefile又引入模式规则。

  • 模式规则:

    • 模式规则示例:

    • *与%通配符:

      • *: 通配符表示匹配任意字符串,可以用在目录名或文件名中。
      • %: 通配符表示匹配任意字符串,并将匹配到的字符串作为变量使用。
      TARGET:=test
      OBJS=add.o sub.o mul.o div.o test.o
      CC=gcc
      
      $(TARGET):$(OBJS)
      	$(CC) $^ -o $@
      %.o:%.c # 通配符的使用,%后可以代表多个字符
      	$(CC) -c $< -o $@
      
    • 结果:

      在这里插入图片描述

5、Makefile中的函数:

  • wildcard 函数:查找指定目录下的指定类型的文件。

    • src=$(wildcard *.c) #找到当前目录下所有后缀名为.c的文件,赋值给src,wildcard后需要空一格
      
  • patsubst 函数:匹配替换

    • obj=$(patsubst %c,%.o,$(src)) #把src变量里面所有后缀为.c的文件替换成.o
      
  • makefile中所有函数都是由返回类型的。

    • SRC=$(wildcard *.c) # 查找当前目录内所有后缀为.c的文件存在SRC中
      OBJS=$(patsubst %.c,%.o,$(SRC)) # 将SRC变量里所有后缀为.c的文件替换为.o文件
      TARGET=test
      CC=gcc
      
      $(TARGET):$(OBJS)
      	$(CC) $^ -o $@
      	
      %.o:%.c
      	$(CC) -c $< -o $@
      clean:
      	rm -rf $(OBJS)
      
    • 结果示例:

      在这里插入图片描述

  • makefile的为目标:

    • 当目标比如clean的当前目录下有同名的clean文件,则不执行clean对应的命令,需要make下的为目标。

    • 伪目标声明:.PHONY:clean声明为目标后,makefile就不会判断目标是否存在或是否需要更新而直接执行目标。

    • clean命令中的特殊符号:

      • “-”此条命令出错,make也会继续执行后续命令。
      • “@”不显示命令本身,只显示结果。
    • SRC=$(wildcard *.c) # 查找当前目录内所有后缀为.c的文件存在SRC中
      OBJS=$(patsubst %.c,%.o,$(SRC)) # 将SRC变量里所有后缀为.c的文件替换为.o文件
      TARGET=test
      CC=gcc
      
      $(TARGET):$(OBJS)
      	$(CC) $^ -o $@
      	
      %.o:%.c
      	$(CC) -c $< -o $@
      .PHONY:clean # 设置伪目标,不管clean是否存在或是否更新,都会执行
      clean:
      	rm -rf $(OBJS)
      
  • 带有路径的Makefile文件编写:
      源文件结构:
    在这里插入图片描述
    要求:生成的目标文件存储在obj目录中, 生成的可执行文件test存储在bin目录中。

# 获取src目录下所有的.cpp文件
SRC=$(wildcard ./src/*.cpp)
#替换为 obj/*.c
OBJS=$(patsubst ./src/%.cpp, ./obj/%.o,$(SRC))

CC=g++
TARGET=./bin/main

$(TARGET):$(OBJS)
   $(CC) $^ -o $@

./obj/%.o:./src/%.cpp
   $(CC) -c $< -o $@

run:
   $(TARGET)

.PHONY:clean
clean:
   rm -rf %(OBJS) $(TARGET)
all:
   echo $(SRC)
   echo $(OBJS)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值