makefile学习笔记

make是什么

  • gcc :编译器

  • make:linux自带的构建器

    • 构建的具体规则写在makefile中
  • makefile文件的命名

    • makefile
    • Makefile
  • makefile中的规则

    • 三部分:目标,依赖,命令

    • 1
      2
      3
      # (注释#)具体格式:
      # 目标:依赖
      # (tab缩进,只能是tab)命令
    • 1
      2
      3
      # 举例:编译语句:gcc a.c b.c c.c -o app 写成makefile
      app:a.c b.c c.c
      gcc a.c b.c c.c -o app
    • makefile中由一条或多条规则组成

  • makefile编写

    • 第一个版本

      • 1
        2
        app:a.c b.c c.c
        gcc a.c b.c c.c -o app
      • 缺点:效率太低,修改一个文件,全部文件都需要重新编译

    • 第二个版本

      • makefile工作原理

        • 检测依赖是否存在:

          • 向下搜索下面的规则,如果有规则是用来生成查找的依赖的,执行规则中的命令
        • 依赖存在,判断是否需要更新

          • 原则:目标时间 > 依赖的时间

            • 反之,则更新
          • 1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            app:main.o add.o sub.o mul.o
            gcc main.o add.o sub.o mul.o -o app
            main.o:main.c
            gcc main.c -c
            add.o:add.c
            gcc add.c -c
            sub.o:sub.c
            gcc sub.c -c
            mul.o:mul.c
            gcc mul.c -c
          • 缺点:冗余(很多重复的命令,写法一样重复在写)

    • 第三个版本

      • 自定义变量:

        1
        obj=a.o b.o c.o

        变量取值:aa=$(obj)

      • makefile自带的变量:大写

        • CPPFLAGES
        • CC
      • 自动变量

        • $@:规则中的目标
        • $<:规则中的第一个依赖
        • $^:规则中的所有依赖
        • 只能在规则的命令中使用
      • 例:

        1
        2
        3
        4
        5
        6
        7
        obj = main.o add.o sub.o mul.o
        target = app
        $(target):$(obj)
        gcc $(obj) -o $(target)
        %.o:%.c
        gcc -c $< -o $@

        模式匹配:

        %.o:%.c

        第一次:main.o没有,向下找匹配规则,自动变量会自动生成规则

        main.o:main.c

        gcc -c main.c -o main.o

        第二次:add.o

        add.o:add.c

        gcc -c add.c -o add.o

      • 缺点:可移植性比较差

    • 第四个版本

      • makefile所有的函数都有返回值
      • 查找指定目录下指定类型的文件
        • src = $(wildcard ./*.c) #搜索当前目录下所有.c文件
      • 匹配替换
        • patsubst进行替换,有三个参数
        • obj = \$(patsubst %.c,%.o,$(src))
      1
      2
      SOURCES = $(wildcard *.cpp)
      OBJS=$(patsubst %.cpp,%.o, $(SOURCES))

      第二种匹配替换方法:

      • 1
        2
        SRC=$(wildcard *.cpp)
        OBJ=$(SRC:.cpp=.o)
      • 用这种方法比patsubst要容易记忆

  • 第五个版本

    • 让make生成不是终极目标的目标

      • make 目标名 :来执行
    • 编写一个清理项目的规则

      • clean:

        -rm -f *.o app

    • 声明伪目标:

      • .PHONY:clean
      • 这样把目标声明成伪目标之后,就不会去进行文件存在检查和文件更新时间检查
    • 补充知识:

      • rm:-f, –force 忽略不存在的文件,从不给出提示。
      • makefile 命令加一个减号 - 代表当前命令执行失败了不会停止,继续执行下面的命令,即忽略失败

最终版本示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
target=myappname
#大写代表是makefile自带的变量,CPPFLAGS指的是预处理时的一些参数,默认为空,忘记了用小写的也行
CPPFLAGS=./include
#makefile 里变量引用的方式为$(x)
#wildcard 可以检索指定目录下的文件名
src=$(wildcard ./src/*.c)
#patsubst进行匹配替换
obj=$(patsubst %.c,%.o, $(src))
#自动变量$@:表示规则中的目标
$(target):$(obj)
gcc $^ -o $@
#自动变量$<:表示规则中第一个条件,只在有一个条件时用,这个条件是变化的,上面编译时,需要什么目标就会通过%模式匹配生成什么编译语句。
#-I 指定头文件目录
%.o:%.c
echo $<
gcc -c $< -I (CPPFLAGS) -o $@
clean:
-rm -f *.o $(target)
.PHONY: clean

补充

@

make执行到每一句命令的时候,不仅会执行那个命令,同时还会将命令完整的打印输出到屏幕上,但是作为执行命令的符号,我们有时候不希望打印在屏幕上,不好看,也显得乱,例如:

1
echo "begin!"

最终输出为:

1
echo begin!

不是我们希望的:

1
begin!

这时候就需要使用到@符号。

  • @
    • 在命令前加上@符号后就可以使make不显示这个命令本身和相关参数

例1:

1
@echo "begin!"

输出为

1
begin!

例二:(不仅不显示命令本身,相关的参数也会被自动去掉)

1
@g++ -c test.cpp -o test.o

输出:

1
test.o

本文标题:makefile学习笔记

文章作者:Yang Shuai

发布时间:2019年02月26日 - 20:02

最后更新:2019年04月24日 - 12:04

原始链接:https://ysbbswork.github.io/2019/02/26/makefile学习笔记/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

坚持原创技术分享,您的支持将鼓励我继续创作!