如何生成保留注释与#include指令但不展开头文件内容的GCC预处理输出?兼求替代预处理器方案
Unfortunately, GCC doesn’t offer a native flag to retain #include directives (via -dI) while skipping the expansion of included header content. The -E flag inherently processes and expands all included files as part of the preprocessing pipeline. However, you can use a post-processing script to filter out the expanded header content from the -E -CC -dI output.
Example Awk Script to Filter Output
When you run gcc -E -CC -dI file.c -o file.i, the output includes line markers that clearly demarcate when we enter/exit included headers, like:
# 1 "file.c" # 1 "my_header.h" 1 // Entire content of my_header.h here # 2 "file.c" 2 // Back to your original file content
You can leverage this structure to strip header content with an awk script tailored to your source file:
BEGIN { in_main = 0 main_file = "file.c" # Replace with your actual source file name } # Track when we enter the main source file /# 1 "\"/ { current_file = substr($3, 2, length($3)-2) # Strip surrounding quotes if (current_file == main_file) { in_main = 1 print $0 next } else { in_main = 0 next } } # Track when we return to the main file from a header /# [0-9]+ "\"/ { current_file = substr($3, 2, length($3)-2) if (current_file == main_file) { in_main = 1 print $0 next } } # Only print lines when we're inside the main file in_main { print $0 }
Run it with:
awk -f filter_headers.awk file.i > filtered_file.i
This script will retain your original source lines, comments, and #include directives, while stripping all expanded header content cleanly.
If post-processing feels too fragile for your workflow, consider these tools:
1. Clang Preprocessor
Clang supports the same -E -CC -dI flags as GCC, so it has the same header expansion behavior. However, Clang’s output is more consistent, making post-processing slightly more reliable. For a more robust solution, you can use libclang (Clang’s C API) to directly parse your source file and extract type information without relying on preprocessor output—this is ideal if your end goal is building a TypeInfo generator, as it natively understands C types and structs.
2. mcpp (Portable C Preprocessor)
mcpp is a lightweight, standards-compliant preprocessor with granular control over include handling. While it still expands includes by default, you can use -nostdinc to skip standard headers, and combine it with path adjustments (like -I-) to avoid resolving user headers if they’re not needed for your TypeInfo parsing.
3. Custom Minimal Preprocessor
For your specific use case (retain comments, #include directives, no header expansion), you could write a simple custom tool using a Python regex library or a lightweight C parser. This would let you explicitly retain only the parts of the source you care about, without dealing with the full preprocessing pipeline.
If your primary goal is to generate TypeInfo for your project’s types and structs, directly parsing the source code with a dedicated C parser (like libclang) is often more reliable than working with preprocessor output. Parsers can handle types and structs natively, eliminating the need to work around header expansion altogether.
内容的提问来源于stack exchange,提问作者WENDYN

