gcc/g++ 有没有办法从命令行转储其预处理器定义?我的意思是 __GNUC__
、__STDC__
等。
是的,使用 -E -dM
选项而不是 -c。示例(将它们输出到标准输出):
echo | gcc -dM -E -
echo | clang -dM -E -
对于 C++
echo | g++ -dM -E -x c++ -
echo | clang++ -dM -E -x c++ -
从 gcc manual:
代替正常的输出,为预处理器执行期间定义的所有宏生成一个“#define”指令列表,包括预定义的宏。这为您提供了一种查找预处理器版本中预定义内容的方法。假设你没有文件 foo.h,命令 touch foo.h; cpp -dM foo.h 将显示所有预定义的宏。如果在没有 -E 选项的情况下使用 -dM,则 -dM 被解释为 -fdump-rtl-mach 的同义词。
我通常这样做:
$ gcc -dM -E - < /dev/null
请注意,一些预处理器定义依赖于命令行选项 - 您可以通过将相关选项添加到上述命令行来测试这些选项。例如,要查看默认启用了哪些 SSE3/SSE4 选项:
$ gcc -dM -E - < /dev/null | grep SSE[34]
#define __SSE3__ 1
#define __SSSE3__ 1
然后在指定 -msse4
时进行比较:
$ gcc -dM -E -msse4 - < /dev/null | grep SSE[34]
#define __SSE3__ 1
#define __SSE4_1__ 1
#define __SSE4_2__ 1
#define __SSSE3__ 1
类似地,您可以看到两组不同的命令行选项之间哪些选项不同,例如比较优化级别 -O0
(无)和 -O3
(完整)的预处理器定义:
$ gcc -dM -E -O0 - < /dev/null > /tmp/O0.txt
$ gcc -dM -E -O3 - < /dev/null > /tmp/O3.txt
$ sdiff -s /tmp/O0.txt /tmp/O3.txt
#define __NO_INLINE__ 1 <
> #define __OPTIMIZE__ 1
迟到的答案 - 我发现其他答案很有用 - 并想补充一点。
如何转储来自特定头文件的预处理器宏?
echo "#include <sys/socket.h>" | gcc -E -dM -
或(感谢@mymedia 的建议):
gcc -E -dM -include sys/socket.h - < /dev/null
特别是,我想看看 SOMAXCONN 在我的系统上的定义。我知道我可以打开标准头文件,但有时我必须搜索一下才能找到头文件的位置。相反,我可以只使用这个单行:
$ gcc -E -dM -include sys/socket.h - < /dev/null | grep SOMAXCONN
#define SOMAXCONN 128
$
简单的方法(gcc -dM -E - < /dev/null
)对 gcc 很好,但对 g++ 失败。最近我需要一个 C++11/C++14 特性的测试。相应宏名称的建议发布在 https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations。但:
g++ -dM -E - < /dev/null | fgrep __cpp_alias_templates
总是失败,因为它静默调用 C 驱动程序(就像被 gcc
调用一样)。您可以通过将其输出与 gcc 的输出进行比较或添加一个 g++ 特定的命令行选项(如 (-std=c++11))来查看这一点,该选项会发出错误消息 cc1: warning: command line option ‘-std=c++11’ is valid for C++/ObjC++ but not for C
。
因为(非 C++)gcc 从不支持“模板别名”(参见 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf),您必须添加 -x c++
选项以强制调用 C++ 编译器(使用 {2 } 选项而不是一个空的虚拟文件转到 yuyichao,见下文):
g++ -dM -E -x c++ /dev/null | fgrep __cpp_alias_templates
不会有输出,因为 g++(修订版 4.9.1,默认为 -std=gnu++98)默认不启用 C++11 功能。为此,请使用
g++ -dM -E -x c++ -std=c++11 /dev/null | fgrep __cpp_alias_templates
最终产生
#define __cpp_alias_templates 200704
注意当使用 -std=c++11
调用时,g++ 4.9.1 确实支持“模板别名”。
-x
参数,因此 g++ -x c++ -dM -E -std=c++11 - < /dev/null | grep cpp
应该可以工作。
在 Linux 或 Windows(没有 /dev/null 的情况下)上同样适用的可移植方法:
echo | gcc -dM -E -
对于 c++,您可以使用(将 c++11
替换为您使用的任何版本):
echo | gcc -x c++ -std=c++11 -dM -E -
它通过告诉 gcc 预处理标准输入(由 echo 产生)和 print all preprocessor defines(搜索 -dletters
)来工作。如果您想知道在包含头文件时添加了什么定义,您可以使用类似于 -dM 但不包含预定义宏的 -dD
选项:
echo "#include <stdlib.h>" | gcc -x c++ -std=c++11 -dD -E -
但是请注意,空输入仍然会产生大量带有 -dD
选项的定义。
NUL
,您又回到了第一个问题:它不会在没有它的系统上工作。
sort
的行为略有不同):echo | gcc -x c++ -std=c++17 -dM -E - | sort
在一个具有复杂构建系统并且很难直接获取(或修改)gcc/g++ 命令的大型项目中工作时,还有另一种方法可以查看宏扩展的结果。只需重新定义宏,您将获得类似于以下内容的输出:
file.h: note: this is the location of the previous definition
#define MACRO current_value
-Wno-builtin-macro-redefined
是一个?
echo | gcc -dM -E -
也适用于 Windows。cpp -dM -E - < NUL
。