blob: ea2363d83c2e1b6baa43017cc172df09140c858f [file]
.. _module-pw_ide-contributing-design-cpp:
=======================
C/C++ code intelligence
=======================
.. pigweed-module-subpage::
:name: pw_ide
Pigweed projects have a few characteristics that make it challenging for some
IDEs and language servers to support C/C++ code intelligence out of the box:
* Pigweed projects generally *don't* use the default host toolchain.
* Pigweed projects usually use *multiple* toolchains for separate build targets.
* Pigweed projects rely on the build system to define the relationship between
:ref:`facades and backends<docs-module-structure-facades>` for each target.
These challenges are common to embedded projects in general.
We've found that the best solution is to use the
`clangd <https://clangd.llvm.org/>`_ language server or alternative language
servers that use the same
`compilation database format <https://clang.llvm.org/docs/JSONCompilationDatabase.html>`_
and comply with the language server protocol. Usually, your build system
generates the compilation database, and we supplement that with Pigweed
tools to produce target-specific compilation databases that work well with
language servers.
-------------------------------------------
Supporting ``clangd`` for embedded projects
-------------------------------------------
There are three main challenges that often prevent ``clangd`` from working
out-of-the-box with embedded projects:
#. Embedded projects cross-compile using alternative toolchains, rather than
using the system toolchain. ``clangd`` doesn't know about those toolchains
by default.
#. Embedded projects (particularly Pigweed projects) often have *multiple*
targets that use *multiple* toolchains. Most build systems that generate
compilation databases put all compile commands in a single database, meaning
a single file can have multiple, conflicting compile commands. ``clangd``
will typically use the first one it finds, which may not be the one you want.
#. Pigweed projects have build steps that use languages other than C/C++. These
steps are not relevant to ``clangd`` but some build systems will include them
in the compilation database anyway.
To deal with these challenges, ``pw_ide`` processes the compilation database(s)
you provide, yielding one or more compilation databases that are valid,
consistent, and specific to a particular target and toolchain combination.
This enables code intelligence and navigation features that accurately reflect
a specific build.
After processing a compilation database, ``pw_ide`` knows what targets are
available and provides tools for selecting which target the language server
should use. Then ``clangd``'s configuration is changed to use the compilation
database associated with that target.
----------------------
Implementation details
----------------------
Bazel
=====
Bazel doesn't have native support for generating compile commands, so Pigweed
IDE uses Bazel queries to create ``clangd`` compile commands that reflect the
Bazel build graph.
.. _module-pw_ide-contributing-design-cpp-gn:
GN (Generate Ninja)
===================
Invoking GN with the ``--export-compile-commands`` flag (e.g.
``gn gen out --export-compile-commands``) will output a compilation database
in the ``out`` directory along with all of the other GN build outputs (in other
words, it produces the same output as ``gn gen out`` but *additionally* produces
the compilation database). You can remove the need to explicitly provide the
flag by adding this to your ``.gn`` file:
``export_compile_commands = [ ":*" ]``.
The database that GN produces will have all compile commands for all targets,
which is a problem for the reasons described above. It will also include
invocations of certain Pigweed Python scripts that are not valid C/C++ compile
commands and cause ``clangd`` to fault. So these files need to be processed to:
* Filter out invalid compile commands
* Separate compile commands into separate databases for each target
* Resolve relative paths so ``clangd`` can find tools in the Pigweed
environment
Pigweed IDE does this for you.
.. _module-pw_ide-contributing-design-cpp-cmake:
CMake
=====
Enabling the ``CMAKE_EXPORT_COMPILE_COMMANDS`` option ensures that compilation
databases are produced along with the rest of the CMake build. This can be done
either in your project's ``CMakeLists.txt`` (i.e.
``set(CMAKE_EXPORT_COMPILE_COMMANDS ON)``), or by setting the flag when invoking
CMake (i.e. ``-DCMAKE_EXPORT_COMPILE_COMMANDS=ON``).
CMake will generate separate ``compile_commands.json`` files that are specific
to each target in the target's build output directory. These files are *already*
in the format we need them to be in, so the only thing Pigweed needs to provide
is a mechanism for discovering those targets and pointing ``clangd`` at the
appropriate file.