Configuration error when fetching two dependencies when there is a dependency between them

I was hoping to pull in both zeromq and azmq (asio binding) for a personal project. I’m using CMake 3.23 on Windows 10 with Visual Studio 2019 MSVC.

In my project CMake I do this:

FetchContent_Declare(
    zeromq
    GIT_REPOSITORY https://github.com/zeromq/libzmq
    GIT_TAG v4.3.4
    GIT_SHALLOW TRUE
    GIT_PROGRESS TRUE
)
FetchContent_Declare(
    azmq
    GIT_REPOSITORY https://github.com/zeromq/azmq.git
    GIT_TAG v1.0.3
    GIT_SHALLOW TRUE
    GIT_PROGRESS TRUE
)
FetchContent_MakeAvailable(zeromq azmq)

but when CMake tries to configure azmq, it can’t find zeromq.

CMake Error at C:/Program Files/CMake/share/cmake-3.23/Modules/FindPackageHandleStandardArgs.cmake:230 (message):
  Could NOT find ZeroMQ (missing: ZeroMQ_INCLUDE_DIRS ZeroMQ_LIBRARIES)
  (Required is at least version "4.0")
Call Stack (most recent call first):
  C:/Program Files/CMake/share/cmake-3.23/Modules/FindPackageHandleStandardArgs.cmake:594 (_FPHSA_FAILURE_MESSAGE)
  D:/Projects/build-QWar-Desktop_Qt_5_15_1_MSVC2019_64bit-Debug/_deps/azmq-src/config/FindZeroMQ.cmake:77 (find_package_handle_standard_args)
  D:/Projects/build-QWar-Desktop_Qt_5_15_1_MSVC2019_64bit-Debug/_deps/azmq-src/CMakeLists.txt:43 (find_package)


-- Configuring incomplete, errors occurred!
See also "D:/Projects/build-QWar-Desktop_Qt_5_15_1_MSVC2019_64bit-Debug/CMakeFiles/CMakeOutput.log".
See also "D:/Projects/build-QWar-Desktop_Qt_5_15_1_MSVC2019_64bit-Debug/CMakeFiles/CMakeError.log".
CMake process exited with exit code 1.

I was reading here [1] and the example shown was this, which seems like just what I’m doing.

# CORRECT: All details declared first, so they will take priority
FetchContent_Declare(uses_other ...)
FetchContent_Declare(other ...)
FetchContent_MakeAvailable(uses_other other)

Any tips to allow azmq to find zeromq when they’re both fetched dependencies with FetchContent? Or is there something obvious I’ve got wrong.
p.s. I believe I’ve tried all permutations of the ordering of the Declare statements and the ordering within the MakeAvailable statement.

EDIT: I can see now I misread the example from the CMake FetchContent documentation. It assumes the uses_other project internally uses FetchContent to get other. So now I’m back to questioning if I can do what I’m trying to do. I certainly don’t think I can use CMAKE_PREFIX_PATH to add in some build folder path to help azmq find zeromq.

MORE EDIT: Yeah I think I’m completely off on this. There’s no way for a project fetched as source to find at configure time an already-built library from a 2nd project that was fetched as source. I’ll leave this comment up for a bit longer in case there are helpful comments but I suspect I need to find an alternate approach. My goal was to allow a person to grab my project and automatically get the external dependencies.

[1] https://cmake.org/cmake/help/latest/module/FetchContent.html

Maybe the changes in CMake 3.24 can help you:

The “FetchContent” module and the
“find_package()” command now
support integration capabilities.

1 Like

I had looked at the new options and hoped they would help, but I don’t think they do in my case.

As @hsattler mentioned, the new FetchContent / find_package() integration in CMake 3.24 might help you here. A key observation that may be tripping you up at the moment is that the dependency name is case-sensitive. You are specifying zeromq in your FetchContent calls, but the find_package() calls inside azmq will be looking for ZeroMQ. Since ZeroMQ is the canonical name for the dependency, your FetchContent calls should use exactly the same thing. If you do that, you can add the OVERRIDE_FIND_PACKAGE keyword to your FetchContent_Declare(ZeroMQ) call and I think you’ll end up with the behavior you’re after. This assumes that building ZeroMQ from source as part of the main build provides all the things that azmq expects. If azmq uses any variables that find_package(ZeroMQ) would normally provide, you may need to do some extra work to handle that. Creating a zeromq-extra.cmake or ZeroMQExtra.cmake file in the CMAKE_FIND_PACKAGE_REDIRECTS_DIR which sets those variables would be the way to do that.

1 Like

Hi Craig,

Thanks for the clarifications. I had tried using the canonical package name of ‘ZeroMQ’ earlier as well. I didn’t try the new OVERRIDE_FIND_PACKAGE and I’ll admit I didn’t fully understand it until now.

I would definitely need to do the extra work you describe because azmq is looking for these variables to be set: ZeroMQ_INCLUDE_DIRS ZeroMQ_LIBRARIES. That extra work is what I’m experimenting with now and I just need to get it to work.

My only question would be: is this an intended use case for FetchContent or would I be better off switching to ExternalProject_Add? I thought I read in a blog somewhere recently that FetchContent is geared towards projects that you control and ExternalProject is better for those you don’t control.

I wouldn’t say ExternalProject is better for projects you don’t control. The advice I would normally give is to avoid mixing ExternalProject with non-ExternalProject things. Put another way, either go a full superbuild where everything is brought in via ExternalProject (so your main project is just acting as a layer that co-ordinates the different external projects), or avoid using ExternalProject. Otherwise, you end up having to manually specify a bunch of platform-dependent stuff. For me personally, I tend to look at using FetchContent first, and only fall back to ExternalProject for those cases where FetchContent isn’t appropriate (e.g. uses a different toolchain, has targets with names that clash with other things, sets or uses cache variables that have side effects on the rest of the build, etc.).

For FetchContent, it is certainly well-suited to dependencies you are in control of. However, you can also use it for other dependencies too, as long as they are well-behaved. The new features around integration with find_package() give you more flexibility, opening up opportunities for using FetchContent where it wasn’t really possible before. Keep an eye on this post, where I intend to provide some clearer guidance on this area once I get some other tasks out of the way.

2 Likes

Just following up on this thread to say that FetchContent did essentially work with the addition of Craig’s OVERRIDE_FIND_PACKAGE. My issue turned out to be a fairly finicky FindZeroMQ.cmake file in azmq that I ended up updating to allow it to find the copy I built and installed. It was written to expect some visual studio naming convention for the library file on Windows but I had built it outside that IDE. Anyway - it is working like a champ for me and even worked with recursive fetching.