• Makefile(二)


    函数格式及示例

    在 Makefile 中调用函数的方法跟变量的使用类似,以“ ( ) ”或“ ()”或“ (){}”符号包含函数

    名和参数,具体语法如下:

    $(函数名 参数)
    # 或者使用花括号
    ${函数名 参数}
    
    • 1
    • 2
    • 3

    下面以常用的 notdir、 patsubst、 wildcard 函数为例进行讲解,并且示例中都是我们后面 Makefile 中使用到的内容.

    notdir 函数

    notdir 函数用于去除文件路径中的目录部分。它的格式如下:

    $(notdir 文件名)

    例如输入参数 ./sources/func.c,函数执行后的输出为 func.c,也就是说它会把输入
    中的 ./sources/ 路径部分去掉,保留文件名。使用范例如下:

    # 把路径中的“./sources/”部分去掉,输出为: hello_func.c
    $(notdir ./sources/hello_func.c)
    
    • 1
    • 2

    wildcard 函数

    wildcard 函数用于获取文件列表,并使用空格分隔开。它的格式如下:

    $(wildcard 匹配规则)

    例如函数调用 $(wildcard *.c),函数执行后会把当前目录的所有 .c 文件列出。假设在 sources目录下有 func.c、main.c,使用范例如下:

     $(wildcard sources/*.c)
      # 函数的输出为:
     sources/func.c sources/main.c
    
    • 1
    • 2
    • 3

    patsubst 函数

    patsubst 函数功能为模式字符串替换。它的格式如下:

    $(patsubst 匹配规则, 替换规则, 输入的字符串)

    当输入的字符串符合匹配规则,那么使用替换规则来替换字符串,当匹配规则中有 % 号时,
    替换规则也可以例程 % 号来提取 % 匹配的内容加入到最后替换的字符串中。有点抽象,请
    直接阅读以下示例:

     $(patsubst %.c, build_dir/%.o, hello_main.c )
     # 函数的输出为:
     build_dir/hello_main.o
     # 执行如下函数
     $(patsubst %.c, build_dir/%.o, hello_main.xxx )
     # 由于 hello_main.xxx 不符合匹配规则"%.c",所以函数没有输出
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    第一个函数调用中,由于 hello_main.c 符合 %.c 的匹配规则(% 在 Makefile 中的类似于 * 通
    配符
    ),而且 %hello_main.c 中提取出了 hello_main 字符,把这部分内容放到替换规
    build_dir/%.o% 号中,所以最终的输出为 build_dir/hello_main.o

    第二个函数调用中,由于由于 hello_main.xxx 不符合 %.c 的匹配规则,.xxx.c
    不上,所以不会进行替换,函数直接返回空的内容。

    示例

    假如我们有以下目录结构:

    .
    ├── includes
    │   ├── add_one.h
    │   └── func.h
    ├── makefile
    └── sources
        ├── add_one.c
        ├── func.c
        └── main.c
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    文件内容如下:

    add_one.h

    int add_one(int x, int y);
    
    • 1

    func.h

    void func(void);
    
    • 1

    add_one.c

    int add_one(int x, int y)
    {
        return x + y;
    }
    
    • 1
    • 2
    • 3
    • 4

    func.c

    #include "stdio.h"
    
    void func(void)
    {
        printf("This is %s file !", __FILE__);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    main.c

    #include "stdio.h"
    #include "add_one.h"
    #include "func.h"
    
    int main()
    {
        int x = 9, y = 8;
        int sum = 0;
    
        sum = add_one(x, y);
    
        printf("%d + %d = %d\n", x, y, sum);
        func();
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    如果我们不借助makefile的话,直接运行指令:

    gcc -o main.exe .\sources\main.c .\sources\func.c .\sources\add_one.c -I .\includes\
    
    • 1

    即可完成编译

    以后我们的源文件 .c 增多,目录结构更复杂,此时借助 makefile 是最方便的

    使用makefile

    # 生成的可执行文件名
    TARGET = main.exe
    # 编译器
    CC = gcc
    
    #存放中间文件的路径
    BUILD_DIR = build
    #存放源文件的文件夹
    SRC_DIR = sources
    #存放头文件的文件夹
    INC_DIR = includes 
    
    # 源文件
    SRCS = $(wildcard $(SRC_DIR)/*.c)  #列出 sources 目录下的文件
    # 目标文件(*.o)
    OBJS = $(patsubst %.c, $(BUILD_DIR)/%.o, $(notdir $(SRCS)))
    # 头文件
    DEPS = $(wildcard $(INC_DIR)/*.h)
    
    # #################
    # 编译选项
    # #################
    # 指定头文件的路径
    CFLAGS = $(patsubst %, -I%, $(INC_DIR))
    # 输出编译警告
    COPTION = -Wall   
    
    # 生成目标文件
    $(BUILD_DIR)/$(TARGET): $(OBJS)
    	$(CC) -o $@ $^ $(CFLAGS) $(COPTION)
    
    #*.o 文件的生成规则
    $(BUILD_DIR)/%.o: $(SRC_DIR)/%.c $(DEPS)
    	@mkdir -p $(BUILD_DIR)
    	$(CC) -o $@ -c $< $(CFLAGS) $(COPTION)
    
    # 运行.exe
    run:
    	@$(BUILD_DIR)/$(TARGET)
    
    # 删除生成的文件
    clean:
    	rm -rf $(BUILD_DIR)
    
    • 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
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    1. 编译
    make
    
    • 1
    1. 运行
    make run
    
    • 1
    1. 删除文件
    make clean
    
    • 1
  • 相关阅读:
    Linux开发工具之编辑器-vim
    我做了一个 VSCode 插件版的 ChatGPT
    基于单片机设计的水平仪(STC589C52+MPU6050)
    物联网如何助力乡村数字经济发展
    OpenCV检测圆(Python版本)
    「Java开发指南」在MyEclipse中的Spring开发(一)
    56.合并区间 | 1288.删除被覆盖的区间 | 986.区间列表的交集
    基于可视图法(VG)的路径规划算法简述
    [C#] FFmpeg 音视频开发总结
    SpringBoot调用WebService的实践
  • 原文地址:https://blog.csdn.net/m0_47329175/article/details/127784867