The autobuilder system of the Buildroot project (which rebuilds packages
for multiple architectures and toolchains) reported an issue when
building s6-rc for ARM using uclibc-ng statically [1]. The build
ends as follows:

In function `strnlen':
strnlen.c:(.text+0x0): multiple definition of `strnlen'
first defined here

It means that skalibs v2.6.3.0 has been compiled with its internal variant of
strnlen(), as the configuration script failed to detect the one provided by

When trying to recreate the build issue, using a tweaked version of
skalibs/configure gives us more information:

-D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -Isrc/include 
-Werror=implicit-function-declaration -Werror=implicit-int -Werror=pointer-sign 
-Werror=pointer-arith -Wno-unused-value -Wno-parentheses -D_LARGEFILE_SOURCE 
-D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -pipe -Wall -std=c99 
-fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables 
-Wa,--noexecstack -ffunction-sections -fdata-sections -O2 -fomit-frame-pointer 
-D_FILE_OFFSET_BITS=64 -Os -static -o trystrnlen.o -c src/sysdeps/trystrnlen.c
src/sysdeps/trystrnlen.c: In function 'main':
src/sysdeps/trystrnlen.c:10:10: error: implicit declaration of function 
'strnlen' [-Werror=implicit-function-declaration]
   return strnlen("/", 1) ;
cc1: some warnings being treated as errors

The MAN page for strnlen() from glibc states that _POSIX_C_SOURCE should be
defined and uclibc-ng seems to behave the same. The _POSIX_C_SOURCE is indeed
passed by Buildroot to the cross-compiler when build the program.

But since v2.6.3.0, skalibs/src/sysdeps/trystrnlen.c clears the definition of
_POSIX_C_SOURCE. Allowing it again solves the issue: the uclibc-ng version of
strnlen() is detected, skalibs internal variant is disabled and s6-rc-update
statically links with uclibc-ng like a charm.

I tried to statically link with musl and surprisingly, there is no linking error
even though the skalibs variant of strnlen() is enabled and musl provides it

$ grep STRNLEN 
$ grep STRNLEN 

One of the differences between uclibc-ng and musl is that uclibc-ng, as glibc,
defines strnlen() using libc_hidden_def(strnlen), which results in the following
when inspecting symbols:

$ objdump -t ~/build/demo-s6/qemu/x86/musl/static/staging/lib/libc.a | grep 
00000000         *UND*  00000000 strnlen
00000000         *UND*  00000000 strnlen
strnlen.o:     format de fichier elf32-i386
00000000 l    df *ABS*  00000000 strnlen.c
00000000 l    d  .text.strnlen  00000000 .text.strnlen
00000000 g     F .text.strnlen  00000033 strnlen
00000000         *UND*  00000000 strnlen
$ objdump -t ~/build/demo-s6/qemu/x86/uclibc/static/staging/usr/lib/libc.a | 
grep strnlen
00000000         *UND*  00000000 __GI_strnlen
00000000         *UND*  00000000 __GI_strnlen
strnlen.os:     format de fichier elf32-i386
00000000 l    df *ABS*  00000000 strnlen.c
00000000 l    d  .text.__GI_strnlen     00000000 .text.__GI_strnlen
00000000 g     F .text.__GI_strnlen     00000034 .hidden __GI_strnlen
00000000 g     F .text.__GI_strnlen     00000034 strnlen
00000000         *UND*  00000000 __GI_strnlen

Would this difference explains why there is no redefinition linking error with
musl, or am I missing something?

What is the reason for clearing _POSIX_C_SOURCE from trystrnlen.c?




Reply via email to