Skip to content

Instantly share code, notes, and snippets.

@x-yuri
Last active June 10, 2022 20:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save x-yuri/0481799b6375f88d8cfcf8fe9b951a4f to your computer and use it in GitHub Desktop.
Save x-yuri/0481799b6375f88d8cfcf8fe9b951a4f to your computer and use it in GitHub Desktop.
Patching musl

Patching musl

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment