Using cmake to include libheif as an external dependency

I’m trying to include libheif into my project using cmake. Libheif is more complicated than what I’ve worked with before because it requires you to externally build and include libde265.

Attempt #1:

I have used vcpkg to export pre-built binary packages, this creates a directory called libheif which includes everything here:

+---bin
> heif.dll
> libde265.dll
> libx265.dll
> libx265.pdb
>
+---debug
> +---bin
> > heif.dll
> > libde265.dll
> > libx265.dll
> > libx265.pdb
> >
> \---lib
> > heif.lib
> > libde265.lib
> > libx265.lib
> > x265-static.lib
> >
> \---pkgconfig
> libheif.pc
> x265.pc
>
+---include
> > x265.h
> > x265_config.h
> >
> +---libde265
> > de265.h
> >
> \---libheif
> heif.h
>
+---lib
> > heif.lib
> > libde265.lib
> > libx265.lib
> > x265-static.lib
> >
> \---pkgconfig
> libheif.pc
> x265.pc
>
+---share
> +---libde265
> > copyright
> > libde265Config-debug.cmake
> > libde265Config-release.cmake
> > libde265Config.cmake
> > libde265ConfigVersion.cmake
> > vcpkg_abi_info.txt
> >
> +---libheif
> > > copyright
> > > libheif-config-debug.cmake
> > > libheif-config-release.cmake
> > > libheif-config-version.cmake
> > > libheif-config.cmake
> > > vcpkg_abi_info.txt
> > >
> > \---.vs
> > ProjectSettings.json
> > slnx.sqlite
> >
> \---x265
> copyright
> vcpkg_abi_info.txt
>
\---tools
+---libde265
> dec265.exe
> enc265.exe
> libde265.dll
>
\---x265
x265.exe

(There were more headers, I removed them because one illustrates the point) I put the folder libheif in my external folder in my project. Then in CMakeLists.txt I have tried using

target_link_libraries(my_project ${CMAKE_SOURCE_DIR}/external/libheif/lib/heif)

that then fails looking for heif.obj, file that is not there. It does find the dlls though.

After that failed, I tried again, this time using the .cmake files in the share directory:

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/external/libheif/share/libheif)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/external/libheif/share/libde265)

include(libheif-config)
include(libde265Config)

This I get unresolved external symbol when trying to use anything in libheif.

Attempt #2:
I tried including libeheif by adding it as a submodule:

git submodule add https://github.com/strukturag/libheif.git external/libheif

and then in CMakeLists.txt I added:

include_directories(external/libheif/include)
include_directories(external/libheif/include/libheif)
include_directories(external/libheif/include/libde265)
add_subdirectory(external/libheif)
target_link_libraries(my_project libheif)

This results in unresolved external symbols whenever I try to use anything in the libheif library.

Other information

  • The only successful thing I have been able to do is include the headers directory so intellisence recognizes when I #include <heif.h>
  • I have looked all over on how to include dll and libraries, but all the results either need me to use the cmake GUI, which I am not sure I can because I’m working on this project with other people and I want to make sure it works on their computer without having to use the cmake GUI.
  • Same with just using vcpkg to include it, I dont want my teammates to have to use it as well, I need to just use CMakeLists.txt
  • This tutorial would be helpful but the generate stuff is above my head and I couldnt find what it meant by generate. It might be a rabbit hole I loose days of work to.
  • I am working on Windows 10, I will eventually need to make it so it can build on OSX but I’m just trying to get it to work on windows for now.

I am trying to understand why each of these approaches failed. I would rather go down the path of attempt #2 and add the project as a submodule because I feel like that is better for down the road when I need to make it compile for mac as well.
I would really appreciate any help or suggestions, I feel like I am missing something important here.

Thank you for your time,
Char

This should probably have had the .lib added.

These are config.cmake files and are meant to be consumed via find_package(libheif) and find_package(libde265). Does this work better?

Shouldn’t he use the libheif target defined in its config file instead of the .lib?

Yes, but using include rather than find_package probably isn’t helping here.

thank you, I just need pointer on how to do it using the git submodule way, my attempts are just to show that I am trying to get it done- though its probably very wrong. When you say config file- do you mean CPPLINT.cfg?
that file just has

set noparent
filter=-,+build/include_what_you_use

Thank you.

No. I mean the libheif-config.cmake file. I recommend reading the find_package documentation.

Sadly your suggestion didnt work
Adding .lib to the end just made it so it couldnt even find the lib files (as oppose to not finding obj files which actually arent there)
and using find_package, I get unresolved external symbol on where I used a libheif function (it didnt link in libheif)
Am I missing something after find_package?
Is this problem too difficult? I am worried im in over my head.

I feel like @craig.scott’s book or the CMake Tutorial are good places to start here.

Basically, using find_package will make the imported targets from libheif available you can then use those targets in target_link_libraries. It’d look something like target_link_libraries(mytarget PRIVATE heif::heif) depending on the target names actually used and whether you want PRIVATE or PUBLIC linking semantics.

Thank you for your suggestions thus far. Ive learned a lot today so far.
I decided to use the module LibFindMacros I found recommended on this cmake tutorial

include(LibFindMacros)
libfind_pkg_check_modules(HEIF_PKGCONF libheif)

find_path(HEIF_INCLUDE_DIR
    NAMES libheif/heif.h
    HINTS ${HEIF_PKGCONF_INCLUDE_DIRS} ${HEIF_PKGCONF_INCLUDEDIR}
    PATH_SUFFIXES heif
)

find_library(HEIF_LIBRARY
    NAMES libheif heif
    HINTS ${HEIF_PKGCONF_LIBRARY_DIRS} ${HEIF_PKGCONF_LIBDIR}
    DOC "Libraries to link against for HEIF Support"
)

set(HEIF_PROCESS_LIBS HEIF_LIBRARY)
set(HEIF_PROCESS_INCLUDES HEIF_INCLUDE_DIR)
libfind_process(HEIF)

if(HEIF_INCLUDE_DIR)
  set(heif_config_file "${HEIF_INCLUDE_DIR}/libheif/heif_version.h")
  if(EXISTS ${heif_config_file})
      file(STRINGS
           ${heif_config_file}
           TMP
           REGEX "#define LIBHEIF_VERSION.*$")
      string(REGEX MATCHALL "[0-9.]+" LIBHEIF_VERSION ${TMP})
  endif()
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(HEIF
    REQUIRED_VARS
        HEIF_INCLUDE_DIR
        HEIF_LIBRARY
    VERSION_VAR
        LIBHEIF_VERSION
)

message("this isHEIF_LIBRARIES: ${HEIF_LIBRARIES}")
target_link_libraries(my_project ${HEIF_LDFLAGS} ${HEIF_LIBRARIES})
target_link_libraries(my_project ${HEIF_LDFLAGS} ${HEIF_LIBRARIES})

but then I get

  WARNING: MISSING PACKAGE
  We could not find development headers for HEIF.  Do you have the necessary
  dev package installed? This package is NOT REQUIRED and you may ignore this
  warning but by doing so you may miss some functionality of my_project.


  Relevant CMake configuration variables:

    HEIF_INCLUDE_DIR=<not found>
    HEIF_LIBRARY=<not found>

I cant find mention of dev files anywhere. I assume that its okay that I just downloaded the libheif from github because thats what Krita (an open source painting app that also uses libheif) is doing. Maybe im not setting locations right?

sigh

You really make your life more complicated than it needs to be.
The correct file is the libheif-config.cmake. This is the file that will be found in CMake with find_package command.

Please read that file and the ones that it includes. And read the find_package documentation. This will also tell you how you can tell CMake the location of that base directory if it cannot find ot itself.

I think I need to give up using any of the pre-compiled binaries. I need to compile it from the cloned repo in my project.

I got stuck trying to get it to use the libheif-config.cmake when I ran into this

CMake Warning at CMakeLists.txt:71 (find_package):
  Could not find a configuration file for package "libheif" that is
  compatible with requested version "1.10.0.0".  

  The following configuration files were considered but not accepted:

    C:/Users/me/Desktop/my_project/my_project_api/external/libheif/share/libheif/libheif-config.cmake, version: 1.10.0.0 (32bit) 

Though my cmake is:

if (WIN32)
    find_package(libheif 1.10.0.0 PATHS "external/libheif/share/libheif")
    target_link_libraries(hop_studio_api libheif)
    target_link_libraries(hop_studio_cli libheif)
endif(WIN32)

I read that it might be because the cmake compiler thinks its 64 bit, and the library is 32, but i put it in the WIN32 conditional, so I have no idea why it isnt accepting this config file.

I am going to go back to the complicated way haha I think its for the better. I need to make a findHEIF.cmake module and make it so that it can compile the source code.

WIN32 is also set for 64bit Windows. Let’s call it legacy.

But the " (32bit)" part of the reported libheif version looks strange. What happens when you do NOT request a specific version by removing 1.10.0.0 from the find_package() call

same thing except the error says:

  Could not find a configuration file for package "libheif" that is
  compatible with requested version "". 

I thought it was the lack of version that was tripping it up, so i put the exact version that the config file is.

That “(32bit)” is saying that the binaries found are compiled for 32bit, but you have a 64bit toolchain. You’ll need pre-compiled x64 binaries or to target 32bit compilation yourself.

if i do that will it build for mac too?

If you build it as part of your project, you’d be much happier. If you download pre-compiled binaries, you’ll need to download the right ones depending on the compiler in use.

yeah I ran into issues even when rebuilding it for 64 bit- it just said can open lib file.
Anyways, now I’m working with the source github, by adding a submodule.
This is now in my CMakeLists.txt

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake/Modules/)
find_package(libheif)
target_link_libraries(my_project libheif::libheif)
target_link_libraries(my_project libheif::libheif)
message("this is HEIF_LIBRARIES: ${HEIF_LIBRARIES}")

and then in cmake/modules I have Findlibheif.cmake, I got it from here
but then i run into

-- Could NOT find libheif (missing: libheif_LIBRARY libheif_INCLUDE_DIR)

and then later on

  Target "my_project" links to target "libheif::libheif" but the target
  was not found.  Perhaps a find_package() call is missing for an IMPORTED
  target, or an ALIAS target is missing?

So when building with the source do i need to compile the library first by using add_library and then use find_package so it can find the .lib files? What search terms should I use to look up this problem? I have tried “writing a find module to build from source” among others, but I cant find useful information

If you’re using a submodule, you should not be using find_package on it. I really recommend Craig’s book (though I don’t know which chapter(s) handle this) or the CMake Tutorial I linked earlier.

I got the book, I got from it that i need to use add_subdirectory, which was the first thing I tried (if you look in the first post here). Alas. The book is too general to help with any other problems. I read the chapter 7 on subdirectories, it doesnt touch on anything that is causing none of the dependencies in libheif not getting found. I also tried adding libde265 as a submodule and adding that subdirectory, yet it still doesnt get detected.
i think a little empathy in this community will go a long way. Instead of taking a bit of time to understand my question you point me to massive amounts of general information. I got the book, it told me something i already know, and the tutorial was also very general. One shouldnt have to be an expert to use cmake, or ask for help.

Including projects as binaries into your project is not trivial and can require some more knowledge of CMake to get things right. As for adding a subproject to your own, that can also be tough. It really depends on:

  • how complicated the subproject is
  • whether the developers of that project considered vendoring like this
  • whether you have to also prepare that project for use by your consumers as well (if SDK; embedded into a complete application is way easier).

These things are not “oh, here’s what you need” kinds of questions, unfortunately. I pointed you to the documentation of the commands you need (find_package), but this started an X/Y problem or some other misunderstanding with other questions along the way. I pointed you to the book and tutorial as a place to start learning more about CMake, not as a “these have your answer already printed” kind of response.