xref: /aosp_15_r20/external/pigweed/pw_ide/design/cpp.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1.. _module-pw_ide-design-cpp:
2
3=======================
4C/C++ code intelligence
5=======================
6.. pigweed-module-subpage::
7   :name: pw_ide
8
9Pigweed projects have a few characteristics that make it challenging for some
10IDEs and language servers to support C/C++ code intelligence out of the box:
11
12* Pigweed projects generally don't use the default host toolchain.
13
14* Pigweed projects usually use multiple toolchains for separate targets.
15
16* Pigweed projects rely on the build system to define the relationship between
17  :ref:`facades and backends<docs-module-structure-facades>` for each target.
18
19These challenges are common to embedded projects in general.
20
21We've found that the best solution is to use the
22`clangd <https://clangd.llvm.org/>`_ language server or alternative language
23servers that use the same
24`compilation database format <https://clang.llvm.org/docs/JSONCompilationDatabase.html>`_
25and comply with the language server protocol. Usually, your build system
26generates the compilation database, and we supplement that with Pigweed
27tools to produce target-specific compilation databases that work well with
28language servers.
29
30-------------------------------------------
31Supporting ``clangd`` for embedded projects
32-------------------------------------------
33There are three main challenges that often prevent ``clangd`` from working
34out-of-the-box with embedded projects:
35
36#. Embedded projects cross-compile using alternative toolchains, rather than
37   using the system toolchain. ``clangd`` doesn't know about those toolchains
38   by default.
39
40#. Embedded projects (particularly Pigweed projects) often have *multiple*
41   targets that use *multiple* toolchains. Most build systems that generate
42   compilation databases put all compile commands in a single database, meaning
43   a single file can have multiple, conflicting compile commands. ``clangd``
44   will typically use the first one it finds, which may not be the one you want.
45
46#. Pigweed projects have build steps that use languages other than C/C++. These
47   steps are not relevant to ``clangd`` but some build systems will include them
48   in the compilation database anyway.
49
50To deal with these challenges, ``pw_ide`` processes the compilation database(s)
51you provide, yielding one or more compilation databases that are valid,
52consistent, and specific to a particular target and toolchain combination.
53This enables code intelligence and navigation features that accurately reflect
54a specific build.
55
56After processing a compilation database, ``pw_ide`` knows what targets are
57available and provides tools for selecting which target the language server
58should use.  Then ``clangd``'s configuration is changed to use the compilation
59database associated with that target.
60
61----------------------
62Implementation details
63----------------------
64.. tab-set::
65
66   .. tab-item:: Bazel
67
68      Bazel doesn't have native support for generating compile commands, so it's
69      common to rely on outside tools. In the
70      :ref:`Pigweed Visual Studio Code extension<module-pw_ide-guide-vscode>`,
71      we use the `Bazel Compile Commands Extractor <https://github.com/hedronvision/bazel-compile-commands-extractor>`_.
72
73   .. tab-item:: GN
74
75      Invoking GN with the ``--export-compile-commands`` flag (e.g.
76      ``gn gen out --export-compile-commands``) will output a compilation
77      database in the ``out`` directory along with all of the other GN build
78      outputs (in other words, it produces the same output as ``gn gen out``
79      but *additionally* produces the compilation database). You can remove the
80      need to explicitly provide the flag by adding this to your ``.gn`` file:
81      ``export_compile_commands = [ ":*" ]``.
82
83      The database that GN produces will have all compile commands for all
84      targets, which is a problem for the reasons described above. It will also
85      include invocations of certain Pigweed Python scripts that are not valid
86      C/C++ compile commands and cause ``clangd`` to fault. So these files need
87      to be processed to:
88
89      * Filter out invalid compile commands
90
91      * Separate compile commands into separate databases for each target
92
93      * Resolve relative paths so ``clangd`` can find tools in the Pigweed
94        environment
95
96      The :ref:`pw_ide CLI<module-pw_ide-guide-cli>` does all of this when you
97      run the ``sync`` command.
98
99   .. tab-item:: CMake
100
101      Enabling the ``CMAKE_EXPORT_COMPILE_COMMANDS`` option ensures that
102      compilation databases are produced along with the rest of the CMake build.
103      This can be done either in your project's ``CMakeLists.txt`` (i.e.
104      ``set(CMAKE_EXPORT_COMPILE_COMMANDS ON)``), or by setting the flag when
105      invoking CMake (i.e. ``-DCMAKE_EXPORT_COMPILE_COMMANDS=ON``).
106
107      CMake will generate separate ``compile_commands.json`` files that are
108      specific to each target in the target's build output directory. These
109      files are *already* in the format we need them to be in, so the only
110      thing Pigweed needs to provide is a mechanism for discovering those
111      targets and pointing ``clangd`` at the appropriate file.
112
113.. _module-pw_ide-design-cpp-target-groups:
114
115-------------
116Target groups
117-------------
118Running code intelligence on the compilation database of a single target is the
119most *consistent* approach, but it's not always the most *useful*. For example,
120application code and test code are usually built in separate targets, but it's
121a nuisance to switch code intelligence targets as you move back and forth
122between application code and test code.
123
124We address this through the use of "target groups", which in which a compilation
125database is build by intentionally combining the compile commands from several
126related targets. Continuing the previous example, you might have a target
127group that contains both the application code and test code to eliminate the
128nuisance of repeatedly switching between those targets. The compile commands
129for the application code would be higher in the list than those for test code,
130so in a conflict (e.g., a test that uses a different backend from the
131application code), you will get code intelligence for the application code. This
132is usually an acceptable trade-off.
133