I apologize at the outset for any lack of clarity in this question. I’m swimming in deep waters and not always staying above the surface. I have tried to figure this out, and have come to a fork in the road, and need to understand the best practice before I choose a path.
Background
I’m trying to fix an application (GNSS-SDR) that is built upon a third-party package (GNU Radio). GNSS-SDR tries to maintain extensive backwards compatibility with older versions, compilers, and operating systems, which seems to complicate things a lot.
The leaf issue is that the newer GNU Radio releases replaced one third party package (log4cpp) with another (spdlog). They also made some significant improvements in their exported CMake files. When I build GNSS-SDR on my CentOS 7 environment, I get a compile error that traces through GNU Radio into spdlog.
I have determined that spdlog properly exposes interface compile and link properties in its spdlogConfigTargets.cmake, like this (from ArchLinux):
set_target_properties(spdlog::spdlog PROPERTIES
INTERFACE_COMPILE_DEFINITIONS "SPDLOG_SHARED_LIB;SPDLOG_COMPILED_LIB;SPDLOG_FMT_EXTERNAL"
INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include"
INTERFACE_LINK_LIBRARIES "Threads::Threads;fmt::fmt"
)
Issue
GNSS-SDR implements a number of FindModules that wrap other packages. Because GNSS-SDR wraps the finding of all these third-party packages, it creates its own import targets for them. I think information is lost in doing this.
In particular, this code explicitly adds the SPDLOG_FMT_EXTERNAL
define to the compile flags of any user of the package.
I tried simply removing the FindSPDLOG
module from GNSS-SDR; then I realized that there is no reason to find it at all; GNU Radio should be (and is) exporting the dependency. When I do this, though, distributions that need the SPDLOG_FMT_EXTERNAL
define no longer compile.
What I think should be happening is that the GNU Radio targets expose the spdlog dependency, including the compilation properties. Unfortunately, GNSS-SDR wraps the GNU Radio targets (gnuradio::gnuradio-XXX
) with its own targets (Gnuradio::XXX
). I think this is the root cause of my problem.
However, as I’ve tried to remove the FindGNURADIO module, I see that it is doing more than just “finding” the package. Here’s where my CMake-fu is too weak.
The Real Question
Should a FindModule simply “find” a package, bringing it into the environment such that it can be used by targets, or should it also “augment” the package, adding meta-data. For example, here, here, and here exposes a flag based on an implementation detail that changed in the past.
If I just remove the GNSS-SDR FindModule (and change find_package(GNURADIO)
to find_package(Gnuradio)
, then things mostly work, but I’m left with the missing metadata. So is that the proper domain of a FindModule?
If I don’t remove the project-specific FindModule and rely on the provided one, where should I put the metadata? Right now, some metadata is in the FindModules and other is in the top-level CMakeLists.txt.
I’m not afraid to do major surgery, but it would be good to “see one” before I “do one”[1].
References
I’ve tried to search on my own. I’ve looked at
- How to properly import CMake files/modules?
- https://cmake.org/cmake/help/latest/manual/cmake-developer.7.html
- https://cmake.org/cmake/help/v3.24/guide/using-dependencies/index.html
- https://cmake.org/cmake/help/latest/module/FindPkgConfig.html
- https://cmake.org/cmake/help/latest/command/find_package.html
I can’t say I’ve understood it all, but I’m coming closer.