strukturag / libheif

libheif is an HEIF and AVIF file format decoder and encoder.
Other
1.68k stars 296 forks source link

Static build of heif-convert #767

Open jankais3r opened 1 year ago

jankais3r commented 1 year ago

Hi,

I am trying to create a static build of heif-convert. Apologies if this is a rookie mistake, I am not well versed in the c++ toolchain.

I first tried to use the CMake approach as autogen is deprecated. I followed instructions from #189, but the result was a dynamically linked binary.

$ mkdir build
$ cd build
$ cmake -DBUILD_SHARED_LIBS=OFF ..
$ make
$ file examples/heif-convert
heif-convert: ELF 64-bit LSB pie executable, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=b45e6dcd01374f8a7e03b46221f6559ad36e9e8b, for GNU/Linux 3.2.0, not stripped

I also tried autogen, but the result was the same:

$ ./autogen.sh
$ ./configure --enable-static
$ make
$ file examples/.libs/heif-convert
heif-convert: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=1eb37876e66816492eda3ce886b8fe2c5150533e, for GNU/Linux 3.2.0, with debug_info, not stripped

Could anyone point me to the right direction please?

bradh commented 1 year ago

There are four parts to building a libheif example application such as heif-convert statically:

  1. Having all the dependencies available as static libraries
  2. Ensuring that the static version of those dependencies is selected
  3. Building libheif as a static library
  4. Statically linking the executable

The first part is out-of-scope for this description, but on Linux, you'll typically get that as part of whatever development package (-dev, -devel) is providing the dynamic library. Its possible you might only have a dynamic library of some encoder or decoder library, but if you don't need that, you can turn it off in the CMake build. (Note: On Ubuntu, libde265.a and libdav1d.a are not available in the -dev package. Also, the package for x265 provides libx265.a, but it requires methods in libnuma, which is not available as a static library. If you need those, you'll have to build it yourself.).

Selecting the static library is probably the most painful part. CMake will pick dynamic libraries first (and this is what most people want - its smaller, easier to upgrade in case of bugs, etc), but clearly it isn't always the right answer. So after running cmake .. (or however you are building), you need to adjust the selected version of the libraries. So lets say the CMake configure step finds AOM_LIBRARY as /usr/lib/x86_64-linux-gnu/libaom.so, you need to change it to /usr/lib/x86_64-linux-gnu/libaom.a. Repeat this process for all the shared libraries. One way to do this is to use ccmake .. (note: two c) and toggle advanced mode. Or if you know the paths, you can specify them on the cmake command line (e.g. -DAOM_LIBRARY=/usr/lib/x86_64-linux-gnu/libaom.a.

Building libheif as a static library is the easiest part - there is an option BUILD_SHARED_LIBS that should be set to OFF. Again, you can use ccmake among other methods.

The last part requires setting CMAKE_EXE_LINKER_FLAGS to include -static. Again, you can use ccmake and toggle advanced options, or another approach if you'd prefer. The "libpixbufloader-heif.so" example only makes sense as a shared object, and needs to be disabled by setting WITH_GDK_PIXBUF to OFF.

I worked through most of it with ccmake, but it will work with a straight command line run. For me, that ended up looking like this:

cmake -DBUILD_SHARED_LIBS=OFF -DCMAKE_EXE_LINKER_FLAGS=-static -DAOM_LIBRARY=/usr/lib/x86_64-linux-gnu/libaom.a -DWITH_GDK_PIXBUF=OFF -DWITH_DAV1D=OFF -DWITH_X265=OFF -DJPEG_LIBRARY_RELEASE=/usr/lib/x86_64-linux-gnu/libjpeg.a -DKVAZAAR_LIBRARY=/usr/local/lib/libkvazaar.a -DLIBDE265_LIBRARY=/home/bradh/coding/libde265/build/libde265/liblibde265.a -DPNG_LIBRARY_RELEASE=/usr/lib/x86_64-linux-gnu/libpng.a -DZLIB_LIBRARY_RELEASE=/usr/lib/x86_64-linux-gnu/libz.a ..

(Note: that has paths you almost certainly won't have, and may not provide all the functionality you need, but the approach remains valid).

The result:

$ file examples/heif-convert 
examples/heif-convert: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=c7b1eae35f6841fa4561c98e8a930b928c6be513, for GNU/Linux 3.2.0, with debug_info, not stripped
$ ./examples/heif-convert /home/bradh/coding/avif-sample-images/fox.profile0.10bpc.yuv420.avif test.png
File contains 1 image
Written to test.png

Note that its pretty easy to build libde265 (which you are likely to want) as a static library - just use the -DBUILD_SHARED_LIBS=OFF option.

Does that meet your needs?

bradh commented 1 year ago

@jankais3r Any thoughts on this?