makefile 学习总结

本文详细介绍Makefile中的wildcard、notdir、patsubst及foreach等函数的应用,并通过实例演示了不同赋值运算符(=、:=、?=、+=)的效果,帮助读者深入理解Makefile的变量处理和文件构建流程。

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

makefile学习过程
/*************************************************************************************/
函数使用方法
1、wildcard : 扩展通配符
2、notdir : 去除路径
3、patsubst :替换通配符
4、foreach

例子:
建立一个测试目录,在测试目录下建立一个名为sub的子目录
$ mkdir test
$ cd test
$ mkdir sub

在test下,建立a.c和b.c2个文件,在sub目录下,建立sa.c和sb.c2 个文件

建立一个简单的Makefile
src=$(wildcard *.c ./sub/*.c)
dir=$(notdir $(src))
obj=$(patsubst %.c,%.o,$(dir) )

all:
 @echo $(src)
 @echo $(dir)
 @echo $(obj)
 @echo "end"
 
执行结果分析:
第一行输出:
a.c b.c ./sub/sa.c ./sub/sb.c

wildcard把 指定目录 ./ 和 ./sub/ 下的所有后缀是c的文件全部展开。

第二行输出:
a.c b.c sa.c sb.c
notdir把展开的文件去除掉路径信息

第三行输出:
a.o b.o sa.o sb.o

在$(patsubst %.c,%.o,$(dir) )中,patsubst把$(dir)中的变量符合后缀是.c的全部替换成.o,
任何输出。
或者可以使用
obj=$(dir:%.c=%.o)
效果也是一样的。

这里用到makefile里的替换引用规则,即用您指定的变量替换另一个变量。
它的标准格式是
$(var:a=b) 或 ${var:a=b}
它的含义是把变量var中的每一个值结尾用b替换掉a

$(foreach <var>,<list>,<text>)


这个函数的意思是,把参数<list>;中的单词逐一取出放到参数<var>;所指定的变量中,然后再执行< text>;所包含的表达式。每一次<text>;会返回一个字符串,循环过程中,<text>;的所返回的每个字符串会以空格分隔,最后当整个循环结束时,<text>;所返回的每个字符串所组成的整个字符串(以空格分隔)将会是foreach函数的返回值。

所以,<var>;最好是一个变量名,<list>;可以是一个表达式,而<text>;中一般会使用<var>;这个参数来依次枚举<list>;中的单词。举个例子:

    names := a b c d

    files := $(foreach n,$(names),$(n).o)

上面的例子中,$(name)中的单词会被挨个取出,并存到变量“n”中,“$(n).o”每次根据“$(n)”计算出一个值,这些值以空格分隔,最后作为foreach函数的返回,所以,$(files)的值是“a.o b.o c.o d.o”。

注意,foreach中的<var>;参数是一个临时的局部变量,foreach函数执行完后,参数<var>;的变量将不在作用,其作用域只在foreach函数当中。

/*************************************************************************************/
在一个目录下面有两个子目录,每个子目录下面有.c文件
例如:目录Test Test.c 下面有子目录Sub0和Sub1   子目录Sub0下面有Sub0.c ;子目录Sub1下面有Sub1.c
      makefile 里面可以用wildcard函数
      src=$(wildcard *.c) $(wildcard ./Sub0/*.c) $(wildcard ./Sub1/*.c)
      src里面包含 Test.c Sub0.c Sub1.c .c文件
/*************************************************************************************/
在Makefile中我们经常看到 = := ?= +=这几个赋值运算符,那么他们有什么区别呢?我们来做个简单的实验

新建一个Makefile,内容为:
ifdef DEFINE_VRE
    VRE = “Hello World!”
else
endif

ifeq ($(OPT),define)
    VRE ?= “Hello World! First!”
endif

ifeq ($(OPT),add)
    VRE += “Kelly!”
endif

ifeq ($(OPT),recover)
    VRE := “Hello World! Again!”
endif

all:
    @echo $(VRE)

敲入以下make命令:
make DEFINE_VRE=true OPT=define 输出:Hello World!
make DEFINE_VRE=true OPT=add 输出:Hello World! Kelly!
make DEFINE_VRE=true OPT=recover  输出:Hello World! Again!
make DEFINE_VRE= OPT=define 输出:Hello World! First!
make DEFINE_VRE= OPT=add 输出:Kelly!
make DEFINE_VRE= OPT=recover 输出:Hello World! Again!

从上面的结果中我们可以清楚的看到他们的区别了
= 是最基本的赋值
:= 是覆盖之前的值
?= 是如果没有被赋值过就赋予等号后面的值
+= 是添加等号后面的值

之前一直纠结makefile中“=”和“:=”的区别到底有什么区别,因为给变量赋值时,两个符号都在使用。网上搜了一下,有人给出了解答,但是本人愚钝,看不懂什么意思。几寻无果之下,也就放下了。今天看一篇博客,无意中发现作者对于这个问题做了很好的解答。解决问题之余不免感叹,有时候给个例子不就清楚了吗?为什么非要说得那么学术呢。^_^

      1、“=”

      make会将整个makefile展开后,再决定变量的值。也就是说,变量的值将会是整个makefile中最后被指定的值。看例子:

            x = foo
            y = $(x) bar
            x = xyz

      在上例中,y的值将会是 xyz bar ,而不是 foo bar 。

      2、“:=”

      “:=”表示变量的值决定于它在makefile中的位置,而不是整个makefile展开后的最终值。

            x := foo
            y := $(x) bar
            x := xyz

      在上例中,y的值将会是 foo bar ,而不是 xyz bar 了
/************************************************************************/
#####################################################################
## file        : test makefile for build current dir .c            ##
## author      : jernymy                                           ##
## date-time   : 05/06/2010                                        ##
#####################################################################

CC      = gcc
CPP     = g++
RM      = rm -rf

## debug flag
DBG_ENABLE   = 1

## source file path
SRC_PATH   := .

## target exec file name
TARGET     := test

## get all source files
SRCS         += $(wildcard $(SRC_PATH)/*.c)

## all .o based on all .c
OBJS        := $(SRCS:.c=.o)


## need libs, add at here
LIBS :=

## used headers  file path
INCLUDE_PATH := .

## used include librarys file path
LIBRARY_PATH := /lib

## debug for debug info, when use gdb to debug
ifeq (1, ${DBG_ENABLE})
    CFLAGS += -D_DEBUG -O0 -g -DDEBUG=1
endif

## get all include path
CFLAGS  += $(foreach dir, $(INCLUDE_PATH), -I$(dir))

## get all library path
LDFLAGS += $(foreach lib, $(LIBRARY_PATH), -L$(lib))

## get all librarys
LDFLAGS += $(foreach lib, $(LIBS), -l$(lib))


all: clean build

build:
    $(CC) -c $(CFLAGS) $(SRCS)
    $(CC) $(CFLAGS) -o $(TARGET) $(OBJS) $(LDFLAGS)
    $(RM) $(OBJS)

clean:
    $(RM) $(OBJS) $(TARGET)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值