* [RFC] eal: add new function versioning macros
@ 2025-03-05 21:23 David Marchand
2025-03-06 2:57 ` Patrick Robb
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: David Marchand @ 2025-03-05 21:23 UTC (permalink / raw)
To: dev; +Cc: thomas, andremue, Tyler Retzlaff, Jasvinder Singh
For versioning symbols:
- MSVC uses pragmas on the function symbol,
- GNU linker uses special asm directives,
To accommodate both GNU linker and MSVC linker, introduce new macros for
versioning functions that will surround the whole function.
This has the advantage of hiding all the ugly details in the macros.
Now versioning a function is just a call to a single macro:
- VERSION_FUNCTION (resp. VERSION_FUNCTION_EXPERIMENTAL), for keeping an
old implementation code under a versioned function,
- DEFAULT_FUNCTION, for declaring the new default versioned function,
and handling the static link special case, instead of
BIND_DEFAULT_SYMBOL + MAP_STATIC_SYMBOL,
Documentation has been updated though it needs some polishing.
The experimental macro has not been tested.
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
doc/guides/contributing/abi_versioning.rst | 133 ++++-----------------
lib/eal/include/rte_function_versioning.h | 27 +++++
lib/net/rte_net_crc.c | 41 +++----
3 files changed, 69 insertions(+), 132 deletions(-)
diff --git a/doc/guides/contributing/abi_versioning.rst b/doc/guides/contributing/abi_versioning.rst
index 7afd1c1886..b83383fd0b 100644
--- a/doc/guides/contributing/abi_versioning.rst
+++ b/doc/guides/contributing/abi_versioning.rst
@@ -277,86 +277,52 @@ 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 ``VERSION_FUNCTION``, passing the current ABI version,
+the function return type, and the function name, then the full implementation of the
+function.
.. 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)
+ +VERSION_FUNCTION(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 ``DEFAULT_FUNCTION``.
.. code-block:: c
- struct rte_acl_ctx * __vsym
- rte_acl_create_v22(const struct rte_acl_param *param, int debug);
+ DEFAULT_FUNCTION(22,
+ struct rte_acl_ctx *,
+ rte_acl_create, (const struct rte_acl_param *param, int debug);
{
struct rte_acl_ctx *ctx = rte_acl_create_v21(param);
ctx->debug = debug;
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 +331,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 +452,19 @@ 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)
+ DEFAULT_FUNCTION(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);
+ })
+ VERSION_FUNCTION_EXPERIMENTAL(
struct rte_acl_ctx *
- rte_acl_create_v22(const struct rte_acl_param *param)
+ 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 +490,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
diff --git a/lib/eal/include/rte_function_versioning.h b/lib/eal/include/rte_function_versioning.h
index eb6dd2bc17..7a33a45928 100644
--- a/lib/eal/include/rte_function_versioning.h
+++ b/lib/eal/include/rte_function_versioning.h
@@ -96,4 +96,31 @@
*/
#endif
+#ifdef RTE_BUILD_SHARED_LIB
+
+#define VERSION_FUNCTION(ver, type, name, ...) \
+__rte_used type name ## _v ## ver __VA_ARGS__ \
+__asm__(".symver " RTE_STR(name) "_v" RTE_STR(ver) ", " RTE_STR(name) "@DPDK_" RTE_STR(ver));
+
+#define VERSION_FUNCTION_EXPERIMENTAL(type, name, ...) \
+__rte_used type name ## _exp __VA_ARGS__ \
+__asm__(".symver " RTE_STR(name) "_exp, " RTE_STR(name) "@EXPERIMENTAL")
+
+#define DEFAULT_FUNCTION(ver, type, name, ...) \
+__rte_used type name ## _v ## ver __VA_ARGS__ \
+__asm__(".symver " RTE_STR(name) "_v" RTE_STR(ver) ", " RTE_STR(name) "@@DPDK_" RTE_STR(ver));
+
+#else /* !RTE_BUILD_SHARED_LIB */
+
+#define VERSION_FUNCTION(ver, type, name, ...) \
+type name ## _v ## ver __VA_ARGS__
+
+#define VERSION_FUNCTION_EXPERIMENTAL(type, name, ...) \
+type name ## _exp __VA_ARGS__
+
+#define DEFAULT_FUNCTION(ver, type, name, ...) \
+type name __VA_ARGS__
+
+#endif /* RTE_BUILD_SHARED_LIB */
+
#endif /* _RTE_FUNCTION_VERSIONING_H_ */
diff --git a/lib/net/rte_net_crc.c b/lib/net/rte_net_crc.c
index 2fb3eec231..a1c17e0735 100644
--- a/lib/net/rte_net_crc.c
+++ b/lib/net/rte_net_crc.c
@@ -345,8 +345,9 @@ handlers_init(enum rte_net_crc_alg alg)
/* Public API */
-void
-rte_net_crc_set_alg_v25(enum rte_net_crc_alg alg)
+VERSION_FUNCTION(25,
+void,
+rte_net_crc_set_alg, (enum rte_net_crc_alg alg)
{
handlers = NULL;
if (max_simd_bitwidth == 0)
@@ -372,11 +373,11 @@ rte_net_crc_set_alg_v25(enum rte_net_crc_alg alg)
if (handlers == NULL)
handlers = handlers_scalar;
-}
-VERSION_SYMBOL(rte_net_crc_set_alg, _v25, 25);
+})
-struct rte_net_crc *rte_net_crc_set_alg_v26(enum rte_net_crc_alg alg,
- enum rte_net_crc_type type)
+DEFAULT_FUNCTION(26,
+struct rte_net_crc *,
+rte_net_crc_set_alg, (enum rte_net_crc_alg alg, enum rte_net_crc_type type)
{
uint16_t max_simd_bitwidth;
struct rte_net_crc *crc;
@@ -413,21 +414,16 @@ struct rte_net_crc *rte_net_crc_set_alg_v26(enum rte_net_crc_alg alg,
break;
}
return crc;
-}
-BIND_DEFAULT_SYMBOL(rte_net_crc_set_alg, _v26, 26);
-MAP_STATIC_SYMBOL(struct rte_net_crc *rte_net_crc_set_alg(
- enum rte_net_crc_alg alg, enum rte_net_crc_type type),
- rte_net_crc_set_alg_v26);
+})
void rte_net_crc_free(struct rte_net_crc *crc)
{
rte_free(crc);
}
-uint32_t
-rte_net_crc_calc_v25(const void *data,
- uint32_t data_len,
- enum rte_net_crc_type type)
+VERSION_FUNCTION(25,
+uint32_t,
+rte_net_crc_calc, (const void *data, uint32_t data_len, enum rte_net_crc_type type)
{
uint32_t ret;
rte_net_crc_handler f_handle;
@@ -436,19 +432,14 @@ rte_net_crc_calc_v25(const void *data,
ret = f_handle(data, data_len);
return ret;
-}
-VERSION_SYMBOL(rte_net_crc_calc, _v25, 25);
+})
-uint32_t
-rte_net_crc_calc_v26(const struct rte_net_crc *ctx,
- const void *data, const uint32_t data_len)
+DEFAULT_FUNCTION(26,
+uint32_t,
+rte_net_crc_calc, (const struct rte_net_crc *ctx, const void *data, const uint32_t data_len)
{
return handlers_dpdk26[ctx->alg].f[ctx->type](data, data_len);
-}
-BIND_DEFAULT_SYMBOL(rte_net_crc_calc, _v26, 26);
-MAP_STATIC_SYMBOL(uint32_t rte_net_crc_calc(const struct rte_net_crc *ctx,
- const void *data, const uint32_t data_len),
- rte_net_crc_calc_v26);
+})
/* Call initialisation helpers for all crc algorithm handlers */
RTE_INIT(rte_net_crc_init)
--
2.48.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC] eal: add new function versioning macros
2025-03-05 21:23 [RFC] eal: add new function versioning macros David Marchand
@ 2025-03-06 2:57 ` Patrick Robb
2025-03-06 10:23 ` Bruce Richardson
2025-03-06 12:50 ` [RFC v2 1/2] " David Marchand
2 siblings, 0 replies; 6+ messages in thread
From: Patrick Robb @ 2025-03-06 2:57 UTC (permalink / raw)
To: David Marchand; +Cc: dev, thomas, andremue, Tyler Retzlaff, Jasvinder Singh
[-- Attachment #1: Type: text/plain, Size: 166 bytes --]
Recheck-request: iol-intel-Performance
There was an infra failure with the Arm Grace server about 12 hours ago
which caused this failure - sending a retest request.
[-- Attachment #2: Type: text/html, Size: 204 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC] eal: add new function versioning macros
2025-03-05 21:23 [RFC] eal: add new function versioning macros David Marchand
2025-03-06 2:57 ` Patrick Robb
@ 2025-03-06 10:23 ` Bruce Richardson
2025-03-06 12:50 ` [RFC v2 1/2] " David Marchand
2 siblings, 0 replies; 6+ messages in thread
From: Bruce Richardson @ 2025-03-06 10:23 UTC (permalink / raw)
To: David Marchand; +Cc: dev, thomas, andremue, Tyler Retzlaff, Jasvinder Singh
On Wed, Mar 05, 2025 at 10:23:49PM +0100, David Marchand wrote:
> For versioning symbols:
> - MSVC uses pragmas on the function symbol,
> - GNU linker uses special asm directives,
>
> To accommodate both GNU linker and MSVC linker, introduce new macros for
> versioning functions that will surround the whole function.
>
> This has the advantage of hiding all the ugly details in the macros.
> Now versioning a function is just a call to a single macro:
> - VERSION_FUNCTION (resp. VERSION_FUNCTION_EXPERIMENTAL), for keeping an
> old implementation code under a versioned function,
> - DEFAULT_FUNCTION, for declaring the new default versioned function,
> and handling the static link special case, instead of
> BIND_DEFAULT_SYMBOL + MAP_STATIC_SYMBOL,
>
> Documentation has been updated though it needs some polishing.
> The experimental macro has not been tested.
>
> Signed-off-by: David Marchand <david.marchand@redhat.com>
> ---
This looks a nice improvement to me, thanks.
^ permalink raw reply [flat|nested] 6+ messages in thread
* [RFC v2 1/2] eal: add new function versioning macros
2025-03-05 21:23 [RFC] eal: add new function versioning macros David Marchand
2025-03-06 2:57 ` Patrick Robb
2025-03-06 10:23 ` Bruce Richardson
@ 2025-03-06 12:50 ` David Marchand
2025-03-06 12:50 ` [RFC v2 2/2] build: generate symbol maps David Marchand
2025-03-06 15:45 ` [RFC v2 1/2] eal: add new function versioning macros Andre Muezerie
2 siblings, 2 replies; 6+ messages in thread
From: David Marchand @ 2025-03-06 12:50 UTC (permalink / raw)
To: dev; +Cc: thomas, bruce.richardson, andremue, Tyler Retzlaff, Jasvinder Singh
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,
Documentation has been updated though it needs some polishing.
The experimental macro has not been tested.
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
Changes since RFC v1:
- renamed and prefixed macros,
- reindented in prevision of second patch,
---
doc/guides/contributing/abi_versioning.rst | 130 ++++-----------------
lib/eal/include/rte_function_versioning.h | 27 +++++
lib/net/rte_net_crc.c | 30 ++---
3 files changed, 57 insertions(+), 130 deletions(-)
diff --git a/doc/guides/contributing/abi_versioning.rst b/doc/guides/contributing/abi_versioning.rst
index 7afd1c1886..c4baf6433a 100644
--- a/doc/guides/contributing/abi_versioning.rst
+++ b/doc/guides/contributing/abi_versioning.rst
@@ -277,86 +277,49 @@ 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, then the full implementation of the
+function.
.. 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);
{
struct rte_acl_ctx *ctx = rte_acl_create_v21(param);
ctx->debug = debug;
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 +328,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 +449,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 +485,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
diff --git a/lib/eal/include/rte_function_versioning.h b/lib/eal/include/rte_function_versioning.h
index eb6dd2bc17..259b960ef5 100644
--- a/lib/eal/include/rte_function_versioning.h
+++ b/lib/eal/include/rte_function_versioning.h
@@ -96,4 +96,31 @@
*/
#endif
+#ifdef RTE_BUILD_SHARED_LIB
+
+#define RTE_VERSION_SYMBOL(ver, type, name, ...) \
+__rte_used type name ## _v ## ver __VA_ARGS__ \
+__asm__(".symver " RTE_STR(name) "_v" RTE_STR(ver) ", " RTE_STR(name) "@DPDK_" RTE_STR(ver));
+
+#define RTE_VERSION_EXPERIMENTAL_SYMBOL(type, name, ...) \
+__rte_used type name ## _exp __VA_ARGS__ \
+__asm__(".symver " RTE_STR(name) "_exp, " RTE_STR(name) "@EXPERIMENTAL")
+
+#define RTE_DEFAULT_SYMBOL(ver, type, name, ...) \
+__rte_used type name ## _v ## ver __VA_ARGS__ \
+__asm__(".symver " RTE_STR(name) "_v" RTE_STR(ver) ", " RTE_STR(name) "@@DPDK_" RTE_STR(ver));
+
+#else /* !RTE_BUILD_SHARED_LIB */
+
+#define RTE_VERSION_SYMBOL(ver, type, name, ...) \
+type name ## _v ## ver __VA_ARGS__
+
+#define RTE_VERSION_EXPERIMENTAL_SYMBOL(type, name, ...) \
+type name ## _exp __VA_ARGS__
+
+#define RTE_DEFAULT_SYMBOL(ver, type, name, ...) \
+type name __VA_ARGS__
+
+#endif /* RTE_BUILD_SHARED_LIB */
+
#endif /* _RTE_FUNCTION_VERSIONING_H_ */
diff --git a/lib/net/rte_net_crc.c b/lib/net/rte_net_crc.c
index 2fb3eec231..dd93d43c2e 100644
--- a/lib/net/rte_net_crc.c
+++ b/lib/net/rte_net_crc.c
@@ -345,8 +345,7 @@ handlers_init(enum rte_net_crc_alg alg)
/* Public API */
-void
-rte_net_crc_set_alg_v25(enum rte_net_crc_alg alg)
+RTE_VERSION_SYMBOL(25, void, rte_net_crc_set_alg, (enum rte_net_crc_alg alg)
{
handlers = NULL;
if (max_simd_bitwidth == 0)
@@ -372,10 +371,9 @@ rte_net_crc_set_alg_v25(enum rte_net_crc_alg alg)
if (handlers == NULL)
handlers = handlers_scalar;
-}
-VERSION_SYMBOL(rte_net_crc_set_alg, _v25, 25);
+})
-struct rte_net_crc *rte_net_crc_set_alg_v26(enum rte_net_crc_alg alg,
+RTE_DEFAULT_SYMBOL(26, struct rte_net_crc *, rte_net_crc_set_alg, (enum rte_net_crc_alg alg,
enum rte_net_crc_type type)
{
uint16_t max_simd_bitwidth;
@@ -413,20 +411,14 @@ struct rte_net_crc *rte_net_crc_set_alg_v26(enum rte_net_crc_alg alg,
break;
}
return crc;
-}
-BIND_DEFAULT_SYMBOL(rte_net_crc_set_alg, _v26, 26);
-MAP_STATIC_SYMBOL(struct rte_net_crc *rte_net_crc_set_alg(
- enum rte_net_crc_alg alg, enum rte_net_crc_type type),
- rte_net_crc_set_alg_v26);
+})
void rte_net_crc_free(struct rte_net_crc *crc)
{
rte_free(crc);
}
-uint32_t
-rte_net_crc_calc_v25(const void *data,
- uint32_t data_len,
+RTE_VERSION_SYMBOL(25, uint32_t, rte_net_crc_calc, (const void *data, uint32_t data_len,
enum rte_net_crc_type type)
{
uint32_t ret;
@@ -436,19 +428,13 @@ rte_net_crc_calc_v25(const void *data,
ret = f_handle(data, data_len);
return ret;
-}
-VERSION_SYMBOL(rte_net_crc_calc, _v25, 25);
+})
-uint32_t
-rte_net_crc_calc_v26(const struct rte_net_crc *ctx,
+RTE_DEFAULT_SYMBOL(26, uint32_t, rte_net_crc_calc, (const struct rte_net_crc *ctx,
const void *data, const uint32_t data_len)
{
return handlers_dpdk26[ctx->alg].f[ctx->type](data, data_len);
-}
-BIND_DEFAULT_SYMBOL(rte_net_crc_calc, _v26, 26);
-MAP_STATIC_SYMBOL(uint32_t rte_net_crc_calc(const struct rte_net_crc *ctx,
- const void *data, const uint32_t data_len),
- rte_net_crc_calc_v26);
+})
/* Call initialisation helpers for all crc algorithm handlers */
RTE_INIT(rte_net_crc_init)
--
2.48.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [RFC v2 2/2] build: generate symbol maps
2025-03-06 12:50 ` [RFC v2 1/2] " David Marchand
@ 2025-03-06 12:50 ` David Marchand
2025-03-06 15:45 ` [RFC v2 1/2] eal: add new function versioning macros Andre Muezerie
1 sibling, 0 replies; 6+ messages in thread
From: David Marchand @ 2025-03-06 12:50 UTC (permalink / raw)
To: dev; +Cc: thomas, bruce.richardson, andremue, Jasvinder Singh
Rather than maintain a file in parallel of the code, symbols to be
exported can be marked with a token.
The build framework then generates map files in a format that can satisfy
GNU linker.
Apply those macros to lib/net as an example.
Documentation is missing.
Converting from .map to Windows export file is not done.
Checks on map files are left in place, though they could be removed once
the whole tree is converted.
Experimental and internal symbol types are not handled.
Probably something else is missing, but this patch is still at RFC level.
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
buildtools/gen-version-map.py | 65 +++++++++++++++++++++++++++++++++++
buildtools/meson.build | 1 +
drivers/meson.build | 2 --
lib/meson.build | 19 ++++++++--
lib/net/rte_arp.c | 1 +
lib/net/rte_ether.c | 3 ++
lib/net/rte_net.c | 2 ++
lib/net/rte_net_crc.c | 1 +
lib/net/version.map | 23 -------------
meson.build | 3 +-
10 files changed, 91 insertions(+), 29 deletions(-)
create mode 100755 buildtools/gen-version-map.py
delete mode 100644 lib/net/version.map
diff --git a/buildtools/gen-version-map.py b/buildtools/gen-version-map.py
new file mode 100755
index 0000000000..2b03f328ea
--- /dev/null
+++ b/buildtools/gen-version-map.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright (c) 2024 Red Hat, Inc.
+
+"""Generate a version map file used by GNU linker."""
+
+import re
+import sys
+
+# From meson.build
+sym_export_regexp = re.compile(r"^RTE_EXPORT_SYMBOL\(([^,]+)\)$")
+# From rte_function_versioning.h
+sym_ver_regexp = re.compile(r"^RTE_VERSION_SYMBOL\(([^,]+), [^,]+, ([^,]+),")
+sym_default_regexp = re.compile(r"^RTE_DEFAULT_SYMBOL\(([^,]+), [^,]+, ([^,]+),")
+
+with open("../ABI_VERSION") as f:
+ abi = re.match("([0-9]+).[0-9]", f.readline()).group(1)
+
+symbols = {}
+
+for file in sys.argv[2:]:
+ with open(file, encoding="utf-8") as f:
+ for ln in f.readlines():
+ node = None
+ symbol = None
+ if sym_export_regexp.match(ln):
+ symbol = sym_export_regexp.match(ln).group(1)
+ elif sym_ver_regexp.match(ln):
+ node = sym_ver_regexp.match(ln).group(1)
+ symbol = sym_ver_regexp.match(ln).group(2)
+ elif sym_default_regexp.match(ln):
+ node = sym_default_regexp.match(ln).group(1)
+ symbol = sym_default_regexp.match(ln).group(2)
+
+ if not symbol:
+ continue
+
+ if not node:
+ node = abi
+ if node not in symbols:
+ symbols[node] = []
+ symbols[node].append(symbol)
+
+with open(sys.argv[1], "w") as outfile:
+ local_token = False
+ if abi in symbols:
+ outfile.writelines(f"DPDK_{abi} {{\n\tglobal:\n\n")
+ for symbol in sorted(symbols[abi]):
+ outfile.writelines(f"\t{symbol};\n")
+ outfile.writelines("\n")
+ if not local_token:
+ outfile.writelines("\tlocal: *;\n")
+ local_token = True
+ outfile.writelines("};\n")
+ del symbols[abi]
+ for key in sorted(symbols.keys()):
+ outfile.writelines(f"DPDK_{key} {{\n\tglobal:\n\n")
+ for symbol in sorted(symbols[key]):
+ outfile.writelines(f"\t{symbol};\n")
+ outfile.writelines("\n")
+ if not local_token:
+ outfile.writelines("\tlocal: *;\n")
+ local_token = True
+ outfile.writelines(f"}} DPDK_{abi};\n")
+ del symbols[key]
diff --git a/buildtools/meson.build b/buildtools/meson.build
index 4e2c1217a2..b745e9afa4 100644
--- a/buildtools/meson.build
+++ b/buildtools/meson.build
@@ -16,6 +16,7 @@ else
py3 = ['meson', 'runpython']
endif
echo = py3 + ['-c', 'import sys; print(*sys.argv[1:])']
+gen_version_map = py3 + files('gen-version-map.py')
list_dir_globs = py3 + files('list-dir-globs.py')
map_to_win_cmd = py3 + files('map_to_win.py')
sphinx_wrapper = py3 + files('call-sphinx-build.py')
diff --git a/drivers/meson.build b/drivers/meson.build
index 05391a575d..d5fe3749c4 100644
--- a/drivers/meson.build
+++ b/drivers/meson.build
@@ -5,8 +5,6 @@ if is_ms_compiler
subdir_done()
endif
-fs = import('fs')
-
# Defines the order of dependencies evaluation
subdirs = [
'common',
diff --git a/lib/meson.build b/lib/meson.build
index ce92cb5537..4db1864241 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -110,6 +110,7 @@ endif
default_cflags = machine_args
default_cflags += ['-DALLOW_EXPERIMENTAL_API']
default_cflags += ['-DALLOW_INTERNAL_API']
+default_cflags += ['-DRTE_EXPORT_SYMBOL(a)=']
if cc.has_argument('-Wno-format-truncation')
default_cflags += '-Wno-format-truncation'
@@ -254,6 +255,9 @@ foreach l:libraries
include_directories: includes,
dependencies: static_deps)
+ version_map = '@0@/@1@/version.map'.format(meson.current_source_dir(), l)
+ lk_deps = []
+
if not use_function_versioning or is_windows
# use pre-build objects to build shared lib
sources = []
@@ -262,10 +266,19 @@ foreach l:libraries
# for compat we need to rebuild with
# RTE_BUILD_SHARED_LIB defined
cflags += '-DRTE_BUILD_SHARED_LIB'
- endif
- version_map = '@0@/@1@/version.map'.format(meson.current_source_dir(), l)
- lk_deps = [version_map]
+ # POC: generate version.map if absent.
+ if not fs.is_file(version_map)
+ map_file = custom_target(libname + '_map',
+ command: [gen_version_map, '@OUTPUT@', '@INPUT@'],
+ input: sources,
+ output: '@0@_version.map'.format(libname))
+ version_map = map_file.full_path()
+ lk_deps += [map_file]
+ else
+ lk_deps += [version_map]
+ endif
+ endif
if is_ms_linker
def_file = custom_target(libname + '_def',
diff --git a/lib/net/rte_arp.c b/lib/net/rte_arp.c
index 22af519586..cd0f49a7a9 100644
--- a/lib/net/rte_arp.c
+++ b/lib/net/rte_arp.c
@@ -47,3 +47,4 @@ rte_net_make_rarp_packet(struct rte_mempool *mpool,
return mbuf;
}
+RTE_EXPORT_SYMBOL(rte_net_make_rarp_packet)
diff --git a/lib/net/rte_ether.c b/lib/net/rte_ether.c
index f59c20289d..9d02db1676 100644
--- a/lib/net/rte_ether.c
+++ b/lib/net/rte_ether.c
@@ -17,6 +17,7 @@ rte_eth_random_addr(uint8_t *addr)
addr[0] &= (uint8_t)~RTE_ETHER_GROUP_ADDR; /* clear multicast bit */
addr[0] |= RTE_ETHER_LOCAL_ADMIN_ADDR; /* set local assignment bit */
}
+RTE_EXPORT_SYMBOL(rte_eth_random_addr)
void
rte_ether_format_addr(char *buf, uint16_t size,
@@ -25,6 +26,7 @@ rte_ether_format_addr(char *buf, uint16_t size,
snprintf(buf, size, RTE_ETHER_ADDR_PRT_FMT,
RTE_ETHER_ADDR_BYTES(eth_addr));
}
+RTE_EXPORT_SYMBOL(rte_ether_format_addr)
static int8_t get_xdigit(char ch)
{
@@ -153,3 +155,4 @@ rte_ether_unformat_addr(const char *s, struct rte_ether_addr *ea)
rte_errno = EINVAL;
return -1;
}
+RTE_EXPORT_SYMBOL(rte_ether_unformat_addr)
diff --git a/lib/net/rte_net.c b/lib/net/rte_net.c
index 0c32e78a13..9a1bc3fb7d 100644
--- a/lib/net/rte_net.c
+++ b/lib/net/rte_net.c
@@ -306,6 +306,7 @@ rte_net_skip_ip6_ext(uint16_t proto, const struct rte_mbuf *m, uint32_t *off,
}
return -1;
}
+RTE_EXPORT_SYMBOL(rte_net_skip_ip6_ext)
/* parse mbuf data to get packet type */
uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
@@ -601,3 +602,4 @@ uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
return pkt_type;
}
+RTE_EXPORT_SYMBOL(rte_net_get_ptype)
diff --git a/lib/net/rte_net_crc.c b/lib/net/rte_net_crc.c
index dd93d43c2e..03be816509 100644
--- a/lib/net/rte_net_crc.c
+++ b/lib/net/rte_net_crc.c
@@ -417,6 +417,7 @@ void rte_net_crc_free(struct rte_net_crc *crc)
{
rte_free(crc);
}
+RTE_EXPORT_SYMBOL(rte_net_crc_free)
RTE_VERSION_SYMBOL(25, uint32_t, rte_net_crc_calc, (const void *data, uint32_t data_len,
enum rte_net_crc_type type)
diff --git a/lib/net/version.map b/lib/net/version.map
deleted file mode 100644
index f4dd673fa3..0000000000
--- a/lib/net/version.map
+++ /dev/null
@@ -1,23 +0,0 @@
-DPDK_25 {
- global:
-
- rte_eth_random_addr;
- rte_ether_format_addr;
- rte_ether_unformat_addr;
- rte_net_crc_calc;
- rte_net_crc_free;
- rte_net_crc_set_alg;
- rte_net_get_ptype;
- rte_net_make_rarp_packet;
- rte_net_skip_ip6_ext;
-
- local: *;
-};
-
-DPDK_26 {
- global:
-
- rte_net_crc_calc;
- rte_net_crc_set_alg;
-
-} DPDK_25;
diff --git a/meson.build b/meson.build
index 8436d1dff8..dfb4cb3aee 100644
--- a/meson.build
+++ b/meson.build
@@ -13,10 +13,11 @@ project('DPDK', 'c',
meson_version: '>= 0.57'
)
+fs = import('fs')
+
# check for developer mode
developer_mode = false
if get_option('developer_mode').auto()
- fs = import('fs')
developer_mode = fs.exists('.git')
else
developer_mode = get_option('developer_mode').enabled()
--
2.48.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC v2 1/2] eal: add new function versioning macros
2025-03-06 12:50 ` [RFC v2 1/2] " David Marchand
2025-03-06 12:50 ` [RFC v2 2/2] build: generate symbol maps David Marchand
@ 2025-03-06 15:45 ` Andre Muezerie
1 sibling, 0 replies; 6+ messages in thread
From: Andre Muezerie @ 2025-03-06 15:45 UTC (permalink / raw)
To: David Marchand
Cc: dev, thomas, bruce.richardson, Tyler Retzlaff, Jasvinder Singh
On Thu, Mar 06, 2025 at 01:50:20PM +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,
>
> Documentation has been updated though it needs some polishing.
> The experimental macro has not been tested.
>
> Signed-off-by: David Marchand <david.marchand@redhat.com>
> ---
> Changes since RFC v1:
> - renamed and prefixed macros,
> - reindented in prevision of second patch,
>
> ---
> doc/guides/contributing/abi_versioning.rst | 130 ++++-----------------
> lib/eal/include/rte_function_versioning.h | 27 +++++
> lib/net/rte_net_crc.c | 30 ++---
> 3 files changed, 57 insertions(+), 130 deletions(-)
>
I like the proposal. Having a single macro able to handle different linkers
is clearly a good step forward.
Acked-by: Andre Muezerie <andremue@linux.microsoft.com>
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2025-03-06 15:45 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-03-05 21:23 [RFC] eal: add new function versioning macros David Marchand
2025-03-06 2:57 ` Patrick Robb
2025-03-06 10:23 ` Bruce Richardson
2025-03-06 12:50 ` [RFC v2 1/2] " David Marchand
2025-03-06 12:50 ` [RFC v2 2/2] build: generate symbol maps David Marchand
2025-03-06 15:45 ` [RFC v2 1/2] eal: add new function versioning macros Andre Muezerie
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).