Using cmake to include libheif as an external dependency

Dealing with dependencies is, unfortunately, often a frustrating experience. It often comes down to how well those dependencies have been written for consumption by other projects. In order to help you move forward, I’ve put together a minimal demo project which shows how to use FetchContent to download libheif and add it to your project. It includes a stub executable that links to the libheif library to verify that it works. I’ve verified that this works for me on both Windows 10 (64-bit) and macOS (see additional info further below for the latter).

CMakeLists.txt:

cmake_minimum_required(VERSION 3.14)
project(heifexample LANGUAGES C)

include(FetchContent)
FetchContent_Declare(libheif
    GIT_REPOSITORY https://github.com/strukturag/libheif.git
    GIT_TAG 7976e1858a857e33200cd33d01689fd040de6d3d  # master
)
FetchContent_MakeAvailable(libheif)

# Add things that libheif neglects to add
target_include_directories(heif INTERFACE
    $<BUILD_INTERFACE:${libheif_BINARY_DIR}>
    $<BUILD_INTERFACE:${libheif_SOURCE_DIR}>
)
# Work around libheif mishandling how to link to gdk-pixbuf-2.0
if(UNIX AND TARGET pixbufloader-heif)
    find_package(PkgConfig)
    pkg_check_modules(GDKPIXBUF2 gdk-pixbuf-2.0)
    # We shouldn't need to do this, but libheif adds the wrong library variable and that requires
    # us to add the library directory so that the library is found at link time
    target_link_directories(pixbufloader-heif PRIVATE ${GDKPIXBUF2_LIBRARY_DIRS})
endif()

add_executable(exampleapp main.c)
target_link_libraries(exampleapp PRIVATE heif)

main.c:

#include <libheif/heif.h>
#include <stddef.h>

int main()
{
    struct heif_context* ctx = heif_context_alloc();
    return ctx == NULL;
}

On macOS, you may need to add /usr/local to your CMAKE_PREFIX_PATH depending on how your system is set up. I had to do that for it to find gdk-pixbuf-2.0 which is provided by homebrew on my system. The following set of steps show how I did that in my testing with the above example:

cd path/to/my/source/dir
mkdir build
cd build
cmake -G Ninja -DCMAKE_PREFIX_PATH=/usr/local ..

Notes

In the above example, I’ve used FetchContent instead of git submodules. You could use submodules instead if you wanted to, in which case you’d need to call add_subdirectories() instead of the two FetchContent_... calls. You’d have to work out the relevant directories in the target_include_directories() call as well, since those are provided by FetchContent_MakeAvailable() in my example.

If you prefer to build against a binary libheif installed somewhere on your system already, that is also possible. I had it working on macOS using pkg-config, but it seemed a bit fragile. I doubt it would work for Windows either since pkg-config is frequently not installed/available on that platform. You could also potentially use find_package() to find it, but on my macOS system, homebrew did not install the files needed for this.

With the above example, I saw that on Windows a lot of the sub-dependencies like Libde265, Rav1, aom, etc, were not found. The readme for libheif talks about how to set things up for these dependencies, so I’ll leave that for you to work through. You may want to follow up with the libheif project itself for how to resolve those if you can’t get it working on your own.

Regarding my book, take a look through Chapter 28: External Content, specifically Section 28.2: FetchContent. It gets fairly involved (because dependencies are hard and a lot can go wrong), but it covers the essentials behind what the above example is doing. For background info on the topics others have mentioned in this discussion, you may also want to take a look at Chapter 24: Finding Things, but my above example doesn’t use anything from that chapter since it is building the libheif dependency from source.

1 Like

Holy moly Craig! You really pulled through! I really appreciate the help, I am obviously new to this and was feeling overwhelmed, but your answer is more than what I could have hoped for! Thank you! I feel like this is the super VIP way to get the external dependency vs ExternalProject.
This really answers all my questions! I defiantly will be reading up the right chapters this time to learn more and include the examples.
Humbly,
Char

Old thread but it may help other:

We did not add yet the VERSION checks. That will be done for the next release as there are quite a few ABI changes in libHEIF since 1.7.0