Skip to content

Commit

Permalink
waf: add support for generating compile_commands.json
Browse files Browse the repository at this point in the history
  • Loading branch information
bugobliterator committed Jun 7, 2024
1 parent cb22a63 commit afe5292
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 1 deletion.
124 changes: 123 additions & 1 deletion Tools/ardupilotwaf/ap_library.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import os
import re

from waflib import Errors, Task, Utils
from waflib import Errors, Task, Utils, Logs
from waflib.Configure import conf
from waflib.TaskGen import after_method, before_method, feature
from waflib.Tools import c_preproc
Expand Down Expand Up @@ -321,6 +321,128 @@ def ap_library_register_for_check(self):
tsk = self.create_task('ap_library_check_headers')
tsk.compiled_task = t

def write_compilation_database(bld):
"""
Write the compilation database as JSON
"""
database_file = bld.bldnode.find_or_declare('compile_commands.json')
# don't remove the file at clean

Logs.info('Build commands will be stored in %s', database_file.path_from(bld.path))
try:
root = database_file.read_json()
except IOError:
root = []
compile_cmd_db = dict((x['file'], x) for x in root)
for task in bld.compilation_database_tasks:
try:
cmd = task.last_cmd
except AttributeError:
continue
f_node = task.inputs[0]
filename = f_node.path_from(task.get_cwd())
entry = {
"directory": task.get_cwd().abspath(),
"arguments": cmd,
"file": filename,
}
compile_cmd_db[filename] = entry
root = list(compile_cmd_db.values())
database_file.write_json(root)

def target_list_changed(bld, targets):
"""
Check if the list of targets has changed recorded in target_list file
"""
# target_list file is in the root build directory
target_list_file = bld.bldnode.find_or_declare('target_list')
try:
with open(target_list_file.abspath(), 'r') as f:
old_targets = f.read().strip().split(',')
except IOError:
Logs.info('No target_list file found, creating')
old_targets = []
if old_targets != targets:
with open(target_list_file.abspath(), 'w') as f:
f.write(','.join(targets))
return True
return False

@conf
def remove_target_list(cfg):
target_list_file = cfg.bldnode.make_node(cfg.options.board + '/target_list')
try:
Logs.info('Removing target_list file %s', target_list_file.abspath())
os.remove(target_list_file.abspath())
except OSError:
pass

GEN_COMPILE_JSON = False

@feature('cxxstlib')
@after_method('process_use')
def dry_run_compilation_database(self):
if not hasattr(self, 'bld'):
return
global GEN_COMPILE_JSON
if GEN_COMPILE_JSON:
return
GEN_COMPILE_JSON = True
bld = self.bld
bld.compilation_database_tasks = []
targets = bld.targets.split(',')
# if targets have not changed and neither has configuration,
# we can skip compilation database generation
if not target_list_changed(bld, targets + self.use):
Logs.info('Targets have not changed, skipping compilation database compile_commands.json generation')
return
Logs.info('Generating compile_commands.json')
# we need only to generate last_cmd, so override
# exec_command temporarily
def exec_command(bld, *k, **kw):
return 0

for g in bld.groups:
for tg in g:
# we only care to list targets and library objects
if not hasattr(tg, 'name'):
continue
if (tg.name not in targets) and (tg.name not in self.use):
continue
try:
f = tg.post
except AttributeError:
pass
else:
f()

if isinstance(tg, Task.Task):
lst = [tg]
else:
lst = tg.tasks
for tsk in lst:
if tsk.__class__.__name__ == "swig":
tsk.runnable_status()
if hasattr(tsk, 'more_tasks'):
lst.extend(tsk.more_tasks)
# Not all dynamic tasks can be processed, in some cases
# one may have to call the method "run()" like this:
# elif tsk.__class__.__name__ == 'src2c':
# tsk.run()
# if hasattr(tsk, 'more_tasks'):
# lst.extend(tsk.more_tasks)

tup = tuple(y for y in [Task.classes.get(x) for x in ('c', 'cxx')] if y)
if isinstance(tsk, tup):
bld.compilation_database_tasks.append(tsk)
tsk.nocache = True
old_exec = tsk.exec_command
tsk.exec_command = exec_command
tsk.run()
tsk.exec_command = old_exec

write_compilation_database(bld)

def configure(cfg):
cfg.env.AP_LIBRARIES_OBJECTS_KW = dict()
cfg.env.AP_LIB_EXTRA_SOURCES = dict()
Expand Down
1 change: 1 addition & 0 deletions wscript
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,7 @@ def configure(cfg):
# add in generated flags
cfg.env.CXXFLAGS += ['-include', 'ap_config.h']

cfg.remove_target_list()
_collect_autoconfig_files(cfg)

def collect_dirs_to_recurse(bld, globs, **kw):
Expand Down

0 comments on commit afe5292

Please sign in to comment.