2

I am trying to make a static executable with CMake 3.15. I am building on Alpine Linux (hence with musl), and currently, my executable's ldd output is:

# ldd my_executable
    /lib/ld-musl-x86_64.so.1 (0x7fc6f7977000)
    libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x7fc6f65b3000)
    libc.musl-x86_64.so.1 => /lib/ld-musl-x86_64.so.1 (0x7fc6f7977000)
    libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x7fc6f659f000)

I can set target_link_options(my_executable PRIVATE -static-libgcc -static-libstdc++), and they got linked statically:

# ldd my_executable
    /lib/ld-musl-x86_64.so.1 (0x7fc6f7977000)
    libc.musl-x86_64.so.1 => /lib/ld-musl-x86_64.so.1 (0x7fc6f7977000)

But I can't manage to get musl to link statically. I tried (with clean builds, to make sure that the configure step starts from zero):

  1. Adding -static to target_link_options above.
  2. set(CMAKE_EXE_LINKER_FLAGS "-static") before the call to add_executable(my_executable ...)
  3. Adding -static to target_link_libraries(my_executable lib1 lib2 -static)

When I run CMake in VERBOSE=1 mode, it always ends the linking command with:

... -Wl,-Bdynamic -ldl -lrt -lm -lpthread

I believe that this is my issue: I want to get rid of that -Bdynamic. What am I missing? Is this -Bdynamic coming from one of my dependencies? I build them all from sources as static (.a) libraries, so how could they be linking libc dynamically? Or would I need to patch them all to add -static when I build them?

JonasVautherin
  • 7,297
  • 6
  • 49
  • 95
  • For option 2, the variable should be `CMAKE_EXE_LINKER_FLAGS`. Also, to be clear about option 3, this means you tried `target_link_libraries(my_executable -static)`? It may help to remove your CMake cache between each build attempt. – Kevin May 14 '20 at 14:11
  • Sorry, typo. And yes, I tried what you said, let me edit. I also made clean builds, but I can try again. – JonasVautherin May 14 '20 at 14:16
  • Edited, @squareskittles! Note: I added `-static` at the end (after the libraries). Does it matter? – JonasVautherin May 14 '20 at 16:09
  • While you can do `set(CMAKE_SHARED_LIBRARY_LINK_DYNAMIC_C_FLAGS "")` It's better to do it [like here](https://stackoverflow.com/questions/16991225/cmake-and-static-linking). – KamilCuk May 14 '20 at 20:44
  • nice! `LINK_SEARCH_START_STATIC` and `LINK_SEARCH_END_STATIC` allowed me to have now all but ld-musl linked statically. I don't know why, but this one is still dynamic. – JonasVautherin May 14 '20 at 22:02

1 Answers1

5

As hinted by KamilCuk's comment, the answer here seems to have the solution. Still, I'm not doing exactly the same, therefore I'll keep this answer, too.

For the target executable that I want statically linked:

add_executable(my_executable main.cpp)

I had to set the following properties/options:

set_target_properties(my_executable PROPERTIES LINK_SEARCH_START_STATIC ON)
set_target_properties(my_executable PROPERTIES LINK_SEARCH_END_STATIC ON)

target_link_options(my_executable PRIVATE -static-libgcc -static-libstdc++ -static)

Some notes:

  • LINK_SEARCH_*_STATIC were useful to remove -Bdynamic from the linking command.
  • I never managed to remove -ldl from the linking command, but it seems like dl did not get link eventually (presumably because it is not used).
  • ldd was not enough to verify that my_executable is statically linked. readelf -l my_executable showed that it does not have an INTERP header, and there is currently no such thing as a dynamic binary without it (using musl).
  • It turns out that checking whether a binary is statically linked or not is not so straightforward :-).
JonasVautherin
  • 7,297
  • 6
  • 49
  • 95