前言
在C/C++开发中,我们常常会在头文件中通过#define 进行宏的定义, 在代码的预编译阶段编译器会将宏进行替换.
然而在有些场景下需要在Makefile中实现类似在头文件通过#define进行宏定义的效果, 那么该怎么写呢?
好在gcc/g++ 等编译器提供了-D这一参数进行同等的操作.
首先可以不通过在Linux下的终端执行 man gcc or man g++命令,查看对于-D参数的说明,
➜ test man gcc
GCC(1) GNU GCC(1)
NAME
gcc - GNU project C and C++ compiler
SYNOPSIS
gcc [-c|-S|-E] [-std=standard]
[-g] [-pg] [-Olevel]
[-Wwarn...] [-Wpedantic]
[-Idir...] [-Ldir...]
[-Dmacro[=defn]...] [-Umacro]
[-foption...] [-mmachine-option...]
[-o outfile] [@file] infile...
Only the most useful options are listed here; see below for the remainder. g++ accepts mostly the same options as gcc.
...
对于-D参数的描述如下(gcc为例子):
-D name
Predefine name as a macro, with definition 1.
-D name=definition
The contents of definition are tokenized and processed as if they appeared during translation phase three in a #define directive. In particular, the definition is truncated by embedded
newline characters.
If you are invoking the preprocessor from a shell or shell-like program you may need to use the shell's quoting syntax to protect characters such as spaces that have a meaning in the
shell syntax.
If you wish to define a function-like macro on the command line, write its argument list with surrounding parentheses before the equals sign (if any). Parentheses are meaningful to most
shells, so you should quote the option. With sh and csh, -D'name(args...)=definition' works.
-D and -U options are processed in the order they are given on the command line. All -imacros file and -include file options are processed after all -D and -U options.
可以看出,主要是两个场景:
- -D name
- -D name=definition
示例演示 -D name
Makefile 文件的实现,
all:
gcc -D TEST test.c
源文件test.c,
#include <stdio.h>
int main(int argc, char **argv)
{
#ifdef TEST
printf("Hi T \r\n");
#endif
return 0;
}
在完成Makefile和test.c 的编写后,test.c 和 Makefile的所在目录下执行make命令,生成可执行程序a.out
➜ test ls
Makefile test.c
➜ test make
gcc -D TEST test.c
然后在终端运行./a.out
➜ test ./a.out
Hi T
➜ test
可以看到打印了字符串"Hi T"
而当去掉Makefile中的-D TEST后,编译生成的a.out,运行不在打印字符串"Hi T"
示例演示 -D name=definition
当definition是数字时,
Makefile 文件的实现,
all:
gcc -D TEST=12 test.c
源文件test.c,
#include <stdio.h>
int main(int argc, char **argv)
{
#ifdef TEST
printf("TEST's value is %d \r\n", TEST);
#endif
return 0;
}
在完成Makefile和test.c 的编写后,test.c 和 Makefile的所在目录下执行make命令,生成可执行程序a.out
➜ test ls
Makefile test.c
➜ test make
gcc -D TEST test.c
然后在终端运行./a.out
➜ test ./a.out
TEST's value is 12
➜ test
当definition是字符串时,
Makefile 文件的实现,
all:
gcc -D TEST=\""hello"\" test.c
源文件test.c,
#include <stdio.h>
int main(int argc, char **argv)
{
#ifdef TEST
printf("TEST's value is %s \r\n", TEST);
#endif
return 0;
}
在完成Makefile和test.c 的编写后,test.c 和 Makefile的所在目录下执行make命令,生成可执行程序a.out
➜ test ls
Makefile test.c
➜ test make
gcc -D TEST test.c
然后在终端运行./a.out
➜ test ./a.out
TEST's value is hello
➜ test
可执行程序打印了TEST值为hello.
总结
在使用gcc or g++的-D参数时需要注意的是在使用-D name=definition传递字符串时需要特别注意.
例如我需要传递的字符串是"hello",那么在上述例子中我们第一感觉的写法是:
all:
gcc -D TEST="hello" test.c
然后在编译生成可执行程序时出现了报错,
➜ test make
gcc -D TEST="hello" test.c
test.c: In function ‘main’:
<command-line>:0:6: error: ‘hello’ undeclared (first use in this function); did you mean ‘ftello’?
test.c:7:39: note: in expansion of macro ‘TEST’
printf("TEST's value is %s \r\n", TEST);
^~~~
<command-line>:0:6: note: each undeclared identifier is reported only once for each function it appears in
test.c:7:39: note: in expansion of macro ‘TEST’
printf("TEST's value is %s \r\n", TEST);
^~~~
Makefile:4: recipe for target 'all' failed
正确的写法是需要在"hello"字符串换加上" 转义,修正如下,
all:
gcc -D TEST=\""hello"\" test.c