In Alpine Linux 3.15 they added a patch to musl
that adds the qsort_r()
function. The patch was removed in Alpine Linux 3.16.
Without this patch programs that need qsort_r()
(e.g. gcc
) won't work.
In place of applying the patch directly, you can use abuild
see this gist for options: https://gist.github.com/x-yuri/aa6db295cd56f757537f756bc390b1df
Related discussion: https://gitlab.alpinelinux.org/alpine/aports/-/issues/10960#note_240872
a.sh
:
. /etc/os-release
verlte() {
[ "$1" = "$(echo -e "$1\n$2" | sort -V | head -n1)" ]
}
verlt() {
[ "$1" = "$2" ] && return 1 || verlte "$1" "$2"
}
vergte() {
! verlt "$1" "$2"
}
vergt() {
! verlte "$1" "$2"
}
apk add build-base curl
if vergte "$VERSION_ID" 3.15.0 && verlt "$VERSION_ID" 3.16.0; then
gcc /host/b.c -o b
gcc -D_GNU_SOURCE /host/c.c -o c
fi
curl https://musl.libc.org/releases/musl-$1.tar.gz -o musl-$1.tar.gz
tar xf musl-$1.tar.gz
cd musl-$1
if [ "${2-}" ]; then
curl https://gitlab.alpinelinux.org/alpine/aports/-/raw/3.15-stable/main/musl/qsort_r.patch -o qsort_r.patch
patch -p1 < qsort_r.patch
fi
./configure
make install
cd /
gcc host/a.c || true
if vergte "$VERSION_ID" 3.15.0 && verlt "$VERSION_ID" 3.16.0; then
./b o i a
./c o i a || true
fi
a.c
:
int main(void)
{
return 0;
}
b.c
:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int
cmpstringp(const void *p1, const void *p2)
{
/* The actual arguments to this function are "pointers to
pointers to char", but strcmp(3) arguments are "pointers
to char", hence the following cast plus dereference. */
return strcmp(*(const char **) p1, *(const char **) p2);
}
int
main(int argc, char *argv[])
{
if (argc < 2) {
fprintf(stderr, "Usage: %s <string>...\n", argv[0]);
exit(EXIT_FAILURE);
}
qsort(&argv[1], argc - 1, sizeof(char *), cmpstringp);
for (int j = 1; j < argc; j++)
puts(argv[j]);
exit(EXIT_SUCCESS);
}
c.c
:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int
cmpstringp(const void *p1, const void *p2, void *arg)
{
/* The actual arguments to this function are "pointers to
pointers to char", but strcmp(3) arguments are "pointers
to char", hence the following cast plus dereference. */
return strcmp(*(const char **) p1, *(const char **) p2);
}
int
main(int argc, char *argv[])
{
if (argc < 2) {
fprintf(stderr, "Usage: %s <string>...\n", argv[0]);
exit(EXIT_FAILURE);
}
qsort_r(&argv[1], argc - 1, sizeof(char *), cmpstringp, NULL);
for (int j = 1; j < argc; j++)
puts(argv[j]);
exit(EXIT_SUCCESS);
}
$ docker run --rm -itv $PWD:/host alpine:3.15 sh -eux host/a.sh 1.2.2
...
+ gcc host/a.c
Error relocating /usr/lib/libctf.so.0: qsort_r: symbol not found
collect2: error: ld returned 127 exit status
+ true
...
+ ./b o i a
a
i
o
+ ./c o i a
Error relocating ./c: qsort_r: symbol not found
+ true
$ docker run --rm -itv $PWD:/host alpine:3.15 sh -eux host/a.sh 1.2.2 fix
...
+ gcc host/a.c
...
+ ./b o i a
a
i
o
+ ./c o i a
a
i
o
$ docker run --rm -itv $PWD:/host alpine:3.14 sh -eux host/a.sh 1.2.2
$ docker run --rm -itv $PWD:/host alpine:3.16 sh -eux host/a.sh 1.2.3