On Tue, Mar 11, 2025 at 10:56:01AM +0100, David Marchand wrote: > For versioning symbols: > - MSVC uses pragmas on the symbol, > - GNU linker uses special asm directives, > > To accommodate both GNU linker and MSVC linker, introduce new macros for > exporting and versioning symbols that will surround the whole function. > > This has the advantage of hiding all the ugly details in the macros. > Now versioning a symbol is just a call to a single macro: > - RTE_VERSION_SYMBOL (resp. RTE_VERSION_EXPERIMENTAL_SYMBOL), for > keeping an old implementation code under a versioned function (resp. > experimental function), > - RTE_DEFAULT_SYMBOL, for declaring the new default versioned function, > and handling the static link special case, instead of > BIND_DEFAULT_SYMBOL + MAP_STATIC_SYMBOL, > > Update lib/net accordingly. > > Signed-off-by: David Marchand <david.march...@redhat.com> > ---
A few review comments on the docs inline below. See nothing wrong from initial review of code changes. /Bruce > Changes since RFC v2: > > Changes since RFC v1: > - renamed and prefixed macros, > - reindented in prevision of second patch, > > --- > doc/guides/contributing/abi_versioning.rst | 165 +++++---------------- > lib/eal/include/rte_function_versioning.h | 96 +++++------- > lib/net/net_crc.h | 15 -- > lib/net/rte_net_crc.c | 28 +--- > 4 files changed, 77 insertions(+), 227 deletions(-) > > diff --git a/doc/guides/contributing/abi_versioning.rst > b/doc/guides/contributing/abi_versioning.rst > index 7afd1c1886..88dd776b4c 100644 > --- a/doc/guides/contributing/abi_versioning.rst > +++ b/doc/guides/contributing/abi_versioning.rst > @@ -138,27 +138,20 @@ macros are used in conjunction with the ``version.map`` > file for > a given library to allow multiple versions of a symbol to exist in a shared > library so that older binaries need not be immediately recompiled. > > -The macros exported are: > +The macros are: > > -* ``VERSION_SYMBOL(b, e, n)``: Creates a symbol version table entry binding > - versioned symbol ``b@DPDK_n`` to the internal function ``be``. > +* ``RTE_VERSION_SYMBOL(ver, type, name, args``: Creates a symbol version > table Missing closing brace .........................^ here > + entry binding symbol ``<name>@DPDK_<ver>`` to the internal function name > + ``<name>_v<ver>``. > > -* ``BIND_DEFAULT_SYMBOL(b, e, n)``: Creates a symbol version entry > instructing > - the linker to bind references to symbol ``b`` to the internal symbol > - ``be``. > +* ``RTE_DEFAULT_SYMBO(ver, type, name, args)``: Creates a symbol version > entry s/SYMBO/SYMBOL/ > + instructing the linker to bind references to symbol ``<name>`` to the > internal > + symbol ``<name>_v<ver>``. > > -* ``MAP_STATIC_SYMBOL(f, p)``: Declare the prototype ``f``, and map it to the > - fully qualified function ``p``, so that if a symbol becomes versioned, it > - can still be mapped back to the public symbol name. > - > -* ``__vsym``: Annotation to be used in a declaration of the internal symbol > - ``be`` to signal that it is being used as an implementation of a particular > - version of symbol ``b``. > - > -* ``VERSION_SYMBOL_EXPERIMENTAL(b, e)``: Creates a symbol version table entry > - binding versioned symbol ``b@EXPERIMENTAL`` to the internal function > ``be``. > - The macro is used when a symbol matures to become part of the stable ABI, > to > - provide an alias to experimental until the next major ABI version. > +* ``RTE_VERSION_EXPERIMENTAL_SYMBOL(type, name, args)``: Similar to > RTE_VERSION_SYMBOL > + but for experimental API symbols. The macro is used when a symbol matures > + to become part of the stable ABI, to provide an alias to experimental > + until the next major ABI version. Just to clarify - this is where we create two names/aliases for the one function, so it can be found either as an experimental version or a stable one, right? In that way it's actually quite different from RTE_VERSION_SYMBOL which is used to define a *NEW" version of an existing function, i.e. two functions rather than one function with two names. > > .. _example_abi_macro_usage: > > @@ -277,49 +270,36 @@ list of exported symbols when DPDK is compiled as a > shared library. > > Next, we need to specify in the code which function maps to the > rte_acl_create > symbol at which versions. First, at the site of the initial symbol > definition, > -we need to update the function so that it is uniquely named, and not in > conflict > -with the public symbol name > +we wrap the function with ``RTE_VERSION_SYMBOL``, passing the current ABI > version, > +the function return type, and the function name and its arguments. > > .. code-block:: c > > -struct rte_acl_ctx * > -rte_acl_create(const struct rte_acl_param *param) > - +struct rte_acl_ctx * __vsym > - +rte_acl_create_v21(const struct rte_acl_param *param) > + +RTE_VERSION_SYMBOL(21, struct rte_acl_ctx *, rte_acl_create, (const struct > rte_acl_param *param)) > { > size_t sz; > struct rte_acl_ctx *ctx; > ... > - > -Note that the base name of the symbol was kept intact, as this is conducive > to > -the macros used for versioning symbols and we have annotated the function as > -``__vsym``, an implementation of a versioned symbol . That is our next step, > -mapping this new symbol name to the initial symbol name at version node 21. > -Immediately after the function, we add the VERSION_SYMBOL macro. > - > -.. code-block:: c > - > - #include <rte_function_versioning.h> > - > - ... > - VERSION_SYMBOL(rte_acl_create, _v21, 21); > + } > > Remembering to also add the rte_function_versioning.h header to the > requisite c > file where these changes are being made. The macro instructs the linker to > create a new symbol ``rte_acl_create@DPDK_21``, which matches the symbol > created > -in older builds, but now points to the above newly named function. We have > now > -mapped the original rte_acl_create symbol to the original function (but with > a > -new name). > +in older builds, but now points to the above newly named function > ``rte_acl_create_v21``. > +We have now mapped the original rte_acl_create symbol to the original > function > +(but with a new name). > > Please see the section :ref:`Enabling versioning macros > <enabling_versioning_macros>` to enable this macro in the meson/ninja build. > -Next, we need to create the new ``v22`` version of the symbol. We create a > new > -function name, with the ``v22`` suffix, and implement it appropriately. > +Next, we need to create the new version of the symbol. We create a new > +function name and implement it appropriately, then wrap it in a call to > ``RTE_DEFAULT_SYMBOL``. > > .. code-block:: c > > - struct rte_acl_ctx * __vsym > - rte_acl_create_v22(const struct rte_acl_param *param, int debug); > + RTE_DEFAULT_SYMBOL(22, struct rte_acl_ctx *, rte_acl_create, (const > struct rte_acl_param *param, > + int debug)) Not directly relevant to the changes in this patch, but since this is documentation which doesn't actually need to be based on a real-life example, we should maybe come up with example functions which are short and don't need line wrapping. This example would be just as effective/instructive with a return value of "int" and parameter type without a "const" qualifier. :-) > { > struct rte_acl_ctx *ctx = rte_acl_create_v21(param); > > @@ -328,35 +308,9 @@ function name, with the ``v22`` suffix, and implement it > appropriately. > return ctx; > } > > -This code serves as our new API call. Its the same as our old call, but adds > the > -new parameter in place. Next we need to map this function to the new default > -symbol ``rte_acl_create@DPDK_22``. To do this, immediately after the > function, > -we add the BIND_DEFAULT_SYMBOL macro. > - > -.. code-block:: c > - > - #include <rte_function_versioning.h> > - > - ... > - BIND_DEFAULT_SYMBOL(rte_acl_create, _v22, 22); > - > The macro instructs the linker to create the new default symbol > -``rte_acl_create@DPDK_22``, which points to the above newly named function. > - > -We finally modify the prototype of the call in the public header file, > -such that it contains both versions of the symbol and the public API. > - > -.. code-block:: c > - > - struct rte_acl_ctx * > - rte_acl_create(const struct rte_acl_param *param); > - > - struct rte_acl_ctx * __vsym > - rte_acl_create_v21(const struct rte_acl_param *param); > - > - struct rte_acl_ctx * __vsym > - rte_acl_create_v22(const struct rte_acl_param *param, int debug); > - > +``rte_acl_create@DPDK_22``, which points to the function named > ``rte_acl_create_v22`` > +(declared by the macro). > > And that's it, on the next shared library rebuild, there will be two > versions of > rte_acl_create, an old DPDK_21 version, used by previously built > applications, > @@ -365,43 +319,10 @@ and a new DPDK_22 version, used by future built > applications. > .. note:: > > **Before you leave**, please take care reviewing the sections on > - :ref:`mapping static symbols <mapping_static_symbols>`, > :ref:`enabling versioning macros <enabling_versioning_macros>`, > and :ref:`ABI deprecation <abi_deprecation>`. > > > -.. _mapping_static_symbols: > - > -Mapping static symbols > -______________________ > - > -Now we've taken what was a public symbol, and duplicated it into two uniquely > -and differently named symbols. We've then mapped each of those back to the > -public symbol ``rte_acl_create`` with different version tags. This only > applies > -to dynamic linking, as static linking has no notion of versioning. That > leaves > -this code in a position of no longer having a symbol simply named > -``rte_acl_create`` and a static build will fail on that missing symbol. > - > -To correct this, we can simply map a function of our choosing back to the > public > -symbol in the static build with the ``MAP_STATIC_SYMBOL`` macro. Generally > the > -assumption is that the most recent version of the symbol is the one you want > to > -map. So, back in the C file where, immediately after ``rte_acl_create_v22`` > is > -defined, we add this > - > - > -.. code-block:: c > - > - struct rte_acl_ctx * __vsym > - rte_acl_create_v22(const struct rte_acl_param *param, int debug) > - { > - ... > - } > - MAP_STATIC_SYMBOL(struct rte_acl_ctx *rte_acl_create(const struct > rte_acl_param *param, int debug), rte_acl_create_v22); > - > -That tells the compiler that, when building a static library, any calls to > the > -symbol ``rte_acl_create`` should be linked to ``rte_acl_create_v22`` > - > - > .. _enabling_versioning_macros: > > Enabling versioning macros > @@ -519,26 +440,17 @@ and ``DPDK_22`` version nodes. > * Create an acl context object for apps to > * manipulate > */ > - struct rte_acl_ctx * > - rte_acl_create(const struct rte_acl_param *param) > + RTE_DEFAULT_SYMBOL(22, struct rte_acl_ctx *, rte_acl_create, > + (const struct rte_acl_param *param)) > { > ... > } > > - __rte_experimental > - struct rte_acl_ctx * > - rte_acl_create_e(const struct rte_acl_param *param) > - { > - return rte_acl_create(param); > - } > - VERSION_SYMBOL_EXPERIMENTAL(rte_acl_create, _e); > - > - struct rte_acl_ctx * > - rte_acl_create_v22(const struct rte_acl_param *param) > + RTE_VERSION_EXPERIMENTAL_SYMBOL(struct rte_acl_ctx *, rte_acl_create, > + (const struct rte_acl_param *param)) > { > return rte_acl_create(param); > } > - BIND_DEFAULT_SYMBOL(rte_acl_create, _v22, 22); > > In the map file, we map the symbol to both the ``EXPERIMENTAL`` > and ``DPDK_22`` version nodes. > @@ -564,13 +476,6 @@ and ``DPDK_22`` version nodes. > rte_acl_create; > }; > > -.. note:: > - > - Please note, similar to :ref:`symbol versioning > <example_abi_macro_usage>`, > - when aliasing to experimental you will also need to take care of > - :ref:`mapping static symbols <mapping_static_symbols>`. > - > - > .. _abi_deprecation: > > Deprecating part of a public API > @@ -616,10 +521,10 @@ Next remove the corresponding versioned export. > > .. code-block:: c > > - -VERSION_SYMBOL(rte_acl_create, _v21, 21); > + -RTE_VERSION_SYMBOL(21, struct rte_acl_ctx *, rte_acl_create, (const struct > rte_acl_param *param)) > > > -Note that the internal function definition could also be removed, but its > used > +Note that the internal function definition must also be removed, but its used its -> it's (or "it is" if you want the longer version). > in our example by the newer version ``v22``, so we leave it in place and > declare > it as static. This is a coding style choice. > > @@ -663,16 +568,18 @@ In the case of our map above, it would transform to > look as follows > local: *; > }; > > -Then any uses of BIND_DEFAULT_SYMBOL that pointed to the old node should be > +Then any uses of RTE_DEFAULT_SYMBOL that pointed to the old node should be > updated to point to the new version node in any header files for all affected > symbols. > > .. code-block:: c > > - -BIND_DEFAULT_SYMBOL(rte_acl_create, _v21, 21); > - +BIND_DEFAULT_SYMBOL(rte_acl_create, _v22, 22); > + -RTE_DEFAULT_SYMBOL(21, struct rte_acl_ctx *, rte_acl_create, (const struct > rte_acl_param *param, > + int debug)) > + -RTE_DEFAULT_SYMBOL(22, struct rte_acl_ctx *, rte_acl_create, (const struct > rte_acl_param *param, > + int debug)) > > -Lastly, any VERSION_SYMBOL macros that point to the old version nodes > +Lastly, any RTE_VERSION_SYMBOL macros that point to the old version nodes > should be removed, taking care to preserve any code that is shared > with the new version node. > > diff --git a/lib/eal/include/rte_function_versioning.h > b/lib/eal/include/rte_function_versioning.h > index eb6dd2bc17..0020ce4885 100644 > --- a/lib/eal/include/rte_function_versioning.h > +++ b/lib/eal/include/rte_function_versioning.h > @@ -11,8 +11,6 @@ > #error Use of function versioning disabled, is > "use_function_versioning=true" in meson.build? > #endif > > -#ifdef RTE_BUILD_SHARED_LIB > - > /* > * Provides backwards compatibility when updating exported functions. > * When a symbol is exported from a library to provide an API, it also > provides a > @@ -20,80 +18,54 @@ > * arguments, etc. On occasion that function may need to change to > accommodate > * new functionality, behavior, etc. When that occurs, it is desirable to > * allow for backwards compatibility for a time with older binaries that are > - * dynamically linked to the dpdk. To support that, the __vsym and > - * VERSION_SYMBOL macros are created. They, in conjunction with the > - * version.map file for a given library allow for multiple versions of > - * a symbol to exist in a shared library so that older binaries need not be > - * immediately recompiled. > - * > - * Refer to the guidelines document in the docs subdirectory for details on > the > - * use of these macros > + * dynamically linked to the dpdk. > */ > > -/* > - * Macro Parameters: > - * b - function base name > - * e - function version extension, to be concatenated with base name > - * n - function symbol version string to be applied > - * f - function prototype > - * p - full function symbol name > - */ > +#ifdef RTE_BUILD_SHARED_LIB > > /* > - * VERSION_SYMBOL > - * Creates a symbol version table entry binding symbol <b>@DPDK_<n> to the > internal > - * function name <b><e> > + * RTE_VERSION_SYMBOL > + * Creates a symbol version table entry binding symbol <name>@DPDK_<ver> to > the internal > + * function name <name>_v<ver>. > */ > -#define VERSION_SYMBOL(b, e, n) __asm__(".symver " RTE_STR(b) RTE_STR(e) ", > " RTE_STR(b) "@DPDK_" RTE_STR(n)) > +#define RTE_VERSION_SYMBOL(ver, type, name, args) \ > +__asm__(".symver " RTE_STR(name) "_v" RTE_STR(ver) ", " RTE_STR(name) > "@DPDK_" RTE_STR(ver)); \ > +__rte_used type name ## _v ## ver args; \ > +type name ## _v ## ver args > > /* > - * VERSION_SYMBOL_EXPERIMENTAL > - * Creates a symbol version table entry binding the symbol <b>@EXPERIMENTAL > to the internal > - * function name <b><e>. The macro is used when a symbol matures to become > part of the stable ABI, > - * to provide an alias to experimental for some time. > + * RTE_VERSION_EXPERIMENTAL_SYMBOL > + * Similar to RTE_VERSION_SYMBOL but for experimental API symbols. > + * This is mainly used for keeping compatibility for symbols that get > promoted to stable ABI. > */ > -#define VERSION_SYMBOL_EXPERIMENTAL(b, e) __asm__(".symver " RTE_STR(b) > RTE_STR(e) ", " RTE_STR(b) "@EXPERIMENTAL") > +#define RTE_VERSION_EXPERIMENTAL_SYMBOL(type, name, args) \ > +__asm__(".symver " RTE_STR(name) "_exp, " RTE_STR(name) "@EXPERIMENTAL") \ > +__rte_used type name ## _exp args; \ > +type name ## _exp args > > /* > - * BIND_DEFAULT_SYMBOL > + * RTE_DEFAULT_SYMBOL > * Creates a symbol version entry instructing the linker to bind references > to > - * symbol <b> to the internal symbol <b><e> > + * symbol <name> to the internal symbol <name>_v<ver>. > */ > -#define BIND_DEFAULT_SYMBOL(b, e, n) __asm__(".symver " RTE_STR(b) > RTE_STR(e) ", " RTE_STR(b) "@@DPDK_" RTE_STR(n)) > +#define RTE_DEFAULT_SYMBOL(ver, type, name, args) \ > +__asm__(".symver " RTE_STR(name) "_v" RTE_STR(ver) ", " RTE_STR(name) > "@@DPDK_" RTE_STR(ver)); \ > +__rte_used type name ## _v ## ver args; \ > +type name ## _v ## ver args > > -/* > - * __vsym > - * Annotation to be used in declaration of the internal symbol <b><e> to > signal > - * that it is being used as an implementation of a particular version of > symbol > - * <b>. > - */ > -#define __vsym __rte_used > +#else /* !RTE_BUILD_SHARED_LIB */ > > -/* > - * MAP_STATIC_SYMBOL > - * If a function has been bifurcated into multiple versions, none of which > - * are defined as the exported symbol name in the map file, this macro can be > - * used to alias a specific version of the symbol to its exported name. For > - * example, if you have 2 versions of a function foo_v1 and foo_v2, where the > - * former is mapped to foo@DPDK_1 and the latter is mapped to foo@DPDK_2 when > - * building a shared library, this macro can be used to map either foo_v1 or > - * foo_v2 to the symbol foo when building a static library, e.g.: > - * MAP_STATIC_SYMBOL(void foo(), foo_v2); > - */ > -#define MAP_STATIC_SYMBOL(f, p) > +#define RTE_VERSION_SYMBOL(ver, type, name, args) \ > +type name ## _v ## ver args; \ > +type name ## _v ## ver args > > -#else > -/* > - * No symbol versioning in use > - */ > -#define VERSION_SYMBOL(b, e, n) > -#define VERSION_SYMBOL_EXPERIMENTAL(b, e) > -#define __vsym > -#define BIND_DEFAULT_SYMBOL(b, e, n) > -#define MAP_STATIC_SYMBOL(f, p) f __attribute__((alias(RTE_STR(p)))) > -/* > - * RTE_BUILD_SHARED_LIB=n > - */ > -#endif > +#define RTE_VERSION_EXPERIMENTAL_SYMBOL(type, name, args) \ > +type name ## _exp args; \ > +type name ## _exp args > + > +#define RTE_DEFAULT_SYMBOL(ver, type, name, args) \ > +type name args > + > +#endif /* RTE_BUILD_SHARED_LIB */ > > #endif /* _RTE_FUNCTION_VERSIONING_H_ */ Changes to this file look ok to me. <snip>