Home / Alt manpages / x86_64-linux-gnu-cpp-13(1)

  • x86_64-linux-gnu-cpp-13(1)
  • User command
  • linux

Preprocess C and C++ Safely with x86_64-linux-gnu-cpp-13

By the end of this guide you will be able to turn a C or C++ source file into inspectable preprocessor output, control its macros and include paths, and produce a Make dependency file. The examples target Ubuntu's x86_64-linux-gnu-cpp-13, provided by GCC 13.3.0 packages. Allow about 10 minutes if the source file already exists.

Before you start

You need a shell, the installed command, and a C or C++ source file that you are allowed to read. Check the version and executable location first:

x86_64-linux-gnu-cpp-13 --version
command -v x86_64-linux-gnu-cpp-13

On the target system this reports Ubuntu's GCC 13.3.0 build and normally resolves to /usr/bin/x86_64-linux-gnu-cpp-13. The unversioned x86_64-linux-gnu-cpp alias reports the same installed GCC build here.

Checkpoint

Continue only when the command exists and its version is the one you intend to document or reproduce.

1. Expand a source file to standard output

Create a small input in a disposable directory, or substitute a real source path. This example uses a temporary file and sends the result to standard output, so it changes no project files:

work=/tmp/cpp-guide
mkdir -p "$work"
printf '%s\n' '#define LIMIT 3' 'int values[LIMIT];' > "$work/sample.c"
x86_64-linux-gnu-cpp-13 -P "$work/sample.c"

The output contains the declaration with LIMIT expanded to 3. The -P option suppresses preprocessor linemarkers, which makes output easier to read when another tool expects source-like text.

Without -P, CPP normally emits linemarkers so a compiler can retain the original file and line locations. Do not treat preprocessed output as a replacement source file unless the next tool expects it.

Checkpoint

Rerun the command without -P if you need to diagnose where a generated line came from.

2. Select behaviour with macros and headers

Use -D to define a macro before processing and -U to cancel a previous definition. Options are applied in the order given, so a later -U can remove a definition made by an earlier -D. Keep shell quoting around definitions that contain spaces or shell metacharacters.

printf '%s\n' '#if FEATURE_LEVEL >= 2' 'const char *mode = "new";' '#else' 'const char *mode = "old";' '#endif' > "$work/feature.c"
x86_64-linux-gnu-cpp-13 -P -DFEATURE_LEVEL=2 "$work/feature.c"

Expected output is:

const char *mode = "new";

For project headers, -I adds a directory to the include search path for both quoted and angle-bracket includes. -iquote applies only to quoted includes. The quoted form searches the current file's directory first, then quote directories, then -I directories and system directories. This order is a common source of accidental header shadowing.

mkdir -p "$work/include"
printf '%s\n' '#define MESSAGE "from local header"' > "$work/include/settings.h"
printf '%s\n' '#include "settings.h"' 'const char *message = MESSAGE;' > "$work/header.c"
x86_64-linux-gnu-cpp-13 -P -I "$work/include" "$work/header.c"

Expected output is:

const char *message = "from local header";

Safety boundary

Do not use -I casually to replace vendor or system headers. The manpage recommends -isystem for vendor-supplied system headers, because it preserves system-header treatment and avoids surprising include ordering.

3. Save output without overwriting the input

Use -o to write preprocessed output to a separate file. The command accepts standard input or standard output as -, and omitted input or output is treated similarly. Make the destination explicit when scripting so a misplaced argument cannot silently replace an important file.

x86_64-linux-gnu-cpp-13 -P -I "$work/include" "$work/header.c" -o "$work/header.i"
test -s "$work/header.i" && sed -n '1,5p' "$work/header.i"

There is no elevated-privilege step here. If the destination is owned by another user, fix the path or permissions rather than reaching for sudo. Warning: the cleanup command below permanently removes files under the named temporary directory. Check the path before running it: rm -rf /tmp/cpp-guide. Use the actual disposable directory if you used the commands above.

4. Generate Make dependencies

For build automation, -MMD produces dependencies for user headers while excluding system headers. -MF chooses the dependency file. Use -MT when the Make target is not the default object name.

x86_64-linux-gnu-cpp-13 -MMD -MF "$work/header.d" -MT 'build/header.o' -I "$work/include" "$work/header.c"
sed -n '1,5p' "$work/header.d"

The dependency rule names build/header.o, the source file and settings.h. If you need system headers included too, use -MD instead. If a generated header is not present yet, -MG can add it to dependency output without raising an error, but use that only when the build has a real generation step.

Do not confuse these modes: -M and -MM emit dependency rules instead of normal preprocessed output. -MF keeps those rules out of the normal output stream. A dependency file is build metadata, not compilable C.

5. Investigate a failing include or macro

Use -H to print each header as it is read, with indentation showing nesting. Use -dM to list the macros defined during processing, including predefined macros. These are diagnostic views, so capture them separately when another tool consumes standard output.

x86_64-linux-gnu-cpp-13 -H -P -I "$work/include" "$work/header.c" > "$work/expanded.txt" 2> "$work/headers.txt"
sed -n '1,5p' "$work/headers.txt"
x86_64-linux-gnu-cpp-13 -dM - < /dev/null | grep -E '^#define (__GNUC__|__x86_64__)'

If an undefined identifier is evaluated in an #if, CPP treats it as zero. Add -Wundef when that default could hide a typo. For strict standard diagnostics, select the relevant -std=c90, -std=c99, -std=c11 or -std=c17 mode and add -pedantic when required. The exact language standard belongs to the project, not to a generic troubleshooting command.

Common traps

  • CPP is for C, C++ and Objective-C lexical input. It can damage formats such as Makefiles by removing significant tabs; use a real text processor for general text.
  • Do not group multi-letter options. -dM is not equivalent to -d -M.
  • Do not assume -C is harmless. Preserving comments can make comments act as tokens and change how directives are recognised.
  • Do not edit system headers to repair an include problem. Inspect the search order with -H, then correct -I, -iquote or the build configuration.

Done means

  • The installed GCC 13.3.0 preprocessor version is confirmed.
  • A disposable source file expands to the expected output.
  • Macro and include-path choices are explicit and verified.
  • Preprocessed output and Make dependencies are written to separate files.
  • Header and macro diagnostics can be captured without contaminating build output.