Makefile的基本了解(学习笔记)

本文是关于Makefile的学习笔记,介绍了Makefile的核心——规则,包括目标、依赖及命令的执行条件。还讲解了Makefile的语法,如通配符、假想目标和变量类型。此外,文中还讨论了即时变量与延时变量的区别,并列举了Makefile中常用的函数,如foreach、filter、filter-out和wildcard等。通过实例展示了如何处理头文件依赖和添加CFLAGS。最后,分享了通用Makefile的设计思想和解析过程,涉及子目录编译和目标链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

下面的内容只是个人学习Makefile的一些笔记,有什么错误大家可以以下探讨。

1、Makefile的核心–规则

  • 目标:依赖1 依赖2 …

  • [TAB] 命令

    当“目标文件”不存在,或者某个依赖文件比目标文件“新”,则执行“命令”

2、Makefile的语法

2.1.通配符:
  • %.o
  • $@ 表示目标
  • $< 表示第1个依赖文件
  • $^ 表示所有依赖文件
  • 不想在终端看到命令输出的话,可在命令前加一个“@”
2.2.假想目标:

我们的 Makefile 中有这样的目标:

clean:
	rm -f $(shell find -name "*.o")
	rm -f $(TARGET)

如果当前目录下恰好有名为“clean”的文件,那么执行“make clean”时它就不会执行那些删除命令。这时我们需要把“clean”这个目标,设置为“假想目标”,这样可以确保执行“make clean”时那些删除命令肯定可以得到执行。

使用下面的语句把“clean”设置为假想目标:

.PHONY : clean
2.3.即时变量、延时变量
A :=  xxx         #  A的值即刻确定,在定义时即确定
B =  xxx          #  B的值使用到时才确定

:=         #   即时变量     
=          #   延时变量
?=        #   延时变量,如果时第一次定义才起效,如果在前面该变量已被定义则忽略这一句
+=       #    附加,它是即时还是延时变量,由前面的定义决定

3、Makefile常用函数

$(foreach var, list, text)                //A = a b c    B = $(foreach f, $(A), $(f).o) 
                                          //给list中的每个内容加上一个text
$(filter pattern..., text)                //C = a b c d/    D = $(filter %/, $(C))
                                          //在text中,取出符合pattern格式的内容
                                            
$(filter-out pattern..., text)            //C = a b c d/    E = $(filter-out %/,$(C))
                                          //在text中,取出不符合pattern格式的内容
                                            
$(wildcard pattern)                       //files = $(wildcard *.c)    
                                  //pattern定义了文件名的格式,wildcard取出其中存在的文件
                                  
$(patsubst pattern, replacement, $(var))  
                //file2 = a.c b.c c.c    dep_files = $(patsubst %.c, %.d, $(file2))    
                            //从text中取出每一个值,如果符合pattern,则替换成replacement                  

4、Makefile实例

4.1.支持头文件依赖
gcc -M c.c    //打印出依赖

gcc -M -MF c.d c.c    //把依赖写入文件c.d

gcc -c -o c.o c.c -MD -MF c.d    //编译c.o,把依赖写入文件c.d

实例:

objs = a.o b.o c.o

dep_files := $(patsubst %,.%.d, $(objs))
dep_files := $(wildcard $(dep_files))

test: $(objs)
    gcc -o -test $^

ifneq ($(dep_files),)
include $(dep_files)
endif

%.o : %.c
    gcc -c -o $@ $< -MD -MF .$@.d
    
clean:
    rm *.o test

distclean:
    rm $(dep_files)
    
.PHONY: clean
4.2.添加CFLAGS
CFLAGS = -Werror -Iinclude      //-Werror-->将warning视为error
                                //-Iinclude-->指定include文件夹作为gcc搜索头文件的目录

实例:

objs = a.o b.o c.o

dep_files := $(patsubst %,.%.d, $(objs))
dep_files := $(wildcard $(dep_files))

CFLAGS = -Werror -Iinclude    ////-Iinclude-->指定include文件夹作为gcc搜索头文件的目录

test: $(objs)
    gcc -o -test $^

ifneq ($(dep_files),)
include $(dep_files)
endif

%.o : %.c
    gcc -c -o $@ $< -MD -MF .$@.d
    
clean:
    rm *.o test

distclean:
    rm $(dep_files)
    
.PHONY: clean

5、通用Makefile的设计思想

5.1.在 Makefile 文件中确定要编译的文件、目录,比如:
obj-y += main.o
obj-y += a/

“Makefile”文件总是被“Makefile.build”包含的。

5.2.在 Makefile.build 中设置编译规则,有 3 条编译规则:
  • 怎么编译子目录? 进入子目录编译:
$(subdir-y):
    make -C $@ -f $(TOPDIR)/Makefile.build
  • 怎么编译当前目录中的文件?
%.o : %.c
    $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -Wp,-MD,$(dep_file) -c -o $@ $<
  • 当前目录下的.o 和子目录下的 built-in.o 要打包起来:
built-in.o : $(cur_objs) $(subdir_objs) 
    $(LD) -r -o $@ $^
5.3. 顶层 Makefile 中把顶层目录的 built-in.o 链接成 APP:
$(TARGET) : built-in.o
    $(CC) $(LDFLAGS) -o $(TARGET) built-in.o

6、通用Makefile的解析

6.1.Makefile
obj-y += main.o
obj-y += sub.o
obj-y += a/

all : start_recursive_build $(TARGET)    //1.执行make,
    @echo $(TARGET) has been built!      //导致顶层Makefile的第一个目标“all”被处理
    
start_recursive_build:                   //2.使用Makefile.build处理顶层目录
    make -C ./ -f $(TOPDIR/Makefile.build)
    
$(TARGET) : built-in.o                   //4.最后链接得到APP
    $(CC) $(LDFLAGS) -o $(TARGET) built-in.o
6.2.Makefile.build
obj-y :=
subdir-y :=                //3-1.变量清零
EXTRA_CFLAGS :=                    

include Makefile           //3-2.包含Makefile,里面有obj-y-->确定文件以及目录
......
PHONY += $(subdir-y)

__build : $(subdir-y) built-in.o    //3-3.先处理子目录-->跟处理顶层目录一样

$(subdir-y):                                  //3-4.编译main.o、sub.o
    make -C $@ -f $(TOPDIR)/Makefile.build    //把mian.o,sub.o以及a/built-in.o
                                              //一起链接得到顶层目录的built-in.o
built-in.o : $(cur_objs) $(subdir_objs)       
    $(LD) -r -o $@ $^

今天的学习就这样啦,明天继续努力!!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值