clangshared-librariesalpine-linuxdynamic-linkingmusl

Unable to dynamically link on Alpine


For some reason I am unable to dynamically link an so-file to a minimal C application built with clang in an Alpine container - when building on my Archlinux, it works.

The application is shown here below in all its glory, and is just calling a random function in a shared library. I have tried with other libraries as well with the same result.

main.c

#include <jansson.h>
#include <stdio.h>

int main(void) {
  printf("Hello, world!\n");

  // call a random function from a shared lib
  json_object();
  return 0;
}

I have a very basic Makefile:

CC = clang
CFLAGS = -Wall -Wextra -O2
DEPS = $(wildcard *.h)
SRC = $(wildcard *.c)
OBJ = $(SRC:.c=.o)
TARGET = app

%.o: %.c $(DEPS)
    $(CC) -c -o $@ $< $(CFLAGS)

$(TARGET): $(OBJ)
    $(CC) -v -L /usr/lib -ljansson -o $@ $^ $(CFLAGS)

.PHONY: clean

clean:
    rm -f $(OBJ) $(TARGET)

I start a Docker container with the following command and install the needed packages:

docker run --rm -it -v $PWD:/work -w /work alpine

apk update
apk add clang make jansson-dev

Finally, I will try building, but it fails as shown:

/work # make
clang -c -o main.o main.c -Wall -Wextra -O2
clang -v -L /usr/lib -ljansson -o app main.o -Wall -Wextra -O2
Alpine clang version 17.0.5
Target: x86_64-alpine-linux-musl
Thread model: posix
InstalledDir: /usr/bin
Configuration file: /etc/clang17/x86_64-alpine-linux-musl.cfg
System configuration file directory: /etc/clang17
Found candidate GCC installation:
/usr/bin/../lib/gcc/x86_64-alpine-linux-musl/13.2.1 Selected GCC installation:
/usr/bin/../lib/gcc/x86_64-alpine-linux-musl/13.2.1 Candidate multilib: .;@m64
Selected multilib: .;@m64
 "/usr/bin/ld" -pie -z now -z relro --hash-style=gnu --build-id --eh-frame-hdr
-m elf_x86_64 -dynamic-linker /lib/ld-musl-x86_64.so.1 -o app /usr/lib/Scrt1.o
/usr/lib/crti.o /usr/bin/../lib/gcc/x86_64-alpine-linux-musl/13.2.1/crtbeginS.o
-L/usr/lib -L/usr/bin/../lib/gcc/x86_64-alpine-linux-musl/13.2.1
-L/usr/bin/../lib/gcc/x86_64-alpine-linux-musl/13.2.1/../../../../x86_64-alpine-linux-musl/lib
-L/lib -L/usr/lib --as-needed -ljansson main.o -lssp_nonshared -lgcc --as-needed
-lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed
/usr/bin/../lib/gcc/x86_64-alpine-linux-musl/13.2.1/crtendS.o /usr/lib/crtn.o
/usr/bin/ld: main.o: in function `main':
main.c:(.text+0xe): undefined reference to `json_object'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [Makefile:12: app] Error 1

And just to be sure, the so-file is where I expect it.

/work # ls /usr/lib/libjansson*
/usr/lib/libjansson.so         /usr/lib/libjansson.so.4       /usr/lib/libjansson.so.4.14.0

If I do the same on my Archlinux or inside an Ubuntu container, it works as expected.

What have I missed?


Solution

  • What have I missed?

    Your link command is wrong: libraries should follow objects which reference them. Move -ljansson after $^ on the link line.

    You might ask: why does it work on other distributions?

    Compilers can be configured differently, and whether the default configuration passes --as-needed to the linker probably matters here.