Why is ffmpeg linking with too many libraries? - ffmpeg

I'm trying to build ffmpeg shared libraries for decoding video on Linux systems. The build is done on Arch Linux but the resulting shared libraries need to be as portable as possible.
Fortunately, the functionality built into ffmpeg is sufficient, so I don't want to link with any libraries that might or might not be present on the target system. I'm taking libvdpau as an example of an unwanted dependency here, but there are many more.
Here's what I tried:
$ git clone https://git.ffmpeg.org/ffmpeg.git --branch n4.3.1 --depth 1
$ cd ffmpeg
$ mkdir build
$ cd build
$ ../configure \
--enable-shared \
--disable-programs --disable-doc \
--disable-avdevice --disable-postproc --disable-avfilter \
--disable-autodetect
$ make -j9
Notice --disable-autodetect which should prevent autodetection of which dependencies happen to be present on the build system.
And yet, when I check the resulting libraries, all of them have dependencies that I didn't ask for. For example:
$ ldd libavcodec/libavcodec.so
linux-vdso.so.1 (0x00007ffcd73cd000)
libswresample.so.3 => /usr/lib/libswresample.so.3 (0x00007fba1e45c000)
libavutil.so.56 => /usr/lib/libavutil.so.56 (0x00007fba1e1a7000)
libm.so.6 => /usr/lib/libm.so.6 (0x00007fba1e061000)
libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007fba1e03f000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007fba1de76000)
libsoxr.so.0 => /usr/lib/libsoxr.so.0 (0x00007fba1ddf4000)
libva-drm.so.2 => /usr/lib/libva-drm.so.2 (0x00007fba1dded000)
libva.so.2 => /usr/lib/libva.so.2 (0x00007fba1ddc0000)
libva-x11.so.2 => /usr/lib/libva-x11.so.2 (0x00007fba1ddb8000)
libvdpau.so.1 => /usr/lib/libvdpau.so.1 (0x00007fba1ddb3000) <- Why is this here?
libX11.so.6 => /usr/lib/libX11.so.6 (0x00007fba1dc72000)
libdrm.so.2 => /usr/lib/libdrm.so.2 (0x00007fba1dc5d000)
libmfx.so.1 => /usr/lib/libmfx.so.1 (0x00007fba1dc4d000)
libdl.so.2 => /usr/lib/libdl.so.2 (0x00007fba1dc47000)
/usr/lib64/ld-linux-x86-64.so.2 (0x00007fba1f971000)
libgomp.so.1 => /usr/lib/libgomp.so.1 (0x00007fba1dc06000)
libXext.so.6 => /usr/lib/libXext.so.6 (0x00007fba1dbf1000)
libXfixes.so.3 => /usr/lib/libXfixes.so.3 (0x00007fba1dbe8000)
libxcb.so.1 => /usr/lib/libxcb.so.1 (0x00007fba1dbbc000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007fba1d9df000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007fba1d9c5000)
libXau.so.6 => /usr/lib/libXau.so.6 (0x00007fba1d9c0000)
libXdmcp.so.6 => /usr/lib/libXdmcp.so.6 (0x00007fba1d9b8000)
I also tried listing all disable flags explicitly, such as --disable-vdpau, but this didn't change anything; libvdpau.so.1 is still listed in ldd output.
Maybe they are just being linked, but not actually used? readelf -d seems to point in that direction:
$ ls */*.so
libavcodec/libavcodec.so libavutil/libavutil.so libswscale/libswscale.so
libavformat/libavformat.so libswresample/libswresample.so
$ readelf -d */*.so | grep 'Shared library:' | sort -u
0x0000000000000001 (NEEDED) Shared library: [libavcodec.so.58]
0x0000000000000001 (NEEDED) Shared library: [libavutil.so.56]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x0000000000000001 (NEEDED) Shared library: [libm.so.6]
0x0000000000000001 (NEEDED) Shared library: [libpthread.so.0]
0x0000000000000001 (NEEDED) Shared library: [libswresample.so.3]
This is a nice and tight set of dependencies, the way I actually want them to be.
So maybe the build system is stupid and always adds all detected libraries to the linker command line anyway? To suppress this, I tried adding --extra-ldflags=-Wl,--as-needed, but that doesn't seem to have any effect either.
The resulting linker command line looks like this (abridged):
$ make -n libavcodec/libavcodec.so.58
gcc \
-shared \
-Wl,-soname,libavcodec.so.58 \
-Wl,-Bsymbolic \
-Wl,--version-script,libavcodec/libavcodec.ver \
-Llibavcodec -Llibavdevice -Llibavfilter -Llibavformat -Llibavresample -Llibavutil -Llibpostproc -Llibswscale -Llibswresample \
-Wl,--as-needed \
-Wl,-z,noexecstack \
-Wl,--warn-common \
-Wl,-rpath-link=:libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil:libavresample \
-Wl,--as-needed \
-o libavcodec/libavcodec.so.58 \
[...all .o files...] \
-lswresample -lavutil -pthread -lm -lm -pthread -lm
It looks like -Wl,--as-needed was already added anyway.
Interestingly, -Llibavdevice is also listed, even though I passed --disable-avdevice --disable-postproc --disable-avfilter to the configure script. That might be a clue: it would pick up my system's libavdevice, which of course comes with far more dependencies. Still I'd expect -Wl,--as-needed to trim these unbuilt dependencies out as well.
Where do these dependencies come from, and how do I get rid of them?

Of course: when running ldd, any dependencies on other ffmpeg libraries are resolved to those installed on my system. And those have many more dependencies. So the problem wasn't with the build system, but rather with the way I was inspecting the resulting output.
Setting LD_LIBRARY_PATH reveals the true list of transitive dependencies:
$ LD_LIBRARY_PATH=libavcodec:libavformat:libavutil:libswresample:libswscale ldd libavcodec/libavcodec.so
linux-vdso.so.1 (0x00007fffaab0f000)
libswresample.so.3 => libswresample/libswresample.so.3 (0x00007f9a8f213000)
libavutil.so.56 => libavutil/libavutil.so.56 (0x00007f9a8ef6c000)
libm.so.6 => /usr/lib/libm.so.6 (0x00007f9a8ede0000)
libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007f9a8edbe000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f9a8ebf5000)
/usr/lib64/ld-linux-x86-64.so.2 (0x00007f9a906e1000)

Related

Linking libs into a binary in order to make it static on most of linux environment

I am currently searching for a way to make a binary that I just compiled, a portable binary for most of all linux environment. I was considering Ermine but it's not free (looking for a free solution right now) and tried also with Statifier but didn't work either. Here is the details on the binary I am trying to make static and portable:
sirius#blackb0x:~/MINING/ARIONUM/ariominer/build$ ldd /home/sirius/MINING/ARIONUM/ariominer/build/ariominer
linux-vdso.so.1 => (0x00007fff692fe000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fdfee979000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fdfee775000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fdfee45f000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fdfee159000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fdfedf42000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fdfedb79000)
/lib64/ld-linux-x86-64.so.2 (0x00007fdfeeb97000)
If some could tell me how exactly to link all the libs to the binary so it could run easy on all or almost all linux env (2.6.18 kernels to latest) it would be very appreciated.
Thanks
Rebuild the program and its dependencies from source (while having LIBS set to -static), and make sure to pass --enable-static --disable-shared to their configure scripts.
If that doesn't work, just compile it on a very old machine and provide binaries for glibc and musl.

Static linking against openmp

I am building a shared object on Ubuntu 16.04 which uses libgomp. My goal is to make this final object as portable as possible, by static linking anything not normally in a base distribution (using docker ubuntu or alpine images as a reference baseline). I've been able to do this with my other dependencies pretty easily, but I'm hung up on libgomp.
I can link just fine with the -fopenmp option, and get a dynamic link:
# ldd *.so
linux-vdso.so.1 => (0x00007fff01df4000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9ba59db000)
libgomp.so.1 => /usr/lib/x86_64-linux-gnu/libgomp.so.1 (0x00007f9ba57b9000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f9ba55a3000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f9ba5386000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9ba4fbc000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9ba6516000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f9ba4db8000)
But if I naively add -static before -fopenmp I get:
relocation R_X86_64_32 against `__TMC_END__' can not be used when making a shared object; recompile with -fPIC
Fair enough; with my other dependencies I've just built from source to enable PIC and any other options I needed. When I try to do the same with libgomp, though, I'm not having any luck. I checked out gcc 5.5 from http://gcc.gnu.org/svn/gcc, and tried building from the gcc/libgomp folder. There is a configure script already generated, but running it returns:
./config.status: line 1486: ./../../config-ml.in: No such file or directory
OK, apparently this has something to do with multilibrary support, which I don't believe I need. Running ./configure --help shows that there is an --enable-multilib option with no obvious default, but setting --enable-multilib=no or --disable-multilib still returns the same error. I've also tried running autoreconf -fiv to regenerate the configure script, but I get this error:
configure.ac:5: error: Please use exactly Autoconf 2.64 instead of 2.69.
If I explicitly install and use autoreconf2.64, I get this one:
configure.ac:65: error: Autoconf version 2.65 or higher is required
What am I missing?
What I was missing was the fact that libgomp is not buildable separate from the rest of gcc. It was just a matter of going up a level and running the whole build with -fPIC enabled:
export CFLAGS="-O3 -fPIC"
export CXXFLAGS="-O3 -fPIC"
./configure --disable-multilib --enable-languages=c,c++
make
make install
That gave me a copy of libgomp.a in /usr/local/lib64 ready for linking in to my shared object.
Follow up:
While this worked, at least in a test environment, after the comments above from Jim Cownie we decided to just disable OpenMP support from our library for now.

Build statically linked binary with waf

I'm trying to build a smbclient binary from the latest source using static linking so it can be portable. I'm doing this on a RHEL 7 machine with all the configure dependencies installed already.
I tried the following but ldd still says the binary has dynamic dependencies.
# wget https://www.samba.org/samba/ftp/samba-latest.tar.gz
# tar -zxvf samba-latest.tar.gz
# cd samba-4.5.1/
# ./configure
# make SHARED=0 CC='gcc -static'
# ldd /root/samba-4.5.1/bin/default/source4/client/smbclient4
linux-vdso.so.1 => (0x00007fff3ebb1000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fb7bf35d000)
libcmdline-credentials-samba4.so => /root/samba-4.5.1/bin/shared/private/libcmdline-credentials-samba4.so (0x00007fb7bf159000)
libsmbclient-raw-samba4.so => /root/samba-4.5.1/bin/shared/private/libsmbclient-raw-samba4.so (0x00007fb7bef0e000)
libtalloc.so.2 => /root/samba-4.5.1/bin/shared/private/libtalloc.so.2 (0x00007fb7bed04000)
libsamba-credentials.so.0 => /root/samba-4.5.1/bin/shared/libsamba-credentials.so.0 (0x00007fb7beaef000)
libsamba-errors.so.1 => /root/samba-4.5.1/bin/shared/libsamba-errors.so.1 (0x00007fb7be7a0000)
libsamba-hostconfig.so.0 => /root/samba-4.5.1/bin/shared/libsamba-hostconfig.so.0 (0x00007fb7be56f000)
libsamba-security-samba4.so => /root/samba-4.5.1/bin/shared/private/libsamba-security-samba4.so (0x00007fb7be34b000)
...
I'm not sure if this is because Samba now uses WAF for builds or not. So I'm looking for help on this.

Trying to build static CGO executable with oracle libraries on Linux/Ubuntu

I have already searched for some days, tried several suggestions but none helped. At the moment I just want to create a small Go snippet which connects to an Oracle Database. While everything works by using normal go build and invoking the resulting dynamic linked application, I am stuck when I try to run the static compiler. I already have build other projects statically (even with CGO) without problems, but here gcc is not finding the oracle library. Maybe someone has a hint?
Error during build:
host link: "gcc" "-m64" "-gdwarf-2" "-o" "/tmp/go-build319417544/command-line-arguments/_obj/exe/a.out" "-static" "/tmp/go-link-116023228/000000.o" "/tmp/go-link-116023228/000001.o" "/tmp/go-link-116023228/000002.o" "/tmp/go-link-116023228/go.o" "-g" "-O2" "-g" "-O2" "-lpthread" "-g" "-O2" "-L/usr/lib/oracle/12.1/client64/lib" "-lclntsh" "-static"
/home/hannes/.gvm/gos/go1.5/pkg/tool/linux_amd64/link: running gcc failed: exit status 1
/usr/bin/ld: cannot find -lclntsh
collect2: error: ld returned 1 exit status
Build command
CGO_ENABLED=1 go build -work -x -ldflags " -v -linkmode external -extldflags -static" ${MAIN_SRC}
Application code:
package main
/*
// #cgo CFLAGS: -I/usr/lib/oracle/12.1/client64/include
// #cgo LDFLAGS: -L/usr/lib/oracle/12.1/client64/lib -lclntsh
*/
import "C"
import (
"fmt"
"database/sql"
_ "github.com/mattn/go-oci8"
"time"
)
func main(){
db, err := sql.Open("oci8", "...")
...
}
I have checked with
dconfig -p | grep cln
libkadm5clnt_mit.so.9 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libkadm5clnt_mit.so.9
libclntshcore.so.12.1 (libc6,x86-64) => /usr/lib/oracle/12.1/client64/lib/libclntshcore.so.12.1
libclntshcore.so (libc6,x86-64) => /usr/lib/oracle/12.1/client64/lib/libclntshcore.so
libclntsh.so.12.1 (libc6,x86-64) => /usr/lib/oracle/12.1/client64/lib/libclntsh.so.12.1
libclntsh.so (libc6,x86-64) => /usr/lib/oracle/12.1/client64/lib/libclntsh.so
The dynamic build executable (just "go build oracle_test.go) has everything it needs:
ldd oracle_test
linux-vdso.so.1 => (0x00007ffeac867000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f083ef82000)
libclntsh.so.12.1 => /usr/lib/oracle/12.1/client64/lib/libclntsh.so.12.1 (0x00007f083bfc5000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f083bbfa000)
/lib64/ld-linux-x86-64.so.2 (0x00005615b32e8000)
libmql1.so => /usr/lib/oracle/12.1/client64/lib/libmql1.so (0x00007f083b984000)
libipc1.so => /usr/lib/oracle/12.1/client64/lib/libipc1.so (0x00007f083b606000)
libnnz12.so => /usr/lib/oracle/12.1/client64/lib/libnnz12.so (0x00007f083aefb000)
libons.so => /usr/lib/oracle/12.1/client64/lib/libons.so (0x00007f083acb6000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f083aab2000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f083a7a9000)
libnsl.so.1 => /lib/x86_64-linux-gnu/libnsl.so.1 (0x00007f083a58f000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f083a387000)
libaio.so.1 => /lib/x86_64-linux-gnu/libaio.so.1 (0x00007f083a184000)
libclntshcore.so.12.1 => /usr/lib/oracle/12.1/client64/lib/libclntshcore.so.12.1 (0x00007f0839c12000)
I also tried to put/export CGO_LDFLAGS and/ord LD_LIBRARY_PATH environment variable, which didn't help.
Pkg-config shows as well the library
pkg-config --libs oci8
-L/usr/lib/oracle/12.1/client64/lib -lclntsh
After looking for the static libraries, I have installed the complete oracle database package and now I have some more files in lib folder:
ls /usr/lib/oracle/12.1/client64/lib/lib*.a
-rw-r--r-- 1 1424782 /usr/lib/oracle/12.1/client64/lib/libagent12.a
-rw-r--r-- 1 1962088 /usr/lib/oracle/12.1/client64/lib/libasmclnt12.a
-rw-r--r-- 1 2187864 /usr/lib/oracle/12.1/client64/lib/libasmclntsh12.a
-rw-r--r-- 1 11386 /usr/lib/oracle/12.1/client64/lib/libasmperl12.a
-rw-r--r-- 1 28454 /usr/lib/oracle/12.1/client64/lib/libavstub12.a
-rw-r--r-- 1 7408322 /usr/lib/oracle/12.1/client64/lib/libcell12.a
-rw-r--r-- 1 11246008 /usr/lib/oracle/12.1/client64/lib/libclient12.a
-rw-r--r-- 1 0 /usr/lib/oracle/12.1/client64/lib/libclntst12.a
-rw-r--r-- 1 1749282 /usr/lib/oracle/12.1/client64/lib/libclsr12.a
-rw-r--r-- 1 10087032 /usr/lib/oracle/12.1/client64/lib/libcommon12.a
-rw-r--r-- 1 5803698 /usr/lib/oracle/12.1/client64/lib/libcore12.a
-rw-r--r-- 1 6051402 /usr/lib/oracle/12.1/client64/lib/libctx12.a
-rw-r--r-- 1 1201840 /usr/lib/oracle/12.1/client64/lib/libctxc12.a
-rw-r--r-- 1 56964 /usr/lib/oracle/12.1/client64/lib/libctxs12.a
...snipped...
As seen the one file has zero size, so I had to run $ORACLE_HOME/bin/genclntst to generate libclntst12.a.
Use $ORACLE_HOME/bin/relink tool to generate the library named libclntst.a
The st stands for static library. Oracle client is not usually shipped with this file. The
Try to link your app with this library. You will most probably find many symbols missing.
Use nm tool to find the source of those missing symbols.
In case of 11gR2 this command worked for me:
/usr/bin/c++ -Wall -ggdb3 -fPIC \
CMakeFiles/opassgen.dir/opassgen.cpp.o \
CMakeFiles/opassgen.dir/dbutils.cpp.o \
CMakeFiles/opassgen.dir/common.cpp.o \
CMakeFiles/opassgen.dir/crypto.cpp.o \
n.o -o opassgen \
-rdynamic -static-libgcc -L. -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic \
/home/oracle/ivan/openssl-1.0.1t/libcrypto.a \
/oracle/u01/db/11.2.0.4/lib/libclntst11.a \
/oracle/u01/db/11.2.0.4/lib/libippdcmerged.a \
/oracle/u01/db/11.2.0.4/lib/libippsmerged.a \
-Wl,--whole-archive libtrotl.a -Wl,--no-whole-archive \
-lpthread -ldl
Static linking requires, that you resolve all the dependencies manually.
In this example libclntst11.a depends on symbols from libippdcmerged.a and libippsmerged.a.
On older Oracle version the whole database was build and linked using Intel's ICC compiler. So when linking Oracle's client lib statically you also had to add some static libs from ICC's runtime.

"Clean" linking with dynamic libraries (no LD_LIBRARY_PATH)?

The title pretty much sums it up. I'm trying to link a dynamic library when compiling another. Here is my (short and humble) makefile:
all: src/
gcc -fPIC -shared src/argsort.c -o libsort.so -lm
gcc -fPIC -shared src/kdtree.c -o libkdtree.so -L./ -lsort -lm
So I'm first building libsort.so. It works great. Then I'm building libkdtree.so which uses libsort.so. The compilation goes great too, but libkdtree.so is unusable: here is the output of ldd for libkdtree.so:
ldd libkdtree.so
linux-vdso.so.1 => (0x00007fffcc54e000)
libsort.so => not found
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f6b3c532000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6b3c172000)
/lib64/ld-linux-x86-64.so.2 (0x00007f6b3ca57000)
If I add the directory to LD_LIBRARY_PATH, it works, the link is there and I can use the library. Is LD_LIBRARY_PATH really meant to be changed like that ? Do I have no other choice ? I mean to share my code with others, and I'd like not to ask people to go add something to their .bashrc just so they can run my code. I think I don't understand what -L does, since I thought it would manually link the library.
Can someone either give me the magic method I overlooked, or crush my dreams of clean linking ?
Thank you !

Resources