srt: [BUG] Linux: static linking apps fails

Background I’m building libsrt on Ubuntu 16.04. I’m building in a Docker build process, since it gives me a clean and easily reproducible build environment - but this should be irrelevant to this bug report. I’ve been building FFmpeg in this way without libsrt for years - adding libsrt has been this weekend’s challenge. I’m building for linux x86_64 and also cross compiling for win_x86_64 and osx_x86_64 - which My final goal is to build a static FFmpeg for all three platforms including libsrt.

Describe the bug I’ve built OpenSSL 1.0.2 as static from git branch OpenSSL_1_0_2-stable.

I wand to build libsrt as static, but after make has built libsrt.a it builds some applications, and those do not link correctly (they need -ldl appending to the link command).

cmake \
    -G \"Unix Makefiles\" \
    -DCMAKE_INSTALL_PREFIX=${prefix} \
    -DENABLE_C_DEPS=ON \
    -DENABLE_SHARED=OFF \
    -DENABLE_STATIC=ON
make VERBOSE=1
[ 91%] Linking CXX executable srt-live-transmit
/usr/bin/cmake -E cmake_link_script CMakeFiles/srt-live-transmit.dir/link.txt --verbose=1
/usr/bin/g++   --static -static -I/opt/ffbuild/include    -DENABLE_LOGGING=1 -Wall -Wextra -O3 -DNDEBUG   -L/opt/ffbuild/lib -static CMakeFiles/srt-live-transmit.dir/apps/srt-live-transmit.cpp.o CMakeFiles/srtsupport_virtual.dir/apps/apputil.cpp.o CMakeFiles/srtsupport_virtual.dir/apps/logsupport.cpp.o CMakeFiles/srtsupport_virtual.dir/apps/socketoptions.cpp.o CMakeFiles/srtsupport_virtual.dir/apps/transmitmedia.cpp.o CMakeFiles/srtsupport_virtual.dir/apps/uriparser.cpp.o CMakeFiles/srtsupport_virtual.dir/apps/verbose.cpp.o  -o srt-live-transmit -rdynamic libsrt.a -ldl -Wl,-Bstatic -lssl -lcrypto -Wl,-Bdynamic -lpthread 
/opt/ffbuild/lib/libcrypto.a(dso_dlfcn.o): In function `dlfcn_globallookup':
dso_dlfcn.c:(.text+0x11): undefined reference to `dlopen'
dso_dlfcn.c:(.text+0x24): undefined reference to `dlsym'
dso_dlfcn.c:(.text+0x2f): undefined reference to `dlclose'
/opt/ffbuild/lib/libcrypto.a(dso_dlfcn.o): In function `dlfcn_bind_func':
dso_dlfcn.c:(.text+0x334): undefined reference to `dlsym'
dso_dlfcn.c:(.text+0x3db): undefined reference to `dlerror'
/opt/ffbuild/lib/libcrypto.a(dso_dlfcn.o): In function `dlfcn_bind_var':
dso_dlfcn.c:(.text+0x454): undefined reference to `dlsym'
dso_dlfcn.c:(.text+0x4fb): undefined reference to `dlerror'
/opt/ffbuild/lib/libcrypto.a(dso_dlfcn.o): In function `dlfcn_load':
dso_dlfcn.c:(.text+0x569): undefined reference to `dlopen'
dso_dlfcn.c:(.text+0x5cb): undefined reference to `dlclose'
dso_dlfcn.c:(.text+0x603): undefined reference to `dlerror'
/opt/ffbuild/lib/libcrypto.a(dso_dlfcn.o): In function `dlfcn_pathbyaddr':
dso_dlfcn.c:(.text+0x69f): undefined reference to `dladdr'
dso_dlfcn.c:(.text+0x709): undefined reference to `dlerror'
/opt/ffbuild/lib/libcrypto.a(dso_dlfcn.o): In function `dlfcn_unload':
dso_dlfcn.c:(.text+0x762): undefined reference to `dlclose'
collect2: error: ld returned 1 exit status
make[2]: *** [srt-live-transmit] Error 1
CMakeFiles/srt-live-transmit.dir/build.make:109: recipe for target 'srt-live-transmit' failed
make[2]: Leaving directory '/opt/ffbuild/src/srt/build'
CMakeFiles/Makefile2:105: recipe for target 'CMakeFiles/srt-live-transmit.dir/all' failed
make[1]: Leaving directory '/opt/ffbuild/src/srt/build'
Makefile:127: recipe for target 'all' failed
make[1]: *** [CMakeFiles/srt-live-transmit.dir/all] Error 2
make: *** [all] Error 2

Workaround Since I only want libsrt.a I can work around by installing the required component (libsrt.a, srt.pc and various .h files) - but it’s a bit ugly.

make VERBOSE=1 srt_static \
 && mkdir -p ${prefix}/include/srt/win \
 && install -m 644 -c libsrt.a ${prefix}/lib/libsrt.a \
 && install -m 644 -c srt.pc ${prefix}/lib/pkgconfig/srt.pc \
 && install -m 644 -c version.h ${prefix}/include/srt/version.h \
 && install -m 644 -c ../srtcore/srt.h ${prefix}/include/srt/srt.h \
 && install -m 644 -c ../srtcore/platform_sys.h ${prefix}/include/srt/platform_sys.h \
 && install -m 644 -c ../srtcore/srt4udt.h ${prefix}/include/srt/srt4udt.h \
 && install -m 644 -c ../srtcore/logging_api.h ${prefix}/include/srt/logging_api.h

(plus some other .h files if I’m cross-compiling for Windows)

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 26 (1 by maintainers)

Most upvoted comments

Ok, I think I got it. I manually changed the libcrypto.pc from above, as:

Libs: -L${libdir} -lcrypto -lz -ldl

thus showing the private libs as public libs, and it worked!

This is NOT the right way to do this, but I think it clearly shows the config/cmake process is not picking up the static (i.e. private) internal libs when it is finding OpenSSL. Coming through FFMPEG configure, it is clear they pass --static and append the Libs.Private when necessary.

I’m way way over my head now. Thanks for listening 😃

Unfortunately, this issue doesn’t solved. I encountered it again when I try to link static openssl library.

After go through this issue, https://github.com/Haivision/srt/issues/1172#issuecomment-680326684 already gives perfect summary. However, it doesn’t help without modify libcrypto.pc which is not supposed to do. https://github.com/Haivision/srt/issues/1172#issuecomment-683852463 also summaries the problem even though it’s mostly talked about zlib, not openssl itself.
So I’d like to talk a bit more to explain and try to help solve this issue.

Reproduction

It can be reproduced on my debian11(gcc (Debian 10.2.1-6) 10.2.1 20210110) as well as Ubuntu 20.04.4 LTS(gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0).

# build openssl 3.0.3 static only libraries for the testing
$ git clone https://github.com/openssl/openssl.git
$ cd openssl && git checkout openssl-3.0.3
$ ./Configure --prefix=$(pwd)/build no-shared && make -j && make install 

# build srt with static openssl
$ git clone https://github.com/Haivision/srt.git
$ cd srt && mkdir -p _build && cd _build
$ PKG_CONFIG_PATH=../../openssl/build/lib64/pkgconfig cmake .. -DENABLE_SHARED=OFF -DENABLE_STATIC=ON
$ cmake --build . -j
/usr/bin/ld: dso_dlfcn.c:(.text+0x578): undefined reference to `dlclose'
/usr/bin/ld: dso_dlfcn.c:(.text+0x5b1): undefined reference to `dlerror'
/usr/bin/ld: /root/workspace/openssl/build/lib64/libcrypto.a(libcrypto-lib-dso_dlfcn.o): in function `dlfcn_pathbyaddr':
/usr/bin/ld: dso_dlfcn.c:(.text+0x6e3): undefined reference to `dlerror'
/usr/bin/ld: /root/workspace/openssl/build/lib64/libcrypto.a(libcrypto-lib-dso_dlfcn.o): in function `dlfcn_unload':
dso_dlfcn.c:(.text+0x744): undefined reference to `dlclose'
collect2: error: ld returned 1 exit status
gmake[2]: *** [CMakeFiles/srt-file-transmit.dir/build.make:114: srt-file-transmit] Error 1
gmake[1]: *** [CMakeFiles/Makefile2:199: CMakeFiles/srt-file-transmit.dir/all] Error 2
gmake[1]: *** Waiting for unfinished jobs....
/usr/bin/ld: /root/workspace/openssl/build/lib64/libcrypto.a(libcrypto-lib-dso_dlfcn.o): in function `dlfcn_globallookup':
dso_dlfcn.c:(.text+0x13): undefined reference to `dlopen'
/usr/bin/ld: dso_dlfcn.c:(.text+0x26): undefined reference to `dlsym'
/usr/bin/ld: dso_dlfcn.c:(.text+0x31): undefined reference to `dlclose'
/usr/bin/ld: /root/workspace/openssl/build/lib64/libcrypto.a(libcrypto-lib-dso_dlfcn.o): in function `dlfcn_bind_func':
dso_dlfcn.c:(.text+0x387): undefined reference to `dlsym'
/usr/bin/ld: dso_dlfcn.c:(.text+0x47e): undefined reference to `dlerror'
/usr/bin/ld: /root/workspace/openssl/build/lib64/libcrypto.a(libcrypto-lib-dso_dlfcn.o): in function `dlfcn_load':
dso_dlfcn.c:(.text+0x4f1): undefined reference to `dlopen'
/usr/bin/ld: dso_dlfcn.c:(.text+0x578): undefined reference to `dlclose'
/usr/bin/ld: dso_dlfcn.c:(.text+0x5b1): undefined reference to `dlerror'
/usr/bin/ld: /root/workspace/openssl/build/lib64/libcrypto.a(libcrypto-lib-dso_dlfcn.o): in function `dlfcn_pathbyaddr':
dso_dlfcn.c:(.text+0x672): undefined reference to `dladdr'
/usr/bin/ld: dso_dlfcn.c:(.text+0x6e3): undefined reference to `dlerror'
/usr/bin/ld: /root/workspace/openssl/build/lib64/libcrypto.a(libcrypto-lib-dso_dlfcn.o): in function `dlfcn_unload':
dso_dlfcn.c:(.text+0x744): undefined reference to `dlclose'
collect2: error: ld returned 1 exit status
gmake[2]: *** [CMakeFiles/srt-live-transmit.dir/build.make:114: srt-live-transmit] Error 1
gmake[1]: *** [CMakeFiles/Makefile2:172: CMakeFiles/srt-live-transmit.dir/all] Error 2
[100%] Linking CXX executable srt-tunnel
/usr/bin/ld: /root/workspace/openssl/build/lib64/libcrypto.a(libcrypto-lib-dso_dlfcn.o): in function `dlfcn_globallookup':
dso_dlfcn.c:(.text+0x13): undefined reference to `dlopen'
/usr/bin/ld: dso_dlfcn.c:(.text+0x26): undefined reference to `dlsym'
/usr/bin/ld: dso_dlfcn.c:(.text+0x31): undefined reference to `dlclose'
/usr/bin/ld: /root/workspace/openssl/build/lib64/libcrypto.a(libcrypto-lib-dso_dlfcn.o): in function `dlfcn_bind_func':
dso_dlfcn.c:(.text+0x387): undefined reference to `dlsym'
/usr/bin/ld: dso_dlfcn.c:(.text+0x47e): undefined reference to `dlerror'
/usr/bin/ld: /root/workspace/openssl/build/lib64/libcrypto.a(libcrypto-lib-dso_dlfcn.o): in function `dlfcn_load':
dso_dlfcn.c:(.text+0x4f1): undefined reference to `dlopen'
/usr/bin/ld: dso_dlfcn.c:(.text+0x578): undefined reference to `dlclose'
/usr/bin/ld: dso_dlfcn.c:(.text+0x5b1): undefined reference to `dlerror'
/usr/bin/ld: /root/workspace/openssl/build/lib64/libcrypto.a(libcrypto-lib-dso_dlfcn.o): in function `dlfcn_pathbyaddr':
dso_dlfcn.c:(.text+0x672): undefined reference to `dladdr'
/usr/bin/ld: dso_dlfcn.c:(.text+0x6e3): undefined reference to `dlerror'
/usr/bin/ld: /root/workspace/openssl/build/lib64/libcrypto.a(libcrypto-lib-dso_dlfcn.o): in function `dlfcn_unload':
dso_dlfcn.c:(.text+0x744): undefined reference to `dlclose'
collect2: error: ld returned 1 exit status
gmake[2]: *** [CMakeFiles/srt-tunnel.dir/build.make:114: srt-tunnel] Error 1
gmake[1]: *** [CMakeFiles/Makefile2:226: CMakeFiles/srt-tunnel.dir/all] Error 2
gmake: *** [Makefile:136: all] Error 2

Analysis

https://github.com/Haivision/srt/issues/1172#issuecomment-680326684 already tells us that it caused by missed -ldl when linking. But doesn libcrypto.pc really miss the -ldl? Let’s take a look.

$ cat openssl/build/lib64/pkgconfig/libcrypto.pc
prefix=/root/workspace/openssl/build
exec_prefix=${prefix}
libdir=${exec_prefix}/lib64
includedir=${prefix}/include
enginesdir=${libdir}/engines-3

Name: OpenSSL-libcrypto
Description: OpenSSL cryptography library
Version: 3.0.3
Libs: -L${libdir} -lcrypto
Libs.private: -ldl -pthread
Cflags: -I${includedir}

We can see that the -ldl is in Libs.private section instead of Libs. According to manual of pkg-config,

Libs.private: This line should list any private libraries in use. Private libraries are libraries which are not exposed through your library, but are needed in the case of static linking.

manual of pkg-config also tells us another option for static linking:

–static Output libraries suitable for static linking. That means including any private libraries in the output. This relies on proper tagging in the .pc files, else a too large number of libraries will ordinarily be output.

OK, it seems that we need to use pkg-config --static <xxx> instead of pkg-config <xxx> for static linking. If we try it on command line, it looks like this:

$ PKG_CONFIG_PATH=../../openssl/build/lib64/pkgconfig pkg-config --libs openssl
-lssl -lcrypto
$ PKG_CONFIG_PATH=../../openssl/build/lib64/pkgconfig pkg-config --libs --static openssl
-lssl -lcrypto -ldl -pthread

Got it! Now another problem is that srt uses cmake build system, how can we add --static in cmake configurations? Actually https://github.com/Haivision/srt/issues/1172#issuecomment-683836490 has already metioned it, cmake FindPkgConfig tells us that

The following variables may be set upon return. Two sets of values exist: One for the common case (<XXX> = <prefix>) and another for the information pkg-config provides when called with the --static option (<XXX> = <prefix>_STATIC).

Here’s a simply change to verify it:

git diff CMakeLists.txt
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9644a10..0b4f9f8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -345,6 +345,7 @@ if (ENABLE_ENCRYPTION)
                # fall back to find_package method otherwise
                if (USE_OPENSSL_PC)
                        pkg_check_modules(SSL ${SSL_REQUIRED_MODULES})
+                      set(SSL_LIBRARIES ${SSL_STATIC_LIBRARIES})
                endif()
                if (SSL_FOUND)
                        # We have some cases when pkg-config is improperly configured

And run the build again

$ cd srt/_build/
$ PKG_CONFIG_PATH=../../openssl/build/lib64/pkgconfig cmake .. -DENABLE_SHARED=OFF -DENABLE_STATIC=ON
$ cmake --build . -j 
[ 90%] Linking CXX executable srt-live-transmit
[ 92%] Linking CXX executable srt-tunnel
[ 94%] Linking CXX executable srt-file-transmit
[ 96%] Built target srt-live-transmit
[ 98%] Built target srt-tunnel
[100%] Built target srt-file-transmit

Now it works correctly!

Conclusion

PR to solve this issue: https://github.com/Haivision/srt/pull/2369 It has been tested on my ffmpeg-build integration.
Hope it can help! Thanks!

Let me reopen this issue to consider in the future then. It will still require some research to see if SRT’s CMake can/should detect extra dependencies of OpenSSL or any other statically built library.

Summary

When OpenSSL is built statically, building SRT apps fails, as there is an additional dependency zlib that has to be linked. Specifying zlib in -DWITH_EXTRALIBS does not help due to the wrong order (zlib is included before OpenSSL?).

Steps to reproduce

Not clear. Try to link statically built OpenSSL? Or follow ffmpeg-build-script.