makefile中的宏

本文详细解释了Makefile中宏的概念及其在实际编程中的应用,包括用户自定义宏与系统内部宏的区别,并展示了如何在Makefile中定义和使用宏。此外,文章还介绍了如何在命令行中定义宏以及宏的优先级规则。最后,通过实例演示了如何利用宏简化编译过程,提高代码维护性。

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

在makefile中可以使用诸如XLIB、UIL等类似于Shell变量的标识符,这些标识符在makefile中称为“宏”,它可以代表一些文件名或选项。宏的作用类似于C语言中的define,利用它们来代表某些多处使用而又可能发生变化的内容,可以节省重复修改的工作,还可以避免遗漏。

Make的宏分为两类,一类是用户自己定义的宏,一类是系统内部定义的宏。用户定义的宏必须在makefile或命令行中明确定义,系统定义的宏不由用户定义。我们首先介绍第一种宏。

这里是一个包含宏的makefile文件,我们将其命名为mymakefile2,如下所示:

all: main
# 使用的编译器
CC = gcc
#包含文件所在目录
INCLUDE = .
# 在开发过程中使用的选项
CFLAGS = -g -Wall –ansi
# 在发行时使用的选项
# CFLAGS = -O -Wall –ansi
main: main.o f1.o f2.o
$(CC) -o main main.o f1.o f2.o
main.o: main.c def1.h
$(CC) -I$(INCLUDE) $(CFLAGS) -c main.c
f1.o: f1.c def1.h def2.h
$(CC) -I$(INCLUDE) $(CFLAGS) -c f1.c
f2.o: f2.c def2.h def3.h
$(CC) -I$(INCLUDE) $(CFLAGS) -c f2.c

我们看到,在这里有一些注释。在makefile中,注释以#为开头,至行尾结束。注释不仅可以帮助别人理解我们的makefile,如果时间久了,有些东西我们自己也会忘掉,它们对makefile的编写者来说也是很有必要的。

现在言归正传,先看一下宏的定义。我们既可以在make命令行中定义宏,也可以在makefile中定义宏。在makefile中定义宏的基本语法是:

宏标识符=值列表

其中,宏标识符即宏的名称通常全部大写,但它实际上可以由大、小写字母、阿拉伯数字和下划线构成。等号左右的空白符没有严格要求,因为它们最终将被make删除。至于值列表,既可以是零项,也可以是一项或者多项。如:

LIST_VALUE = one two three

当一个宏定义之后,我们就可以通过$(宏标识符)或者${宏标识符}来访问这个标识符所代表的值了。

在makefile中,宏经常用作编译器的选项。很多时候,处于开发阶段的应用程序在编译时是不用优化的,但是却需要调试信息;而正式版本的应用程序却正好相反,没有调试信息的代码不仅所占内存较小,进过优化的代码运行起来也更快。

对于Mymakefile1来说,它假定所用的编译器是gcc,不过在其他的UNIX系统上,更常用的编译器是cc或者c89,而非gcc。如果你想让自己的makefile适用于不同的UNIX操作系统,或者在一个系统上使用其他种类的编译器,这时就不得不对这个makefile中的多处进行修改。

但对于mymakefile2来说则不存在这个问题,我们只需修改一处,即宏定义的值就行了。除了在makefile中定义宏的值之外,我们还可以在make命令行中加以定义,如:

$ make CC=c89

当命令行中的宏定义跟makefile中的定义有冲突时,以命令行中的定义为准。当在makefile文件之外使用时,宏定义必须作为单个参数进行传递,所以要避免使用空格,但是更妥当的方法是使用引号,如:

$ make “CC =   c89”

这样就不必担心空格所引起的问题了。现在让我们将前面的编译结果删掉,来测试一下mymakefile2的工作情况。命令如下所示:

$ rm *.o main

$ make -f Mymakefile2
gcc -I. -g -Wall -ansi -c main.c
gcc -I. -g -Wall -ansi -c f1.c
gcc -I. -g -Wall -ansi -c f2.c
gcc -o main main.o f1.o f2.o
$

就像我们看到的那样,Make程序会用相应的定义来替换宏引用$(CC )、$(CFLAGS )和$(INCLUDE),这跟C语言中的宏的用法比较相似。

上面介绍了用户定义的宏,现在介绍make的内部宏。常用的内部宏有:

$? :比目标的修改时间更晚的那些依赖模块表。
$@ :当前目标的全路径名。可用于用户定义的目标名的相关行中。
$< :比给定的目标文件时间标记更新的依赖文件名。
$* :去掉后缀的当前目标名。例如,若当前目标是pro.o,则$*表示pro。


<think>我们在之前的讨论中已经了解了Makefile的基本使用和定义的相关知识。根据用户当前的问题“如何在Makefile中定义和使用”,结合用户提供的引用内容,我们可以总结如下:在Makefile中定义主要通过编译器选项`-D`实现,通常将其添加到`CFLAGS`(或类似的)变量中。定义有两种主要形式:1.定义符号(无值):`-D名称`2.定义有值的(字符串或整数):`-D名称=值`我们可以在Makefile中通过变量(如`CFLAGS`)来添加这些选项,然后在编译命令中使用该变量。###具体步骤:1.**在Makefile中定义**:在变量`CFLAGS`(C编译器标志)或`CXXFLAGS`(C++编译器标志)中添加`-D`选项。2.**使用**:在源代码中通过`#ifdef`或`#if`等预处理指令来使用。###示例1:定义一个无值的(例如,定义`_DEBUG`)在Makefile中:```makefileCFLAGS+=-D_DEBUG```在C源代码中:```c#ifdef_DEBUGprintf("Debugmodeenabled\n");#endif```###示例2:定义有值的(例如,字符串`VERSION`和整数`LEVEL`)在Makefile中:```makefileCFLAGS+=-DVERSION=\"1.0\"-DLEVEl=10```在C源代码中:```cprintf("Version:%s\n",VERSION);printf("Level:%d\n",LEVEL);```###示例3:在Makefile中传递的值我们可以通过命令行覆盖Makefile中的定义,例如:```bashmakeCFLAGS="-DLEVEL=5"```###一个完整的Makefile示例(参考引用[4]):```makefileCC=gccCFLAGS=-O0-Wall-gCFLAGS+=-DVERSION=\"1.0\"#定义字符串CFLAGS+=-DLEVEL=10#定义整数TARGET=test$(TARGET):test.c$(CC)$(CFLAGS)$^-o$@clean:rm-f$(TARGET)```###注意事项:-对于字符串,在Makefile中定义时需要用转义引号(`\"`)包裹字符串,例如:`-DVERSION=\"1.0\"`。-整数则直接赋值,如`-DLEVEL=10`。-定义对大小写敏感。通过以上方式,我们可以在Makefile中灵活地定义和使用,控制程序的不同编译行为。§§相关问题§§1.如何在Makefile中通过命令行参数覆盖定义?2.定义在Makefile中的常见应用场景有哪些?3.如何检查Makefile中定义的是否生效?</think> ### 如何在 Makefile 中定义和使用Makefile 中定义和使用主要通过编译器的 `-D` 选项实现,结合预定义的变量 `CFLAGS` 或 `CXXFLAGS`。以下是具体操作步骤: #### 1. **基础定义(无值)** ```makefile CFLAGS += -DDEBUG # 定义 DEBUG ``` 在代码中使用: ```c #ifdef DEBUG printf("Debug mode enabled\n"); #endif ``` #### 2. **带值的定义** ```makefile # 定义字符串 (需转义引号) CFLAGS += -DVERSION=\"1.0\" # 定义整型 CFLAGS += -DBUFFER_SIZE=1024 ``` 在代码中使用: ```c printf("Version: %s\n", VERSION); int buffer[BUFFER_SIZE]; ``` #### 3. **完整 Makefile 示例** ```makefile CC = gcc CFLAGS = -Wall -O2 CFLAGS += -DPLATFORM_LINUX # 平台 CFLAGS += -DMAX_USERS=100 # 整型 CFLAGS += -DAPP_NAME=\"MyApp\" # 字符串 target: source.c $(CC) $(CFLAGS) source.c -o target ``` #### 4. **关键细节** - **变量位置**:定义需放在编译命令前 - **命令行覆盖**:可通过命令行覆盖值 ```bash make CFLAGS="-DMAX_USERS=200" ``` - **字符串处理**:字符串需转义引号 `-DNAME=\"value\"` - **变量传递**:在编译指令中使用 `$(CC) $(CFLAGS) ...` 传递 #### 5. **实际应用场景** 1. **环境区分**:`-DENV_PRODUCTION` 2. **功能开关**:`-DUSE_FEATURE_X` 3. **版本控制**:`-DBUILD_VERSION=\"v2.3\"` 4. **硬件适配**:`-DARCH_ARM=1` > 参考实现:[^1][^2][^4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值