Add information about main(int, argc **) in places where the documentation stated that only parameterless main could be used Signed-off-by: Jakub Michalski <jmichalski@internships.antmicro.com> Signed-off-by: Filip Kokosinski <fkokosinski@antmicro.com>
255 lines
11 KiB
ReStructuredText
255 lines
11 KiB
ReStructuredText
.. _language_cpp:
|
|
|
|
C++ Language Support
|
|
####################
|
|
|
|
C++ is a general-purpose object-oriented programming language that is based on
|
|
the C language.
|
|
|
|
Enabling C++ Support
|
|
********************
|
|
|
|
Zephyr supports applications written in both C and C++. However, to use C++ in
|
|
an application you must configure Zephyr to include C++ support by selecting
|
|
the :kconfig:option:`CONFIG_CPP` in the application configuration file.
|
|
|
|
To enable C++ support, the compiler toolchain must also include a C++ compiler
|
|
and the included compiler must be supported by the Zephyr build system. The
|
|
:ref:`toolchain_zephyr_sdk`, which includes the GNU C++ Compiler (part of GCC),
|
|
is supported by Zephyr, and the features and their availability documented
|
|
here assume the use of the Zephyr SDK.
|
|
|
|
The default C++ standard level (i.e. the language enforced by the
|
|
compiler flags passed) for Zephyr apps is C++11. Other standards are
|
|
available via kconfig choice, for example
|
|
:kconfig:option:`CONFIG_STD_CPP98`. The oldest standard supported and
|
|
tested in Zephyr is C++98.
|
|
|
|
When compiling a source file, the build system selects the C++ compiler based
|
|
on the suffix (extension) of the files. Files identified with either a **cpp**
|
|
or a **cxx** suffix are compiled using the C++ compiler. For example,
|
|
:file:`myCplusplusApp.cpp` is compiled using C++.
|
|
|
|
The C++ standard requires the ``main()`` function to have the return type of
|
|
``int``. Your ``main()`` must be defined as ``int main(void)`` or
|
|
``int main(int, char **)``. To use main with arguments the ``CONFIG_BOOTARGS`` option
|
|
has to be selected. Zephyr ignores the return value from main, so applications
|
|
should not return status information and should, instead, return zero.
|
|
|
|
.. note::
|
|
Do not use C++ for kernel, driver, or system initialization code.
|
|
|
|
Language Features
|
|
*****************
|
|
|
|
Zephyr currently provides only a subset of C++ functionality. The following
|
|
features are *not* supported:
|
|
|
|
* Static global object destruction
|
|
* OS-specific C++ standard library classes (e.g. ``std::thread``,
|
|
``std::mutex``)
|
|
|
|
While not an exhaustive list, support for the following functionality is
|
|
included:
|
|
|
|
* Inheritance
|
|
* Virtual functions
|
|
* Virtual tables
|
|
* Static global object constructors
|
|
* Dynamic object management with the **new** and **delete** operators
|
|
* Exceptions
|
|
* :abbr:`RTTI (runtime type information)`
|
|
* Standard Template Library (STL)
|
|
|
|
Static global object constructors are initialized after the drivers are
|
|
initialized but before the application :c:func:`main()` function. Therefore,
|
|
use of C++ is restricted to application code.
|
|
|
|
In order to make use of the C++ exceptions, the
|
|
:kconfig:option:`CONFIG_CPP_EXCEPTIONS` must be selected in the application
|
|
configuration file.
|
|
|
|
Zephyr Minimal C++ Library
|
|
**************************
|
|
|
|
Zephyr minimal C++ library (:file:`lib/cpp/minimal`) provides a minimal subset
|
|
of the C++ standard library and application binary interface (ABI) functions to
|
|
enable basic C++ language support. This includes:
|
|
|
|
* ``new`` and ``delete`` operators
|
|
* virtual function stub and vtables
|
|
* static global initializers for global constructors
|
|
|
|
The scope of the minimal C++ library is strictly limited to providing the basic
|
|
C++ language support, and it does not implement any `Standard Template Library
|
|
(STL)`_ classes and functions. For this reason, it is only suitable for use in
|
|
the applications that implement their own (non-standard) class library and do
|
|
not rely on the Standard Template Library (STL) components.
|
|
|
|
Any application that makes use of the Standard Template Library (STL)
|
|
components, such as ``std::string`` and ``std::vector``, must enable the C++
|
|
standard library support.
|
|
|
|
C++ Standard Library
|
|
********************
|
|
|
|
The `C++ Standard Library`_ is a collection of classes and functions that are
|
|
part of the ISO C++ standard (``std`` namespace).
|
|
|
|
Zephyr does not include any C++ standard library implementation in source code
|
|
form. Instead, it allows configuring the build system to link against the
|
|
pre-built C++ standard library included in the C++ compiler toolchain.
|
|
|
|
To enable C++ standard library, select an applicable toolchain-specific C++
|
|
standard library type from the :kconfig:option:`CONFIG_LIBCPP_IMPLEMENTATION`
|
|
in the application configuration file.
|
|
|
|
For instance, when building with the :ref:`toolchain_zephyr_sdk`, the build
|
|
system can be configured to link against the GNU C++ Library (``libstdc++.a``),
|
|
which is a fully featured C++ standard library that provides all features
|
|
required by the ISO C++ standard including the Standard Template Library (STL),
|
|
by selecting :kconfig:option:`CONFIG_GLIBCXX_LIBCPP` in the application
|
|
configuration file.
|
|
|
|
The following C++ standard libraries are supported by Zephyr:
|
|
|
|
* GNU C++ Library (:kconfig:option:`CONFIG_GLIBCXX_LIBCPP`)
|
|
* ARC MetaWare C++ Library (:kconfig:option:`CONFIG_ARCMWDT_LIBCPP`)
|
|
|
|
A Zephyr subsystem that requires the features from the full C++ standard
|
|
library can select, from its config,
|
|
:kconfig:option:`CONFIG_REQUIRES_FULL_LIBCPP`, which automatically selects a
|
|
compatible C++ standard library unless the Kconfig symbol for a specific C++
|
|
standard library is selected.
|
|
|
|
Header files and incompatibilities between C and C++
|
|
****************************************************
|
|
|
|
To interact with each other, C and C++ must share code through header
|
|
files: data structures, macros, static functions,... While C and C++
|
|
have a large overlap, they're different languages with `known
|
|
incompatibilities`_. C is not just a C++ subset. Standard levels (e.g.:
|
|
"C+11") add another level of complexity as new features are often
|
|
inspired by and copied from the other language but many years later and
|
|
with subtle differences. Making things more complex, compilers often
|
|
offer early prototypes of features before they become
|
|
standardized. Standards can have ambiguities interpreted differently by
|
|
different compilers. Compilers can have bugs and these may need
|
|
workarounds. To help with this, many projects restrict themselves to a
|
|
limited number of toolchains. Zephyr does not.
|
|
|
|
These compatibility issues affect header files dis-proportionally. Not
|
|
just because they have to be compatible between C and C++, but also
|
|
because they end up being compiled in a surprisingly high number of other
|
|
source files due to *indirect* inclusion and the `lack of structure and
|
|
headers organization`_ that is typical in real-world projects. So, header
|
|
files are exposed to a much larger variety of toolchains and project
|
|
configurations.
|
|
Adding more constraints, the Zephyr project has demanding policies
|
|
with respect to code style, compiler warnings, static analyzers and
|
|
standard compliance (e.g.: MISRA).
|
|
|
|
Put together, all these constraints can make writing header files very
|
|
challenging. The purpose of this section is to document some best "header
|
|
practices" and lessons learned in a Zephyr-specific context. While a lot
|
|
of the information here is not Zephyr-specific, this section is not a
|
|
substitute for knowledge of C/C++ standards, textbooks and other
|
|
references.
|
|
|
|
Testing
|
|
-------
|
|
|
|
Fortunately, the Zephyr project has an extensive test and CI
|
|
infrastructure that provides coverage baselines, catches issues early,
|
|
enforces policies and maintains such combinatorial explosions under some
|
|
control. The ``tests/lib/cpp/cxx/`` are very useful in this context
|
|
because their ``testcase.yaml`` configuration lets ``twister`` iterate
|
|
quickly over a range of ``-std`` parameters: ``-std=c++98``,
|
|
``-std=c++11``, etc.
|
|
|
|
Keep in mind unused macros are not compiled.
|
|
|
|
Designated initializers
|
|
-----------------------
|
|
|
|
Initialization macros are common in header files as they help reduce
|
|
boilerplate code. C99 added initialization of ``struct`` and ``union``
|
|
types by "designated" member names instead of a list of *bare*
|
|
expressions. Some GCC versions support designated initializers even in
|
|
their C90 mode.
|
|
|
|
When used at a simple level, designated initializers are less
|
|
error-prone, more readable and more flexible. On the other hand, C99
|
|
allowed a surprisingly large and lax set of possibilities: designated
|
|
initializers can be out of order, duplicated, "nested" (``.a.x =``),
|
|
various other braces can be omitted, designated initializers and not can
|
|
be mixed, etc.
|
|
|
|
Twenty years later, C++20 added designated initializers to C++ but in
|
|
much more restricted way; partly because a C++ ``struct`` is actually a
|
|
``class``. As described in the C++ proposal number P0329 (which compares
|
|
with C) or in any complete C++ reference, a mix is not allowed and
|
|
initializers must be in order (gaps are allowed).
|
|
|
|
Interestingly, the new restrictions in C++20 can cause ``gcc -std=c++20``
|
|
to fail to compile code that successfully compiles with
|
|
``gcc -std=c++17``. For example, ``gcc -std=c++17`` and older allow the
|
|
C-style mix of initializers and bare expressions. This fails to compile
|
|
with using ``gcc -std=c++20`` *with the same GCC version*.
|
|
|
|
Recommendation: to maximize compatibility across different C and C++
|
|
toolchains and standards, designated initializers in Zephyr header files
|
|
should follow all C++20 rules and restrictions. Non-designated, pre-C99
|
|
initialization offers more compatibility and is also allowed but
|
|
designated initialization is the more readable and preferred code
|
|
style. In any case, both styles must never be mixed in the same
|
|
initializer.
|
|
|
|
Warning: successful compilation is not the end of the incompatibility
|
|
story. For instance, the *evaluation order* of initializer expressions is
|
|
unspecified in C99! It is the (expected) left-to-right order in
|
|
C++20. Other standard revisions may vary. In doubt, do not rely on
|
|
evaluation order (here and elsewhere).
|
|
|
|
Anonymous unions
|
|
----------------
|
|
|
|
Anonymous unions (a.k.a. "unnamed" unions) seem to have been part of C++
|
|
from its very beginning. They were not officially added to C until C11.
|
|
As usual, there are differences between C and C++. For instance, C
|
|
supports anonymous unions only as a member of an enclosing ``struct`` or
|
|
``union``, empty lists ``{ }`` have always been allowed in C++ but they
|
|
require C23, etc.
|
|
|
|
When initializing anonymous members, the expression can be enclosed in
|
|
braces or not. It can be either designated or bare. For maximum
|
|
portability, when initializing *anonymous unions*:
|
|
|
|
- Do *not* enclose *designated* initializers with braces. This is
|
|
required by C++20 and above which perceive such braces as mixing bare
|
|
expressions with (other) designated initializers and fails to compile.
|
|
|
|
- Do enclose *bare* expressions with braces. This is required by C.
|
|
Maybe because C is laxer and allows many initialization possibilities
|
|
and variations, so it may need such braces to disambiguate? Note C
|
|
does allow omitting most braces in initializer expressions - but not
|
|
in this particular case of initializing anonymous unions with bare
|
|
expressions.
|
|
|
|
Some pre-C11 GCC versions support some form of anonymous unions. They
|
|
unfortunately require enclosing their designated initializers with
|
|
braces which conflicts with this recommendation. This can be solved
|
|
with an ``#ifdef __STDC_VERSION__`` as demonstrated in Zephyr commit
|
|
`c15f029a7108
|
|
<https://github.com/zephyrproject-rtos/zephyr/commit/c15f029a7108>`_ and
|
|
the corresponding code review.
|
|
|
|
|
|
.. _`C++ Standard Library`: https://en.wikipedia.org/wiki/C%2B%2B_Standard_Library
|
|
.. _`Standard Template Library (STL)`: https://en.wikipedia.org/wiki/Standard_Template_Library
|
|
.. _`known incompatibilities`: https://en.wikipedia.org/wiki/Compatibility_of_C_and_C%2B%2B
|
|
.. _`lack of structure and headers organization`:
|
|
https://github.com/zephyrproject-rtos/zephyr/issues/41543
|
|
.. _`gcc commit [C++ PATCH] P0329R4: Designated Initialization`:
|
|
https://gcc.gnu.org/pipermail/gcc-patches/2017-November/487584.html
|