From 89da9421f60a024875574ea493c59106cdc63622 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Nov 2025 09:13:06 +0000 Subject: [PATCH 1/8] Initial plan From 49ee1f79205e194d7e1d284cce098aaeb5e68c57 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Nov 2025 09:18:34 +0000 Subject: [PATCH 2/8] Add API conventions documentation and update design guidelines Co-authored-by: kartben <128251+kartben@users.noreply.github.com> --- doc/develop/api/api_conventions.rst | 102 +++++++++++++++++++ doc/develop/api/design_guidelines.rst | 139 ++++++++++++-------------- doc/develop/api/index.rst | 1 + doc/glossary.rst | 5 +- 4 files changed, 169 insertions(+), 78 deletions(-) create mode 100644 doc/develop/api/api_conventions.rst diff --git a/doc/develop/api/api_conventions.rst b/doc/develop/api/api_conventions.rst new file mode 100644 index 0000000000000..a2cf4603b767a --- /dev/null +++ b/doc/develop/api/api_conventions.rst @@ -0,0 +1,102 @@ +.. _api_conventions.rst: + +API Conventions +############### + +Zephyr provides a few programming interfaces that users can use for creating their applications. +Zephyr's API space includes the following areas: + +- C programming interface (function prototypes, structures, and macros), provided in C header files +- Configuration system (Kconfig) +- Hardware description system (Devicetree) + +Other areas, such as the build system (CMake), may also be seen as Zephyr's API. However, any area +that is not explicitly listed herein is not considered Zephyr's API as of today. + +API classification +****************** +The files that define the Zephyr APIs may contain symbols intended for different usage. The intended +API usage is designated by the API class. Zephyr APIs are classified as: + +Private + These APIs are intended for use within the boundary of a :term:`software component`. Private APIs + defined in the main Zephyr tree are not subject to :ref:`api_lifecycle`. Therefore, they can be changed or + removed at any time. Changes to the private APIs may not be documented at all, and are not included in the + migration guide. + +Internal + In general, these APIs are intended for use only between certain software components that are + located in the main Zephyr tree. The context where the API is called or implemented is well defined. For + example, functions prefixed with `arch_` are intended for use by the Zephyr kernel to invoke + architecture-specific code. An API is classified as internal on a case by case basis. + Internal APIs should not be used by out-of-tree code. Internal APIs are not subject + to :ref:`api_lifecycle`. Therefore, can be changed or removed at any time. However, changes to the + internal APIs must be documented in the migration guide. + +Public + These APIs intended for use from any :term:`software component`. Public APIs may be used in-tree + and out-of-tree. Public APIs are subject to the :ref:`api_lifecycle`. Therefore, changes to an + API are introduced and documented according to the rules defined for the API life cycle. This includes + documenting any breaking changes in the migration guide. + +Note, that only APIs defined in the main Zephyr tree are subject to :ref:`api_lifecycle`. External projects +used as :ref:`modules` may define their own rules for API lifecycle. + +Zephyr is a constantly evolving project and API classification may change over time. A Private or +Internal API may be promoted to Internal or Public API, respectively. Zephyr users are encouraged to +follow :ref:`rfcs` process to recommend changes in API classification. + +The following sections provide guidelines on how to identify the class of an API depending on its +type. + +Header files contents +===================== +Private + Functions and data types declared in header files located in + :zephyr_file:`include/zephyr/private/`. In addition, private symbols are prefixed with ``z_``. + Due to historical reasons some APIs prefixed with ``z_`` are public. + +Internal + Functions and data types declared :zephyr_file:`include/zephyr/internal`. In addition, Internal + APIs must use ``@internal`` doxygen command. + +Public + Functions and data types declared in header files located in :zephyr_file:`include/zephyr/`. + +In addition, the following prefixes are reserved by Zephyr kernel for use in Zephyr Public APIs: + +.. list-table:: Prefixes and Descriptions + :header-rows: 1 + :widths: 10 40 40 + :stub-columns: 1 + + * - Prefix + - Description + - Example + * - ``atomic_`` + - Denotes an atomic operation. + - :c:func:`atomic_inc` + * - ``device_`` + - Denotes an API relating to devices and their initialization. + - :c:func:`device_get_binding` + * - ``irq_`` + - Denotes an IRQ management operation. + - :c:func:`irq_disable` + * - ``k_`` + - Kernel-specific function. + - :c:func:`k_malloc` + * - ``sys_`` + - Catch-all for APIs that do not fit into the other namespaces. + - :c:func:`sys_write32` + +Kconfig symbols +=============== +All Kconfig symbols are Public. The :ref:`api_lifecycle` of a Kconfig symbol is defined by the +:ref:`api_lifecycle` of a :term:`software component` to which the binding belongs. For example, +Kconfig symbols defined for regulators follow the lifecycle of the :ref:`regulator_api`. + +Devicetree bindings +=================== +Device tree bindings and their content are Public. The :ref:`api_lifecycle` of a binding is defined +by the :ref:`api_lifecycle` of a :term:`software component` to which the binding belongs. For +example, bindings defined for regulators follow the lifecycle of the :ref:`regulator_api`. diff --git a/doc/develop/api/design_guidelines.rst b/doc/develop/api/design_guidelines.rst index 1dfeda4c45fc2..2e621e5946c7b 100644 --- a/doc/develop/api/design_guidelines.rst +++ b/doc/develop/api/design_guidelines.rst @@ -3,55 +3,47 @@ API Design Guidelines ##################### -Zephyr development and evolution is a group effort, and to simplify -maintenance and enhancements there are some general policies that should -be followed when developing a new capability or interface. +Zephyr development and evolution is a group effort, and to simplify maintenance and enhancements +there are some general policies that should be followed when developing a new capability or +interface. Using Callbacks *************** -Many APIs involve passing a callback as a parameter or as a member of a -configuration structure. The following policies should be followed when -specifying the signature of a callback: +Many APIs involve passing a callback as a parameter or as a member of a configuration structure. +The following policies should be followed when specifying the signature of a callback: -* The first parameter should be a pointer to the object most closely - associated with the callback. In the case of device drivers this - would be ``const struct device *dev``. For library functions it may be a - pointer to another object that was referenced when the callback was - provided. +* The first parameter should be a pointer to the object most closely associated with the callback. + In the case of device drivers this would be ``const struct device *dev``. For library functions + it may be a pointer to another object that was referenced when the callback was provided. -* The next parameter(s) should be additional information specific to the - callback invocation, such as a channel identifier, new status value, - and/or a message pointer followed by the message length. +* The next parameter(s) should be additional information specific to the callback invocation, such + as a channel identifier, new status value, and/or a message pointer followed by the message + length. -* The final parameter should be a ``void *user_data`` pointer carrying - context that allows a shared callback function to locate additional - material necessary to process the callback. +* The final parameter should be a ``void *user_data`` pointer carrying context that allows a shared + callback function to locate additional material necessary to process the callback. -An exception to providing ``user_data`` as the last parameter may be -allowed when the callback itself was provided through a structure that -will be embedded in another structure. An example of such a case is -:c:struct:`gpio_callback`, normally defined within a data structure -specific to the code that also defines the callback function. In those -cases further context can accessed by the callback indirectly by -:c:macro:`CONTAINER_OF`. +An exception to providing ``user_data`` as the last parameter may be allowed when the callback +itself was provided through a structure that will be embedded in another structure. An example of +such a case is :c:type:`gpio_callback`, normally defined within a data structure specific to the +code that also defines the callback function. In those cases further context can accessed by the +callback indirectly by :c:macro:`CONTAINER_OF`. Examples ======== -* The requirements of :c:type:`k_timer_expiry_t` invoked when a system - timer alarm fires are satisfied by:: +* The requirements of :c:type:`k_timer_expiry_t` invoked when a system timer alarm fires are + satisfied by:: void handle_timeout(struct k_timer *timer) { ... } - The assumption here, as with :c:struct:`gpio_callback`, is that the - timer is embedded in a structure reachable from - :c:macro:`CONTAINER_OF` that can provide additional context to the - callback. + The assumption here, as with :c:type:`gpio_callback`, is that the timer is embedded in a structure + reachable from :c:macro:`CONTAINER_OF` that can provide additional context to the callback. -* The requirements of :c:type:`counter_alarm_callback_t` invoked when a - counter device alarm fires are satisfied by:: +* The requirements of :c:type:`counter_alarm_callback_t` invoked when a counter device alarm fires + are satisfied by:: void handle_alarm(const struct device *dev, uint8_t chan_id, @@ -59,64 +51,61 @@ Examples void *user_data) { ... } - This provides more complete useful information, including which - counter channel timed-out and the counter value at which the timeout - occurred, as well as user context which may or may not be the - :c:struct:`counter_alarm_cfg` used to register the callback, depending - on user needs. + This provides more complete useful information, including which counter channel timed-out and the + counter value at which the timeout occurred, as well as user context which may or may not be the + :c:type:`counter_alarm_cfg` used to register the callback, depending on user needs. Conditional Data and APIs ************************* -APIs and libraries may provide features that are expensive in RAM or -code size but are optional in the sense that some applications can be -implemented without them. Examples of such feature include -:kconfig:option:`capturing a timestamp ` or -:kconfig:option:`providing an alternative interface `. The -developer in coordination with the community must determine whether -enabling the features is to be controllable through a Kconfig option. +APIs and libraries may provide features that are expensive in RAM or code size but are optional in +the sense that some applications can be implemented without them. Examples of such feature include +:kconfig:option:`capturing a timestamp ` or :kconfig:option:`providing an +alternative interface `. The developer in coordination with the community must +determine whether enabling the features is to be controllable through a Kconfig option. -In the case where a feature is determined to be optional the following -practices should be followed. +In the case where a feature is determined to be optional the following practices should be followed. -* Any data that is accessed only when the feature is enabled should be - conditionally included via ``#ifdef CONFIG_MYFEATURE`` in the - structure or union declaration. This reduces memory use for +* Any data that is accessed only when the feature is enabled should be conditionally included via + ``#ifdef CONFIG_MYFEATURE`` in the structure or union declaration. This reduces memory use for applications that don't need the capability. -* Function declarations that are available only when the option is - enabled should be provided unconditionally. Add a note in the - description that the function is available only when the specified - feature is enabled, referencing the required Kconfig symbol by name. - In the cases where the function is used but not enabled the definition - of the function shall be excluded from compilation, so references to - the unsupported API will result in a link-time error. -* Where code specific to the feature is isolated in a source file that - has no other content that file should be conditionally included in - ``CMakeLists.txt``:: +* Function declarations that are available only when the option is enabled should be provided + unconditionally. Add a note in the description that the function is available only when the + specified feature is enabled, referencing the required Kconfig symbol by name. In the cases where + the function is used but not enabled the definition of the function shall be excluded from + compilation, so references to the unsupported API will result in a link-time error. +* Where code specific to the feature is isolated in a source file that has no other content that + file should be conditionally included in ``CMakeLists.txt``:: zephyr_sources_ifdef(CONFIG_MYFEATURE foo_funcs.c) -* Where code specific to the feature is part of a source file that has - other content the feature-specific code should be conditionally - processed using ``#ifdef CONFIG_MYFEATURE``. +* Where code specific to the feature is part of a source file that has other content the + feature-specific code should be conditionally processed using ``#ifdef CONFIG_MYFEATURE``. -The Kconfig flag used to enable the feature should be added to the -``PREDEFINED`` variable in :file:`doc/zephyr.doxyfile.in` to ensure the -conditional API and functions appear in generated documentation. +The Kconfig flag used to enable the feature should be added to the ``PREDEFINED`` variable in +:file:`doc/zephyr.doxyfile.in` to ensure the conditional API and functions appear in generated +documentation. + +Subsystem namespaces +******************** +A subsystem can define its own naming conventions for symbols as long as the scheme doesn't collide +with Zephyr naming conventions :ref:`api_conventions.rst`. The naming convention should include a +namespace prefix (for example, bt\_ for Bluetooth LE, or net\_ for IP). This limits possible +collisions with symbols defined by an application. Return Codes ************ +Zephyr uses the standard codes in ``errno.h`` for all APIs. As a general rule, 0 indicates success; +a negative ``errno.h`` code indicates an error condition. -Implementations of an API, for example an API for accessing a peripheral might -implement only a subset of the functions that is required for minimal operation. -A distinction is needed between APIs that are not supported and those that are -not implemented or optional: +Implementations of an API, for example an API for accessing a peripheral might implement only a +subset of the functions that is required for minimal operation. A distinction is needed between APIs +that are not supported and those that are not implemented or optional: - APIs that are supported but not implemented shall return ``-ENOSYS``. -- Optional APIs that are not supported by the hardware should be implemented and - the return code in this case shall be ``-ENOTSUP``. +- Optional APIs that are not supported by the hardware should be implemented and the return code in + this case shall be ``-ENOTSUP``. -- When an API is implemented, but the particular combination of options - requested in the call cannot be satisfied by the implementation the call shall - return ``-ENOTSUP``. (For example, a request for a level-triggered GPIO interrupt on - hardware that supports only edge-triggered interrupts) +- When an API is implemented but the particular combination of options requested in the call cannot + be satisfied by the implementation, the call shall return ``-ENOTSUP``. (For example, a request + for a level-triggered GPIO interrupt on hardware that supports only edge-triggered interrupts) diff --git a/doc/develop/api/index.rst b/doc/develop/api/index.rst index d22cc1f1b31b2..6ec28e4ff8562 100644 --- a/doc/develop/api/index.rst +++ b/doc/develop/api/index.rst @@ -7,6 +7,7 @@ API Status and Guidelines :maxdepth: 1 overview.rst + api_conventions.rst api_lifecycle.rst design_guidelines.rst terminology.rst diff --git a/doc/glossary.rst b/doc/glossary.rst index c21bc98e54315..cd487603f687e 100644 --- a/doc/glossary.rst +++ b/doc/glossary.rst @@ -169,9 +169,8 @@ Glossary of Terms features, and that the vendor typically names and markets together. software component - A software component is a self-contained, modular, and replaceable part of - the Zephyr source code. A driver, a subsystem or an applications are all - examples of software components present in Zephyr. + A software component is a self-contained, modular, and replaceable part of the Zephyr source + code. A driver or subsystem is an example of a software component present in Zephyr. subsystem A subsystem refers to a logically distinct part of the operating system From 45db5c8716c5a8b3f8165016701093c67703abea Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Nov 2025 09:21:38 +0000 Subject: [PATCH 3/8] Fix RST label and reference syntax Co-authored-by: kartben <128251+kartben@users.noreply.github.com> --- doc/develop/api/api_conventions.rst | 2 +- doc/develop/api/design_guidelines.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/develop/api/api_conventions.rst b/doc/develop/api/api_conventions.rst index a2cf4603b767a..5b2c912aa3fb7 100644 --- a/doc/develop/api/api_conventions.rst +++ b/doc/develop/api/api_conventions.rst @@ -1,4 +1,4 @@ -.. _api_conventions.rst: +.. _api_conventions: API Conventions ############### diff --git a/doc/develop/api/design_guidelines.rst b/doc/develop/api/design_guidelines.rst index 2e621e5946c7b..d9c261d56a6c5 100644 --- a/doc/develop/api/design_guidelines.rst +++ b/doc/develop/api/design_guidelines.rst @@ -88,7 +88,7 @@ documentation. Subsystem namespaces ******************** A subsystem can define its own naming conventions for symbols as long as the scheme doesn't collide -with Zephyr naming conventions :ref:`api_conventions.rst`. The naming convention should include a +with Zephyr naming conventions :ref:`api_conventions`. The naming convention should include a namespace prefix (for example, bt\_ for Bluetooth LE, or net\_ for IP). This limits possible collisions with symbols defined by an application. From 6daf2e54775e6b06fec448b6381244b719a7e236 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Nov 2025 09:22:36 +0000 Subject: [PATCH 4/8] Fix grammar issues in API conventions documentation Co-authored-by: kartben <128251+kartben@users.noreply.github.com> --- doc/develop/api/api_conventions.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/develop/api/api_conventions.rst b/doc/develop/api/api_conventions.rst index 5b2c912aa3fb7..bd0d93fb1f619 100644 --- a/doc/develop/api/api_conventions.rst +++ b/doc/develop/api/api_conventions.rst @@ -30,7 +30,7 @@ Internal example, functions prefixed with `arch_` are intended for use by the Zephyr kernel to invoke architecture-specific code. An API is classified as internal on a case by case basis. Internal APIs should not be used by out-of-tree code. Internal APIs are not subject - to :ref:`api_lifecycle`. Therefore, can be changed or removed at any time. However, changes to the + to :ref:`api_lifecycle`. Therefore, they can be changed or removed at any time. However, changes to the internal APIs must be documented in the migration guide. Public @@ -57,7 +57,7 @@ Private Due to historical reasons some APIs prefixed with ``z_`` are public. Internal - Functions and data types declared :zephyr_file:`include/zephyr/internal`. In addition, Internal + Functions and data types declared in :zephyr_file:`include/zephyr/internal`. In addition, Internal APIs must use ``@internal`` doxygen command. Public From 7feebed535faca1024acb0d2e2007bcaa1baac71 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Nov 2025 09:54:18 +0000 Subject: [PATCH 5/8] Remove formatting-only changes and add comprehensive breaking change examples Co-authored-by: kartben <128251+kartben@users.noreply.github.com> --- doc/develop/api/api_conventions.rst | 133 ++++++++++++++++++++++++++ doc/develop/api/design_guidelines.rst | 132 ++++++++++++++----------- 2 files changed, 210 insertions(+), 55 deletions(-) diff --git a/doc/develop/api/api_conventions.rst b/doc/develop/api/api_conventions.rst index bd0d93fb1f619..f9d8790b96ee7 100644 --- a/doc/develop/api/api_conventions.rst +++ b/doc/develop/api/api_conventions.rst @@ -100,3 +100,136 @@ Devicetree bindings Device tree bindings and their content are Public. The :ref:`api_lifecycle` of a binding is defined by the :ref:`api_lifecycle` of a :term:`software component` to which the binding belongs. For example, bindings defined for regulators follow the lifecycle of the :ref:`regulator_api`. + +Breaking and non-breaking changes +********************************** + +This section provides guidance on what constitutes a breaking change versus a non-breaking change +for each API type. Understanding these distinctions helps developers maintain API stability and +properly document changes in migration guides. + +C API breaking changes +======================= + +The following changes to Public or Internal C APIs are considered **breaking changes**: + +**Function signatures:** + +- Removing a public function +- Renaming a public function +- Changing the return type of a function +- Adding, removing, or reordering function parameters +- Changing parameter types in a way that is not backwards compatible +- Changing a function from inline to non-inline (or vice versa) +- Removing or changing function attributes (e.g., ``__deprecated``, ``__weak``) + +**Data types and structures:** + +- Removing a public structure, union, or enum +- Renaming a public structure, union, or enum +- Removing, renaming, or reordering fields in a structure or union +- Changing the type of a structure or union field +- Changing the size of a structure or union (except when adding fields at the end with explicit versioning) +- Removing or renaming enum values +- Changing the numeric value of an enum constant + +**Macros and constants:** + +- Removing a public macro +- Renaming a public macro +- Changing the value of a constant macro in a way that affects behavior +- Changing a function-like macro in a way that is not backwards compatible + +**Behavioral changes:** + +- Changing the semantics or behavior of a function in a way that breaks existing usage +- Changing error codes returned by a function +- Changing the threading or interrupt context requirements for a function + +C API non-breaking changes +=========================== + +The following changes to Public or Internal C APIs are generally **non-breaking changes**: + +- Adding new functions with unique names +- Adding new structures, unions, or enums with unique names +- Adding new enum values (at the end of the enum, without changing existing values) +- Adding fields at the end of a structure when using explicit versioning or size fields +- Adding new macros with unique names +- Deprecating (but not removing) functions, types, or macros using ``__deprecated`` +- Adding function attributes that don't change the ABI (e.g., ``__unused``, documentation) +- Changing internal implementation details without affecting the API contract +- Improving documentation or comments +- Adding optional parameters via variadic functions or configuration structures with size/version fields + +Kconfig breaking changes +========================= + +The following changes to Kconfig symbols are considered **breaking changes**: + +- Removing a Kconfig symbol +- Renaming a Kconfig symbol +- Changing the type of a Kconfig symbol (e.g., from bool to int) +- Removing a Kconfig symbol's default value without providing a migration path +- Changing the dependency tree in a way that makes previously valid configurations invalid +- Changing the semantics of what a Kconfig symbol controls + +Kconfig non-breaking changes +============================= + +The following changes to Kconfig symbols are generally **non-breaking changes**: + +- Adding new Kconfig symbols +- Adding new dependencies to an existing symbol (if it doesn't break existing configurations) +- Changing the help text or prompt +- Changing the default value in a way that maintains backwards compatibility +- Adding ranges or choices that include previously valid values +- Deprecating a Kconfig symbol (with migration path to new symbol) + +Devicetree breaking changes +============================ + +The following changes to Devicetree bindings are considered **breaking changes**: + +- Removing a binding file +- Removing a required property from a binding +- Renaming a required property in a binding +- Changing the type of a property in a binding +- Removing or changing the meaning of a cell in a phandle-array or phandle property +- Making a previously optional property required without providing a default value +- Removing support for a compatible string + +Devicetree non-breaking changes +================================ + +The following changes to Devicetree bindings are generally **non-breaking changes**: + +- Adding new binding files +- Adding new optional properties to a binding +- Adding new compatible strings +- Adding default values for properties +- Making a previously required property optional +- Deprecating a property (while maintaining support for it) +- Changing or improving property descriptions +- Adding new cells to phandle-arrays when properly versioned + +API lifecycle considerations +============================= + +The impact of a breaking change depends on the API classification: + +**Private APIs:** + Breaking changes are allowed at any time without documentation. Since these APIs are internal + to a software component, changes are expected and applications should not depend on them. + +**Internal APIs:** + Breaking changes are allowed but must be documented in the migration guide. This helps + maintainers of other Zephyr components update their code accordingly. + +**Public APIs:** + Breaking changes must follow the :ref:`api_lifecycle`. This typically means: + + - **Experimental APIs**: Can have breaking changes, but should be documented + - **Unstable APIs**: Can have breaking changes, but must be documented in migration guide + - **Stable APIs**: Breaking changes should be avoided. If absolutely necessary, must go through + deprecation period and be thoroughly documented diff --git a/doc/develop/api/design_guidelines.rst b/doc/develop/api/design_guidelines.rst index d9c261d56a6c5..1f5a234952f2b 100644 --- a/doc/develop/api/design_guidelines.rst +++ b/doc/develop/api/design_guidelines.rst @@ -3,47 +3,55 @@ API Design Guidelines ##################### -Zephyr development and evolution is a group effort, and to simplify maintenance and enhancements -there are some general policies that should be followed when developing a new capability or -interface. +Zephyr development and evolution is a group effort, and to simplify +maintenance and enhancements there are some general policies that should +be followed when developing a new capability or interface. Using Callbacks *************** -Many APIs involve passing a callback as a parameter or as a member of a configuration structure. -The following policies should be followed when specifying the signature of a callback: +Many APIs involve passing a callback as a parameter or as a member of a +configuration structure. The following policies should be followed when +specifying the signature of a callback: -* The first parameter should be a pointer to the object most closely associated with the callback. - In the case of device drivers this would be ``const struct device *dev``. For library functions - it may be a pointer to another object that was referenced when the callback was provided. +* The first parameter should be a pointer to the object most closely + associated with the callback. In the case of device drivers this + would be ``const struct device *dev``. For library functions it may be a + pointer to another object that was referenced when the callback was + provided. -* The next parameter(s) should be additional information specific to the callback invocation, such - as a channel identifier, new status value, and/or a message pointer followed by the message - length. +* The next parameter(s) should be additional information specific to the + callback invocation, such as a channel identifier, new status value, + and/or a message pointer followed by the message length. -* The final parameter should be a ``void *user_data`` pointer carrying context that allows a shared - callback function to locate additional material necessary to process the callback. +* The final parameter should be a ``void *user_data`` pointer carrying + context that allows a shared callback function to locate additional + material necessary to process the callback. -An exception to providing ``user_data`` as the last parameter may be allowed when the callback -itself was provided through a structure that will be embedded in another structure. An example of -such a case is :c:type:`gpio_callback`, normally defined within a data structure specific to the -code that also defines the callback function. In those cases further context can accessed by the -callback indirectly by :c:macro:`CONTAINER_OF`. +An exception to providing ``user_data`` as the last parameter may be +allowed when the callback itself was provided through a structure that +will be embedded in another structure. An example of such a case is +:c:type:`gpio_callback`, normally defined within a data structure +specific to the code that also defines the callback function. In those +cases further context can accessed by the callback indirectly by +:c:macro:`CONTAINER_OF`. Examples ======== -* The requirements of :c:type:`k_timer_expiry_t` invoked when a system timer alarm fires are - satisfied by:: +* The requirements of :c:type:`k_timer_expiry_t` invoked when a system + timer alarm fires are satisfied by:: void handle_timeout(struct k_timer *timer) { ... } - The assumption here, as with :c:type:`gpio_callback`, is that the timer is embedded in a structure - reachable from :c:macro:`CONTAINER_OF` that can provide additional context to the callback. + The assumption here, as with :c:type:`gpio_callback`, is that the + timer is embedded in a structure reachable from + :c:macro:`CONTAINER_OF` that can provide additional context to the + callback. -* The requirements of :c:type:`counter_alarm_callback_t` invoked when a counter device alarm fires - are satisfied by:: +* The requirements of :c:type:`counter_alarm_callback_t` invoked when a + counter device alarm fires are satisfied by:: void handle_alarm(const struct device *dev, uint8_t chan_id, @@ -51,42 +59,53 @@ Examples void *user_data) { ... } - This provides more complete useful information, including which counter channel timed-out and the - counter value at which the timeout occurred, as well as user context which may or may not be the - :c:type:`counter_alarm_cfg` used to register the callback, depending on user needs. + This provides more complete useful information, including which + counter channel timed-out and the counter value at which the timeout + occurred, as well as user context which may or may not be the + :c:type:`counter_alarm_cfg` used to register the callback, depending + on user needs. Conditional Data and APIs ************************* -APIs and libraries may provide features that are expensive in RAM or code size but are optional in -the sense that some applications can be implemented without them. Examples of such feature include -:kconfig:option:`capturing a timestamp ` or :kconfig:option:`providing an -alternative interface `. The developer in coordination with the community must -determine whether enabling the features is to be controllable through a Kconfig option. +APIs and libraries may provide features that are expensive in RAM or +code size but are optional in the sense that some applications can be +implemented without them. Examples of such feature include +:kconfig:option:`capturing a timestamp ` or +:kconfig:option:`providing an alternative interface `. The +developer in coordination with the community must determine whether +enabling the features is to be controllable through a Kconfig option. -In the case where a feature is determined to be optional the following practices should be followed. +In the case where a feature is determined to be optional the following +practices should be followed. -* Any data that is accessed only when the feature is enabled should be conditionally included via - ``#ifdef CONFIG_MYFEATURE`` in the structure or union declaration. This reduces memory use for +* Any data that is accessed only when the feature is enabled should be + conditionally included via ``#ifdef CONFIG_MYFEATURE`` in the + structure or union declaration. This reduces memory use for applications that don't need the capability. -* Function declarations that are available only when the option is enabled should be provided - unconditionally. Add a note in the description that the function is available only when the - specified feature is enabled, referencing the required Kconfig symbol by name. In the cases where - the function is used but not enabled the definition of the function shall be excluded from - compilation, so references to the unsupported API will result in a link-time error. -* Where code specific to the feature is isolated in a source file that has no other content that - file should be conditionally included in ``CMakeLists.txt``:: +* Function declarations that are available only when the option is + enabled should be provided unconditionally. Add a note in the + description that the function is available only when the specified + feature is enabled, referencing the required Kconfig symbol by name. + In the cases where the function is used but not enabled the definition + of the function shall be excluded from compilation, so references to + the unsupported API will result in a link-time error. +* Where code specific to the feature is isolated in a source file that + has no other content that file should be conditionally included in + ``CMakeLists.txt``:: zephyr_sources_ifdef(CONFIG_MYFEATURE foo_funcs.c) -* Where code specific to the feature is part of a source file that has other content the - feature-specific code should be conditionally processed using ``#ifdef CONFIG_MYFEATURE``. +* Where code specific to the feature is part of a source file that has + other content the feature-specific code should be conditionally + processed using ``#ifdef CONFIG_MYFEATURE``. -The Kconfig flag used to enable the feature should be added to the ``PREDEFINED`` variable in -:file:`doc/zephyr.doxyfile.in` to ensure the conditional API and functions appear in generated -documentation. +The Kconfig flag used to enable the feature should be added to the +``PREDEFINED`` variable in :file:`doc/zephyr.doxyfile.in` to ensure the +conditional API and functions appear in generated documentation. Subsystem namespaces ******************** + A subsystem can define its own naming conventions for symbols as long as the scheme doesn't collide with Zephyr naming conventions :ref:`api_conventions`. The naming convention should include a namespace prefix (for example, bt\_ for Bluetooth LE, or net\_ for IP). This limits possible @@ -94,18 +113,21 @@ collisions with symbols defined by an application. Return Codes ************ + Zephyr uses the standard codes in ``errno.h`` for all APIs. As a general rule, 0 indicates success; a negative ``errno.h`` code indicates an error condition. -Implementations of an API, for example an API for accessing a peripheral might implement only a -subset of the functions that is required for minimal operation. A distinction is needed between APIs -that are not supported and those that are not implemented or optional: +Implementations of an API, for example an API for accessing a peripheral might +implement only a subset of the functions that is required for minimal operation. +A distinction is needed between APIs that are not supported and those that are +not implemented or optional: - APIs that are supported but not implemented shall return ``-ENOSYS``. -- Optional APIs that are not supported by the hardware should be implemented and the return code in - this case shall be ``-ENOTSUP``. +- Optional APIs that are not supported by the hardware should be implemented and + the return code in this case shall be ``-ENOTSUP``. -- When an API is implemented but the particular combination of options requested in the call cannot - be satisfied by the implementation, the call shall return ``-ENOTSUP``. (For example, a request - for a level-triggered GPIO interrupt on hardware that supports only edge-triggered interrupts) +- When an API is implemented, but the particular combination of options + requested in the call cannot be satisfied by the implementation the call shall + return ``-ENOTSUP``. (For example, a request for a level-triggered GPIO interrupt on + hardware that supports only edge-triggered interrupts) From 5d78d68fae24bc7d3bd74269818a34ad1c9b51de Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Nov 2025 10:19:09 +0000 Subject: [PATCH 6/8] Make breaking/non-breaking changes more concise with table format Co-authored-by: kartben <128251+kartben@users.noreply.github.com> --- doc/develop/api/api_conventions.rst | 208 +++++++++++----------------- 1 file changed, 80 insertions(+), 128 deletions(-) diff --git a/doc/develop/api/api_conventions.rst b/doc/develop/api/api_conventions.rst index f9d8790b96ee7..b8d1e78d1e5a4 100644 --- a/doc/develop/api/api_conventions.rst +++ b/doc/develop/api/api_conventions.rst @@ -104,132 +104,84 @@ example, bindings defined for regulators follow the lifecycle of the :ref:`regul Breaking and non-breaking changes ********************************** -This section provides guidance on what constitutes a breaking change versus a non-breaking change -for each API type. Understanding these distinctions helps developers maintain API stability and -properly document changes in migration guides. - -C API breaking changes -======================= - -The following changes to Public or Internal C APIs are considered **breaking changes**: - -**Function signatures:** - -- Removing a public function -- Renaming a public function -- Changing the return type of a function -- Adding, removing, or reordering function parameters -- Changing parameter types in a way that is not backwards compatible -- Changing a function from inline to non-inline (or vice versa) -- Removing or changing function attributes (e.g., ``__deprecated``, ``__weak``) +This section categorizes common changes as breaking or non-breaking for each API type. -**Data types and structures:** - -- Removing a public structure, union, or enum -- Renaming a public structure, union, or enum -- Removing, renaming, or reordering fields in a structure or union -- Changing the type of a structure or union field -- Changing the size of a structure or union (except when adding fields at the end with explicit versioning) -- Removing or renaming enum values -- Changing the numeric value of an enum constant - -**Macros and constants:** - -- Removing a public macro -- Renaming a public macro -- Changing the value of a constant macro in a way that affects behavior -- Changing a function-like macro in a way that is not backwards compatible - -**Behavioral changes:** - -- Changing the semantics or behavior of a function in a way that breaks existing usage -- Changing error codes returned by a function -- Changing the threading or interrupt context requirements for a function - -C API non-breaking changes -=========================== - -The following changes to Public or Internal C APIs are generally **non-breaking changes**: - -- Adding new functions with unique names -- Adding new structures, unions, or enums with unique names -- Adding new enum values (at the end of the enum, without changing existing values) -- Adding fields at the end of a structure when using explicit versioning or size fields -- Adding new macros with unique names -- Deprecating (but not removing) functions, types, or macros using ``__deprecated`` -- Adding function attributes that don't change the ABI (e.g., ``__unused``, documentation) -- Changing internal implementation details without affecting the API contract -- Improving documentation or comments -- Adding optional parameters via variadic functions or configuration structures with size/version fields - -Kconfig breaking changes -========================= - -The following changes to Kconfig symbols are considered **breaking changes**: - -- Removing a Kconfig symbol -- Renaming a Kconfig symbol -- Changing the type of a Kconfig symbol (e.g., from bool to int) -- Removing a Kconfig symbol's default value without providing a migration path -- Changing the dependency tree in a way that makes previously valid configurations invalid -- Changing the semantics of what a Kconfig symbol controls - -Kconfig non-breaking changes -============================= - -The following changes to Kconfig symbols are generally **non-breaking changes**: - -- Adding new Kconfig symbols -- Adding new dependencies to an existing symbol (if it doesn't break existing configurations) -- Changing the help text or prompt -- Changing the default value in a way that maintains backwards compatibility -- Adding ranges or choices that include previously valid values -- Deprecating a Kconfig symbol (with migration path to new symbol) - -Devicetree breaking changes -============================ - -The following changes to Devicetree bindings are considered **breaking changes**: - -- Removing a binding file -- Removing a required property from a binding -- Renaming a required property in a binding -- Changing the type of a property in a binding -- Removing or changing the meaning of a cell in a phandle-array or phandle property -- Making a previously optional property required without providing a default value -- Removing support for a compatible string - -Devicetree non-breaking changes -================================ - -The following changes to Devicetree bindings are generally **non-breaking changes**: - -- Adding new binding files -- Adding new optional properties to a binding -- Adding new compatible strings -- Adding default values for properties -- Making a previously required property optional -- Deprecating a property (while maintaining support for it) -- Changing or improving property descriptions -- Adding new cells to phandle-arrays when properly versioned - -API lifecycle considerations -============================= - -The impact of a breaking change depends on the API classification: - -**Private APIs:** - Breaking changes are allowed at any time without documentation. Since these APIs are internal - to a software component, changes are expected and applications should not depend on them. - -**Internal APIs:** - Breaking changes are allowed but must be documented in the migration guide. This helps - maintainers of other Zephyr components update their code accordingly. - -**Public APIs:** - Breaking changes must follow the :ref:`api_lifecycle`. This typically means: - - - **Experimental APIs**: Can have breaking changes, but should be documented - - **Unstable APIs**: Can have breaking changes, but must be documented in migration guide - - **Stable APIs**: Breaking changes should be avoided. If absolutely necessary, must go through - deprecation period and be thoroughly documented +.. list-table:: C API Changes + :header-rows: 1 + :widths: 50 50 + + * - Breaking Changes + - Non-Breaking Changes + * - | **Functions:** + | • Remove or rename function + | • Change return type + | • Add, remove, or reorder parameters + | • Change parameter types + | • Change behavior or error codes + | + | **Data types:** + | • Remove or rename struct/union/enum + | • Modify struct fields (remove, rename, reorder, change type) + | • Remove/rename enum values + | • Change enum constant values + | + | **Macros:** + | • Remove or rename macro + | • Change macro value affecting behavior + - | **Functions:** + | • Add new function + | • Deprecate (not remove) function + | • Improve documentation + | + | **Data types:** + | • Add new struct/union/enum + | • Add enum value at end + | • Add struct field at end (with versioning) + | + | **Macros:** + | • Add new macro + +.. list-table:: Kconfig Changes + :header-rows: 1 + :widths: 50 50 + + * - Breaking Changes + - Non-Breaking Changes + * - | • Remove or rename symbol + | • Change symbol type (e.g., bool to int) + | • Remove default without migration path + | • Change dependencies breaking configs + | • Change symbol semantics + - | • Add new symbol + | • Change help text or prompt + | • Change default (backward compatible) + | • Add ranges/choices including valid values + | • Deprecate with migration path + +.. list-table:: Devicetree Changes + :header-rows: 1 + :widths: 50 50 + + * - Breaking Changes + - Non-Breaking Changes + * - | • Remove binding file + | • Remove or rename required property + | • Change property type + | • Make optional property required (no default) + | • Change phandle-array cell meaning + | • Remove compatible string + - | • Add binding file + | • Add optional property + | • Add compatible string + | • Add property default + | • Make required property optional + | • Deprecate property (keep support) + +API Lifecycle Impact +==================== + +Breaking changes require different handling based on API classification: + +- **Private APIs**: Changes allowed anytime without documentation +- **Internal APIs**: Changes allowed but must document in migration guide +- **Public APIs**: Must follow :ref:`api_lifecycle` (Experimental → Unstable → Stable) From 9994c102dbf8437e13ee891d165a6d91059f6be3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Nov 2025 10:24:29 +0000 Subject: [PATCH 7/8] Add note that ABI compatibility is out of scope Co-authored-by: kartben <128251+kartben@users.noreply.github.com> --- doc/develop/api/api_conventions.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/develop/api/api_conventions.rst b/doc/develop/api/api_conventions.rst index b8d1e78d1e5a4..3043a4b28ccbc 100644 --- a/doc/develop/api/api_conventions.rst +++ b/doc/develop/api/api_conventions.rst @@ -106,6 +106,11 @@ Breaking and non-breaking changes This section categorizes common changes as breaking or non-breaking for each API type. +.. note:: + This section focuses on API source compatibility. ABI (Application Binary Interface) compatibility + is out of scope, as it is assumed that applications recompile their entire code base when updating + Zephyr versions. + .. list-table:: C API Changes :header-rows: 1 :widths: 50 50 From 75572427617f0e5b3836f92218a555fcc0426239 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Nov 2025 10:30:11 +0000 Subject: [PATCH 8/8] Remove struct field reordering from breaking changes (ABI issue, not API) Co-authored-by: kartben <128251+kartben@users.noreply.github.com> --- doc/develop/api/api_conventions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/develop/api/api_conventions.rst b/doc/develop/api/api_conventions.rst index 3043a4b28ccbc..5e2c5052c1b9f 100644 --- a/doc/develop/api/api_conventions.rst +++ b/doc/develop/api/api_conventions.rst @@ -126,7 +126,7 @@ This section categorizes common changes as breaking or non-breaking for each API | | **Data types:** | • Remove or rename struct/union/enum - | • Modify struct fields (remove, rename, reorder, change type) + | • Modify struct fields (remove, rename, change type) | • Remove/rename enum values | • Change enum constant values |