YOLO部署实战(4):Makefile的规范与优化

1. 引言

在大型工程中,源文件众多,通过合理定义makefile可以规范文件的编译顺序与重新编译规则。本文将深入探讨makefile的基本概念、命名规则、变量和函数的运用,以及通过示例演示makefile的不同层次的优化。

在工程中,makefile定义了源文件的编译规则和操作系统命令。它不仅指定文件的编译顺序,还可以执行操作系统的命令,是完成大型工程的必备工具。因此,一个人是否能熟练编写makefile,反映了其完成大型工程的能力。

2. 命名规范

makefile的命名只有两种形式:makefileMakefile,其他形式不被允许。

Makefile中的规则由三个基本要素组成:目标(target)、依赖(prerequisites)和命令(command)。以下是其内部型编写形式:

target: prerequisites
    command

**目标(target)**代表着一个文件或标签,可以是Object File,也可以是执行文件。对于标签的特性,将在后续“伪目标”章节中详细叙述。

**依赖(prerequisites)**指定了生成目标文件(target)所需要的文件或目标。这是一个文件的依赖关系,即目标文件依赖于prerequisites中的文件。

**命令(command)**包含了make需要执行的任意Shell命令。这一部分定义了生成目标文件的具体规则。如果prerequisites中的文件比目标文件新,make将执行所定义的命令。

这些规则构成了Makefile中最为核心、关键的内容,规定了文件生成的逻辑和依赖关系。

3. 变量与函数

makefile中使用变量和函数有助于提高代码的灵活性和可维护性。

** 变量 **

(1) 规则
    %o : %c        
    Tab键 gcc  -c  $<  -o   $@

(2) makefile中的自动变量

    (a) $< : 规则中的第一个依赖

    (b) $@ : 规则中的目标

    (c) $^ :规则中的所有依赖

(3) makefile中系统自己维护的变量

    (a) CC  = cc (其实 cc 是系统默认的gcc ,当然 CC 的值可以赋值 )

    (b) CPPFLAGS = -I   (  编译时需要的参数  )

** 函数 **

(1) wildcard
    src = $(wildcard    /*.c) 表示把当前目录下的所有.c文件返回一个字符串给src
(2) patsubst
    obj = $(patsubst   ./*.c  , ./*.o  , $(src)) 表示把当前目录下src的所有.c文件换成.o文件

4. 不同级别的makefile示例

通过初级、中级、高级和终极的makefile示例演示了不同级别的优化,包括减少冗余命令、根据依赖项精确编译等。

  • 初级makefile
calc:calc.c add.c sub.c mul.c div.c
            gcc calc.c add.c sub.c mul.c div.c -o calc

通过写 makefile 减少了 编译运行程序时,繁杂冗余的命令出现

  • 中级makefile
calc:calc.o add.o sub.o mul.o div.o
           gcc calc.o add.o sub.c mul.o div.o -o calc
   
   calc.o:calc.c
           gcc -c calc.c
   add.o:add.c
           gcc -c add.c
   sub.o:sub.c
           gcc -c sub.c
  mul.o:mul.c
          gcc -c mul.c
  div.o:div.c
          gcc -c div.c 
  clean:
          rm *.o calc

中级makefile 比初级makefile 更好一点,主要是因为: 初级的makefile在任何时候,只要其中的一个依赖文件改变,就必须重新编译,这样会导致大量时间被浪费。

如果所依赖的文件比较多的话,那么编译就会耗费大量时间。而中级makefile 会根据哪一个依赖项 发生改变,则这个目标文件重新编译,不用全部重新编译 。

  • 高级makefile
obj = calc.o add.o sub.o mul.o div.o
   target = calc
   
   # makefile中的自动变量
   CC = gcc
   CPPFLAGS = -I
   
   
   $(target):$(obj)
          $(CC) $(obj) -o $(target)
  %.o:%.c
          $(CC) -c $< -o $@

高级makefile 的性能就更好了,而且比较标准和规范化,用到了变量和公式,避免了makefile中出现大量的相同代码。

  • 终极makefile
#obj = calc.o add.o sub.o mul.o div.o
   target = calc
   
   # makefile中的自动变量
   # makefile中的函数使用
   
   # src 是获取当前目录下所有.c文件
   
   src = $(wildcard ./*.c)
  
  # obj 把当前目录下所有的.c替换成.o
  
  obj = $(patsubst %.c, %.o, $(src))
  
  CC = gcc
  CPPFLAGS = -I
  
  $(target):$(obj)
          $(CC) $(obj) -o $(target)
  %.o:%.c
         $(CC) -c $< -o $@
  
  # .PHONY:clean 意思是申明clean 为伪目标,它不会和磁盘上的 clean 进行比较
  .PHONY:clean
  clean:
          rm  $(obj) $(target) -f
  
  hello:
          echo "Hello,makefile"

5. 实际案例

以一个具体工程为例,展示了包含多个头文件和C文件的makefile,通过变量、规则和自动推导等手段简化了代码结构,提高了可维护性。

# 定义目标文件
objects = main.o kbd.o command.o display.o \
          insert.o search.o files.o utils.o

# 默认目标为edit,生成执行文件
edit : $(objects)
    cc -o edit $(objects)

# 隐晦规则,make会自动推导依赖关系和生成规则
main.o : defs.h
kbd.o : defs.h command.h
command.o : defs.h command.h
display.o : defs.h buffer.h
insert.o : defs.h buffer.h
search.o : defs.h buffer.h
files.o : defs.h buffer.h command.h
utils.o : defs.h

# 伪目标,用于清理生成的文件
.PHONY : clean
clean :
    rm edit $(objects)
  1. 变量的使用 (Variable Usage):

    • objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o: 定义了一个变量 objects,其中包含了所有的目标文件。这样的定义使得代码更加清晰,同时方便后续的修改,只需要在这个变量中添加或删除目标文件即可。

    • edit : $(objects): 在生成目标文件 edit 时,使用了变量 $(objects),这样做使得代码更简洁,并且方便维护。

  2. 隐晦规则 (Implicit Rules):

    • 针对每个 .o 文件,只需提供对应的头文件,make 会自动推导生成规则。例如,main.o : defs.h 表示 main.o 依赖于 defs.h,而不需要手动指定生成规则。

    • 这种方式减少了代码的冗余,提高了可读性,并使代码更加易于维护。

  3. 伪目标 (Phony Target):

    • .PHONY : clean 表示 clean 是一个伪目标。伪目标通常用于表示执行一些操作而不生成实际文件,例如清理操作。

    • clean : rm edit $(objects) 定义了清理操作,可以通过执行 make clean 来删除生成的执行文件和目标文件。

这样的 Makefile 更加简洁、可读性更强,并且降低了维护的难度。通过使用变量和隐晦规则,可以更方便地扩展项目,而使用伪目标则使清理操作更加安全和可控。

6. 总结

本文解释了make的工作原理,包括寻找makefile、目标与依赖关系的比较、执行命令等步骤。希望大家对make的运行机制有更深刻的理解,可以更好地理解makefile的规范与优化方法。合理的makefile不仅提高了代码的编译效率,还使得工程更易于维护。在实际项目中,充分利用makefile的功能,将对项目的开发和维护产生积极的影响。

你可能感兴趣的:(YOLO部署实战,YOLO,makefile)