LUMIERA.clone/admin/scons/CompileDB.py
Ichthyostega 109d682408 Buildsystem: generate a compilation database for clangd (closes: #1436)
Knowledge-Technology(Claude Opus 5) used
 - to assess the situation and present implementation avenues
 - for discussion while shaping the solution
 - for generating code and validating results

Clang based tooling is used frequently for code analysis and navigation.
This requires however that the exact flags and invocation is captured for
each possible translation unit in the code base. That knowledge exists solely
in the build system, and the established way to hand it over is the
LLVM "JSON Compilation Database".

SCons has provided a `CompilationDatabase` builder since 4.0, and it fits
our setup well: it installs an emitter on the object builders and captures
each command line while the dependency graph is constructed. Hence nothing
is compiled -- generating takes about two seconds -- and the result always
describes the complete build graph as declared, rather than the target
actually requested on this invocation.

This feature is provided as ''opt-in'', either through the sticky option
`COMPILEDB=yes` or by direct invocation with `scons compiledb`

The `compile_commands.json` is generated into the build output `target/' dir
For configuration, a `.clangd` in project root instructs the language server
where to find this file.

__Note__ the ordering constraint recorded in `CompileDB.py`:
the emitter must be installed only after `Platform.configure()` has run,
or it also captures the `conftest_*` compilations of the configure checks.
That is why this is a plain helper invoked from the `SConstruct` -- similar to
Setup, Options, Platform -- and not a tool loaded from the `LumieraEnvironment`.
2026-10-01 01:08:23 +02:00

59 lines
3 KiB
Python

# coding: utf-8
##
## CompileDB.py - SCons build: generate a compilation database for clangd
##
# Copyright (C)
# 2026, Hermann Vosseler <Ichthyostega@web.de>
#
# **Lumiera** is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version. See the file COPYING for further details.
#####################################################################
from SCons.Script import COMMAND_LINE_TARGETS
def setup(env):
""" Emit a *compilation database*, describing every compiler invocation of the
complete build. This JSON file is the interface used by `clangd` and the other
tools built on the Clang front-end, which need to reproduce the exact flags
of a translation unit in order to parse it the way the build does.
The actual work is performed by the `CompilationDatabase` builder, which SCons
provides since 4.0: it installs an additional *emitter* on the object builders,
capturing each command line while the dependency graph is constructed. Thus no
compilation is involved -- `scons compiledb` takes about two seconds -- and the
database always covers the *complete declared build*, not just the requested
target, since the SConscript definitions are processed into a dependency tree
on every invocation anyway.
@return a dependency node, to be added to the `build` alias, or an empty list
when the feature is switched off (in which case nothing at all is
installed into the build environment).
@note **must be invoked after** `Platform.configure(env)`. The emitter would
otherwise also capture the `conftest_*` compilations performed by the
configure checks, which then show up as bogus entries below '.sconf_temp'.
This ordering constraint is why this module is a plain helper invoked
from the 'SConstruct' -- like `Setup`, `Options` and `Platform` -- and
not a SCons tool loaded from the `LumieraEnvironment` constructor.
@remark the database is written into the (relocatable) target tree, while the
'.clangd' configuration in the project root directs the language server
there; consumers do not search 'target/' on their own.
"""
if not isActivated(env): return []
env.Tool('compilation_db') # the builder provided by SCons
env['COMPILATIONDB_USE_ABSPATH'] = True # make recorded content unambiguous
compileDB = env.CompilationDatabase('$TARGDIR/compile_commands.json')
env.Alias('compiledb', compileDB)
return compileDB
def isActivated(env):
""" generation is opt-in through the (sticky) build option,
but can also be requested for a single invocation by naming the target.
"""
return env['COMPILEDB'] or 'compiledb' in COMMAND_LINE_TARGETS