野火makefile多级结构工程---学习笔记

源代码

#定义变量
#ARCH默认为x86,使用gcc编译器,
#否则使用arm编译器
ARCH ?= x86
TARGET = hello_main


#存放中间文件的路径
BUILD_DIR = build_$(ARCH)
#存放源文件的文件夹
SRC_DIR = sources
#存放头文件的文件夹
INC_DIR = includes .

#源文件
SRCS = $(wildcard $(SRC_DIR)/*.c)
#目标文件(*.o)
OBJS = $(patsubst %.c, $(BUILD_DIR)/%.o, $(notdir $(SRCS)))
#头文件
DEPS = $(wildcard $(INC_DIR)/*.h)

#指定头文件的路径
CFLAGS = $(patsubst %, -I%, $(INC_DIR))

#根据输入的ARCH变量来选择编译器
#ARCH=x86,使用gcc
#ARCH=arm,使用arm-gcc
ifeq ($(ARCH),x86)
CC = gcc
else
CC = arm-linux-gnueabihf-gcc
endif

#目标文件
$(BUILD_DIR)/$(TARGET): $(OBJS)
   $(CC) -o $@ $^ $(CFLAGS)

#*.o文件的生成规则
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c $(DEPS)
#创建一个编译目录,用于存放过程文件
#命令前带“@”,表示不在终端上输出
@mkdir -p $(BUILD_DIR)
$(CC) -c -o $@ $< $(CFLAGS)

#伪目标
.PHONY: clean cleanall
#按架构删除
clean:
   rm -rf $(BUILD_DIR)

#全部删除
cleanall:
   rm -rf build_x86 build_arm

代码详解(使用时请开两个窗口观看

  • 代码:定义了变量BULID_DIR、SRC_DIR、INC_DIR分别赋值为工程的编译输出路径build_$(ARCH)、源文 件路径sources以及头文件路径includes和当前目录“.”。其中编译输出路径包含了架构$(ARCH)的内容,ARCH=x86时编译输出路径为build _x86,ARCH=arm时编译输出路径为build_arm,方便区分不同的编译输出。

make之前

make之后则变成了

 

  • 代码:定义了变量SRCS用于存储所有需要编译的源文件,它的值为wildcard函 数的输出,本例子中该函数的输出为“sources/hello_func.c sources/hello_main.c sources/test.c”。

  • 我的错误:错认为wildcard函数的输出是没有带目录的了,那个是notdir函数。

  • 代码:定义了OBJS变量用于存储所有要生成的的.o文件,它的值为patsubst函数 的输出,本例子中该函数是把所有c文件名替换为同名的.o文件,并添加build目录,即函数的输 出为”build/hello_func.o build /hello_main.o build /test.o”。

  • 我的疑惑:①如果输出目录不存在,patsubst函数会创建目录嘛?→不会。

                         ②这里只是替换了个名字,将.c改成 输出目录/.o的用处是什么?→用在后面目标文件的代码中,$(BUILD_DIR)/$(TARGET): $(OBJS) 。这样就方便很多。

  • 代码的第22行:定义了CFLAGS变量,用于存储包含的头文件路径,它的值为patsubst函数的 输出,本例子中该函数是把includes目录添加到“-I”后面,函数的输出为“-Iincludes”。

  • 我的疑惑:①-I的作用是什么?

    在gcc中,-I选项是用来指定头文件的搜索路径的¹。这样,gcc就可以根据你给出的路径来查找你引用的头文件。例如:gcc   -I/home/me/development/skia    sample.c

    这样,gcc就会在/home/me/development/skia目录下查找sample.c中引用的头文件。

                          ②这里为什么要这么定义一个CFLAGS变量?

因为后面定义目标的生成规则时,代码行是这样的
​​​​​​​#目标文件
$(BUILD_DIR)/$(TARGET): $(OBJS)
   $(CC) -o $@ $^ $(CFLAGS)

$(CFLAGS) = -Iincludes ,作用是在编译$(OBJS)的时候在 includes目录下查找头文件。

那这里又延申出一个问题:③如果使用-Iincludes就不能查到到头文件了吗?如果可以查找的话,为什么要多此一举?

如果你不使用-I选项来引用头文件,那么gcc会按照一定的顺序来搜索头文件目录。这个顺序是:

  1. 当前目录
  2. 环境变量C_INCLUDE_PATH或CPLUS_INCLUDE_PATH指定的目录
  3. gcc安装时指定的目录
  4. 标准系统目录

所以,如果你的头文件不在这些目录中,那么gcc就无法找到它,编译就会失败。因此,使用-I选项可以让你自定义头文件的位置,避免编译错误。

  • 代码:相对于之前的Makefile(野火文档中),这里在$(TARGET)前增加了$(BUILD_DIR)路径,使得最终的可执行程序放在build目录下。

 

  •  代码:给.o目标文件添加$(BUILD_DIR)路径,在执行编译前先创建build目录,以存放后面的.o文件。命令前的“@”表示执行该命令时不在终端上输出。

使用

使用该Makefile时,直接在Makefile的目录执行make即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值