LV02-05-Makefile-08-GCC宏的使用

本文主要是通过makefile读取配置文件中的宏定义,然后使用GCC的 -D 选项传入C语言文件实现不同的编译代码的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。

点击查看使用工具及版本
Windows windows11
Ubuntu Ubuntu16.04的64位版本
VMware® Workstation 16 Pro 16.2.3 build-19376536
SecureCRT Version 8.7.2 (x64 build 2214) - 正式版-2020年5月14日
开发板 正点原子 i.MX6ULL Linux阿尔法开发板
uboot NXP官方提供的uboot,NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03)
linux内核 linux-4.15(NXP官方提供)
STM32开发板 正点原子战舰V3(STM32F103ZET6)
点击查看本文参考资料
参考方向 参考原文
------
点击查看相关文件下载
--- ---

一、在Makefile中包含文件

在前边的学习中,我们知道,我们可以使用include来包含相关文件,但是当时并没有深入去了解,也没有写例子,现在我们来看一看Makefile的文件包含吧。

1. mk文件

我们可以将被包含的文件命名为filename.mk文件,在整个.mk文件中,我们可以定义一些变量来让Makefile读取,例如我们新建一个config.mk的文件,内容如下:

1
2
3
TEST1=n
TEST2=n
TEST3=y

2. Makefile包含

上边准备好文件后,我们在makefile文件中包含上边的文件并打印出相关的变量的值:

1
2
3
4
5
6
7
include config.mk

print:
@echo "TEST1=$(TEST1)"
@echo "TEST2=$(TEST2)"
@echo "TEST3=$(TEST3)"
@echo "TEST4=$(TEST4)"

然后我们执行 make 命令,会看到如下输出:

1
2
3
4
TEST1=n
TEST2=n
TEST3=y
TEST4=

可以看到,makefile中并没有定义这几个变量,但是都是将变量的值正常打印出来了,除了TEST4为空,因为我们并没有在.mk文件中定义这个变量。

二、GCC的-D选项

在这里,复习一下GCC的-D选项,我们准备一个c语言源文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>

int main(int argc, char *argv[])
{
printf("start!!!\n");
#ifdef TEST1
printf("TEST1 has been defined!!\n");
#endif
#ifdef TEST2
printf("TEST2 has been defined!!\n");
#endif
#ifdef TEST3
printf("TEST3 has been defined!!\n");
#endif

return 0;
}

然后我们编译这个文件,执行以下命令:

1
gcc main.c -Wall

然后执行生成的可执行文件 a.out ,可以得到如下输出:

1
start!!!

会发现,只有第一个输出,后边的都没有输出,原因在哪里呢?我们根本就没有定义上边的TEST1、TEST2和TEST3宏,肯定不会有输出啊。

我们现在更换以下编译命令(注意每一个需要传入的宏都需要使用-D):

1
gcc -DTEST1 -DTEST2 main.c -Wall

然后我们再执行可执行文件,就会得到下列输出信息:

1
2
3
start!!!
TEST1 has been defined!!
TEST2 has been defined!!

发现,我们可以通过-D选项来达到在C语言文件中的#define关键字一样的效果,这也就意味着,我们可以在一套代码中通过不同的编译命令来选择编译出不同的内容。

三、makefile与GCC

一般来说,对于大型工程,我们都会使用makefile来管理,但是他本质上还是在调用GCC来编译工程,所以,这两者可以结合起来,我们在.mk文件中定义宏,选择使用哪些宏,选择不使用哪些宏。接下来我们就来看一看吧。

1. config.mk

我们还是使用上边的config.mk文件,里边只定义宏,并以y表示将其作为GCC的参数,n表示不定义该宏:

1
2
3
CONFIG_TEST1=y
CONFIG_TEST2=n
CONFIG_TEST3=y

2. makefile

我们的makefile文件修改如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
include config.mk

ifeq ($(CONFIG_TEST1), y)
DFLAG +=-DTEST1
endif

ifeq ($(CONFIG_TEST2), y)
DFLAG +=-DTEST2
endif

ifeq ($(CONFIG_TEST3), y)
DFLAG +=-DTEST3
endif

main:
gcc $(DFLAG) main.c -Wall

print:
@echo "CONFIG_TEST1=$(CONFIG_TEST1)"
@echo "CONFIG_TEST2=$(CONFIG_TEST2)"
@echo "CONFIG_TEST3=$(CONFIG_TEST3)"
@echo "DFLAG=$(DFLAG)"

3. main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>

int main(int argc, char *argv[])
{
printf("start!!!\n");
#ifdef TEST1
printf("TEST1 has been defined!!\n");
#endif
#ifdef TEST2
printf("TEST2 has been defined!!\n");
#endif
#ifdef TEST3
printf("TEST3 has been defined!!\n");
#endif

return 0;
}

4. 编译测试

我们执行 make print 命令看一下各变量的值,会看到如下输出:

1
2
3
4
CONFIG_TEST1=y
CONFIG_TEST2=n
CONFIG_TEST3=y
DFLAG=-DTEST1 -DTEST3

然后执行 make 命令,我们会看到如下输出:

1
gcc -DTEST1 -DTEST3 main.c -Wall

可以看到被设置成y的两个配置项已经成为GCC的-D选项的参数啦。

接下来我们执行./a.out,也就是执行可执行文件,会看到如下输出:

1
2
3
start!!!
TEST1 has been defined!!
TEST3 has been defined!!

如此这般,我们的目的就达到了,在.mk文件中进行配置,在makefile文件中进行判断,判断过后将开启的宏添加到GCC编译命令中,这样我们就实现了对整个工程的配置。