build: Add simple compile_commands.json generation

This can be used with a clangd server to get code completion and cross
references in editor. To simplify the generation, create .cmd files for
most object files while building that contains the base directory and
command that was used when compiling it.

A very simple gen_compile_commands.py is provided which will read one or
more build directories and generate the compile_commands.json file for
it.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
This commit is contained in:
Benjamin Berg 2024-05-08 12:56:10 +02:00 committed by Jouni Malinen
parent 733069fd4c
commit 619ff3d2e8
3 changed files with 60 additions and 0 deletions

3
.gitignore vendored
View file

@ -6,3 +6,6 @@ wpaspy/build
**/parallel-vm.log **/parallel-vm.log
tags tags
build/ build/
# clangd commands and cache
compile_commands.json
.cache

54
gen_compile_commands.py Executable file
View file

@ -0,0 +1,54 @@
#!/usr/bin/env python3
# compile_commands.json generator
# Copyright (C) 2024 Intel Corporation
#
# This software may be distributed under the terms of the BSD license.
# See README for more details.
import os
import sys
import glob
import json
import argparse
parser = argparse.ArgumentParser(description='Read each of the build directories that are given and generate '
'a compile_commands.json file. If a source file is found multiple times, '
'then the compile flags from the last build directory will be used.')
parser.add_argument('-o', '--output', default='compile_commands.json', type=str,
help="Output file to generate")
parser.add_argument('builddirs', nargs='+', type=str, metavar="builddir",
help='Build directories to search')
args = parser.parse_args()
files = {}
for builddir in args.builddirs:
for cmd_file in glob.glob('**/*.o.cmd', root_dir=builddir, recursive=True):
with open(os.path.join(builddir, cmd_file), encoding='ascii') as f:
base_dir, cmd = f.readline().split(':', 1)
src_file = cmd.rsplit(maxsplit=1)[1]
src_file = os.path.abspath(os.path.join(base_dir, src_file))
files[src_file] = {
'command': cmd.strip(),
'directory': base_dir,
'file': src_file,
}
flist = json.dumps(sorted(list(files.values()), key=lambda k: k['file']), indent=2, sort_keys=True)
try:
# Avoid writing the file if it did not change, first read original
with open(args.output, 'rt', encoding='UTF-8') as f:
orig = []
while data := f.read():
orig.append(data)
orig = ''.join(orig)
except OSError:
orig = ''
# And only write if something changed
if orig != flist:
with open(args.output, 'wt', encoding='UTF-8') as f:
f.write(flist)

View file

@ -83,13 +83,16 @@ _make_dirs:
@mkdir -p $(sort $(_DIRS)) @mkdir -p $(sort $(_DIRS))
$(BUILDDIR)/$(PROJ)/src/%.o: $(ROOTDIR)src/%.c $(CONFIG_FILE) | _make_dirs $(BUILDDIR)/$(PROJ)/src/%.o: $(ROOTDIR)src/%.c $(CONFIG_FILE) | _make_dirs
@echo $(CURDIR): '$(CC) -c -o $@ $(CFLAGS) $<' >$@.cmd
$(Q)$(CC) -c -o $@ $(CFLAGS) $< $(Q)$(CC) -c -o $@ $(CFLAGS) $<
@$(E) " CC " $< @$(E) " CC " $<
$(BUILDDIR)/$(PROJ)/%.o: %.c $(CONFIG_FILE) | _make_dirs $(BUILDDIR)/$(PROJ)/%.o: %.c $(CONFIG_FILE) | _make_dirs
@echo $(CURDIR): '$(CC) -c -o $@ $(CFLAGS) $<' >$@.cmd
$(Q)$(CC) -c -o $@ $(CFLAGS) $< $(Q)$(CC) -c -o $@ $(CFLAGS) $<
@$(E) " CC " $< @$(E) " CC " $<
# for the fuzzing tests # for the fuzzing tests
$(BUILDDIR)/$(PROJ)/wpa_supplicant/%.o: $(ROOTDIR)wpa_supplicant/%.c $(CONFIG_FILE) | _make_dirs $(BUILDDIR)/$(PROJ)/wpa_supplicant/%.o: $(ROOTDIR)wpa_supplicant/%.c $(CONFIG_FILE) | _make_dirs
@echo $(CURDIR): '$(CC) -c -o $@ $(CFLAGS) $<' >$@.cmd
$(Q)$(CC) -c -o $@ $(CFLAGS) $< $(Q)$(CC) -c -o $@ $(CFLAGS) $<
@$(E) " CC " $< @$(E) " CC " $<