cmake: newlib linking flags -lc and -lgcc circular dependency

Fixes: #28650

Linking with newlib now defines the following linker flags as:
```
${CMAKE_C_LINKER_WRAPPER_FLAG}${CMAKE_LINK_LIBRARY_FLAG}c
${CMAKE_C_LINKER_WRAPPER_FLAG}${CMAKE_LINK_LIBRARY_FLAG}gcc
c
```

This is needed because when linking with newlib on aarch64, then libgcc
has a link dependency to libc (strchr), but libc also has dependencies
to libgcc.

CMake is capable of handling circular link dependencies for CMake
defined static libraries, which can be further controlled using
`LINK_INTERFACE_MULTIPLICITY`.

However, libc and libgcc are not regular CMake libraries, and is seen as
linker flags by CMake, and thus symbol de-duplications will be
performed.

CMake link options cannot be used, as that will place those libs first
on the linker invocation. -Wl,--start-group is problematic as the
placement of -lc and -lgcc is not guaranteed in case later libraries are
also using -lc / -libbgcc as interface linker flags.

Thus, we resort to use
`${CMAKE_C_LINKER_WRAPPER_FLAG}${CMAKE_LINK_LIBRARY_FLAG}`
as this ensures the uniqueness and thus avoids symbol de-duplication
which means libc will be followed by libgcc, which is finally followed
by libc again.

It would have been possible to use `-lc` directly, but there is a risk
that an externally library is also adding `-lc` and thus de-duplication
and re-arrangement of this flag happens. This risk is in theory also
existing with this fix, but the long nature of this link flag with using
`${CMAKE_C_LINKER_WRAPPER_FLAG}` would likely indicate a similar fix and
thus those libraries will stay in order.

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
This commit is contained in:
Torsten Rasmussen 2020-12-08 10:47:15 +01:00 committed by Anas Nashif
commit da3726006b

View file

@ -30,13 +30,38 @@ endif()
# used by the network stack # used by the network stack
zephyr_compile_definitions(__LINUX_ERRNO_EXTENSIONS__) zephyr_compile_definitions(__LINUX_ERRNO_EXTENSIONS__)
# We are using
# - ${CMAKE_C_LINKER_WRAPPER_FLAG}${CMAKE_LINK_LIBRARY_FLAG}c
# - ${CMAKE_C_LINKER_WRAPPER_FLAG}${CMAKE_LINK_LIBRARY_FLAG}gcc
# - c
# in code below.
# This is needed because when linking with newlib on aarch64, then libgcc has a
# link dependency to libc (strchr), but libc also has dependencies to libgcc.
#
# CMake is capable of handling circular link dependencies for CMake defined
# static libraries, which can be further controlled using LINK_INTERFACE_MULTIPLICITY.
# However, libc and libgcc are not regular CMake libraries, and is seen as linker
# flags by CMake, and thus symbol de-duplications will be performed.
# CMake link options cannot be used, as that will place those libs first on the
# linker invocation. -Wl,--start-group is problematic as the placement of -lc
# and -lgcc is not guaranteed in case later libraries are also using
# -lc / -libbgcc as interface linker flags.
#
# Thus, we resort to use `${CMAKE_C_LINKER_WRAPPER_FLAG}${CMAKE_LINK_LIBRARY_FLAG}`
# as this ensures the uniqueness and thus avoids symbol de-duplication which means
# libc will be followed by libgcc, which is finally followed by libc again.
list(JOIN CMAKE_C_LINKER_WRAPPER_FLAG "" linker_wrapper_string)
zephyr_link_libraries( zephyr_link_libraries(
m m
c "${linker_wrapper_string}${CMAKE_LINK_LIBRARY_FLAG}c"
${LIBC_LIBRARY_DIR_FLAG} # NB: Optional ${LIBC_LIBRARY_DIR_FLAG} # NB: Optional
$<$<BOOL:${CONFIG_NEWLIB_LIBC_FLOAT_PRINTF}>:-u_printf_float> $<$<BOOL:${CONFIG_NEWLIB_LIBC_FLOAT_PRINTF}>:-u_printf_float>
$<$<BOOL:${CONFIG_NEWLIB_LIBC_FLOAT_SCANF}>:-u_scanf_float> $<$<BOOL:${CONFIG_NEWLIB_LIBC_FLOAT_SCANF}>:-u_scanf_float>
gcc # Lib C depends on libgcc. e.g. libc.a(lib_a-fvwrite.o) references __aeabi_idiv # Lib C depends on libgcc. e.g. libc.a(lib_a-fvwrite.o) references __aeabi_idiv
"${linker_wrapper_string}${CMAKE_LINK_LIBRARY_FLAG}gcc"
c
) )
if(CONFIG_NEWLIB_LIBC_NANO) if(CONFIG_NEWLIB_LIBC_NANO)
@ -47,4 +72,3 @@ if(CONFIG_NEWLIB_LIBC_NANO)
-specs=nano.specs -specs=nano.specs
) )
endif() endif()