Skip to content

Instantly share code, notes, and snippets.

@yoshinari-nomura
Created October 22, 2025 11:31
Show Gist options
  • Select an option

  • Save yoshinari-nomura/3c2521641a77867d819be9e3e04d0d3e to your computer and use it in GitHub Desktop.

Select an option

Save yoshinari-nomura/3c2521641a77867d819be9e3e04d0d3e to your computer and use it in GitHub Desktop.
clangd-setup - Generate .clangd from compile_commands.json
#!/bin/bash
################################################################
# * clangd-setup - Generate .clangd from compile_commands.json
#
# Copyright (C) 2025 Yoshinari Nomura <[email protected]>
# LICENSE: MIT
#
# clangd-setup is useful when your project uses GCC/G++ cross-compilers,
# such as in Arduino (CLI) or ESP-IDF projects.
#
# It performs the following steps:
# 1) Finds project-specific compiler executables from {build/,}compile_commands.json
# 2) Queries the compilers for their default include paths
# 3) Generates a .clangd file with CompileFlags: Add: and Remove: sections
#
# * Usage
#
# From your project root directory:
# clangd-setup > .clangd
#
# clangd-setup works similarly to using the clangd --query-driver option.
# However, setting --query-driver for each project individually
# is cumbersome and inconvenient for me.
#
################################################################
# Find compiler executable names from compile_commands.json
#
# For an ESP-IDF project: "command": "/usr/bin/gcc ..."
#
# jq -r '.[].command| split(" ")[0]' compile_commands.json
#
# For an Arduino CLI project: "arguments": ["/usr/bin/gcc", ...
#
# jq -r '.[].arguments[0]' compile_commands.json
#
# Combined form:
#
# jq -r '.[]| (.arguments[0]//(.command| split(" ")[0]))' compile_commands.json
#
function find_compilers() {
local compile_commands_json="$1"
jq -r '.[]| (.arguments[0] // (.command| split(" ")[0]))' \
"$compile_commands_json" | sort | uniq
}
# Show the default include paths for a given compiler
#
function default_include_path() {
local compiler="$1"
echo "" | "$compiler" -xc++ -E -v - 2>&1 | \
sed -n '1,/^#include <...> .* here:/d; /^End of/q; s/^ *//p'
}
# Find the path to compile_commands.json
#
function find_compile_commands_json() {
for d in . build
do
if [ -f "$d/compile_commands.json" ]; then
echo "$d/compile_commands.json"
return
fi
done
}
################################################################
# Find compilers from compile_commands.json
compile_commands_json=$(find_compile_commands_json)
if [ -z "$compile_commands_json" ]; then
echo "compile_commands.json not found." >&2
exit 1
fi
compilers=$(find_compilers "$compile_commands_json")
if [ -z "$compilers" ]; then
echo "No compilers found." >&2
exit 1
fi
################################################################
# Query each compiler for its default include paths
echo "# Add below in your .clangd:" >&2
cat <<EOH
CompileFlags:
Add: [
EOH
for compiler in $compilers
do
for include_path in $(default_include_path "$compiler")
do
echo " -I$(realpath $include_path),"
done
done
################################################################
# Remove GCC-specific compiler options
cat <<EOF
]
Remove: [
-fstrict-volatile-bitfields,
-fno-tree-switch-conversion,
-fno-shrink-wrap,
-fno-tree-switch-conversion
]
EOF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment