BLUF (Bottom Line Up Front) Pascal quote applies
If a package provides a CMake FooConfig.cmake
file and also provides pkg-config support (foo.pc
), should I reasonably expect that the information in both locations are consistent?
If not, is there a (good) way to force the pkg-config information to be applied when I “import” the package? Specifically, the compiler flags?
Painful Detail
I have the feeling this must be a common issue, but I couldn’t quite find a match anywhere. I am (externally to my project) building and installing libzmq and cppzmq in a toolchain OCI image. Both products are built like this (fragment of my Dockerfile):
; ${CMAKE} \
${CMAKE_FLAGS} \
${cmake_INSTALL_FLAGS} \
-DCMAKE_BUILD_TYPE=Release \
-DENABLE_DRAFTS=on \
-S .. \
; make ${MAKEFLAGS} install \
; /sbin/ldconfig \
The ENABLE_DRAFTS option defines a compiler macro ZMQ_BUILD_DRAFT_API
, which must be defined for my code to compile.
In my project then, I simply add
find_package(ZeroMQ REQUIRED)
find_package(cppzmq REQUIRED)
The installed ZeroMQConfig.cmake is this:
# ZeroMQ cmake module
#
# The following import targets are created
#
# ::
#
# libzmq-static
# libzmq
#
# This module sets the following variables in your project::
#
# ZeroMQ_FOUND - true if ZeroMQ found on the system
# ZeroMQ_INCLUDE_DIR - the directory containing ZeroMQ headers
# ZeroMQ_LIBRARY -
# ZeroMQ_STATIC_LIBRARY
####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() #######
####### Any changes to this file will be overwritten by the next CMake run ####
####### The input file was ZeroMQConfig.cmake.in ########
get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE)
macro(set_and_check _var _file)
set(${_var} "${_file}")
if(NOT EXISTS "${_file}")
message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !")
endif()
endmacro()
macro(check_required_components _NAME)
foreach(comp ${${_NAME}_FIND_COMPONENTS})
if(NOT ${_NAME}_${comp}_FOUND)
if(${_NAME}_FIND_REQUIRED_${comp})
set(${_NAME}_FOUND FALSE)
endif()
endif()
endforeach()
endmacro()
####################################################################################
if(NOT TARGET libzmq AND NOT TARGET libzmq-static)
include("${CMAKE_CURRENT_LIST_DIR}/ZeroMQTargets.cmake")
if (TARGET libzmq)
get_target_property(ZeroMQ_INCLUDE_DIR libzmq INTERFACE_INCLUDE_DIRECTORIES)
else ()
get_target_property(ZeroMQ_INCLUDE_DIR libzmq-static INTERFACE_INCLUDE_DIRECTORIES)
endif()
if (TARGET libzmq)
get_target_property(ZeroMQ_LIBRARY libzmq LOCATION)
endif()
if (TARGET libzmq-static)
get_target_property(ZeroMQ_STATIC_LIBRARY libzmq-static LOCATION)
endif()
endif()
(as I type this, I realize that nothing here exports compile flags; so it may be an intentional limitation of the ZeroMQ package)
The CppZmq package is header-only, and does export pkg-config options. In particular,
$ pkg-config --cflags cppzmq
-I/opt/foss/include -DZMQ_BUILD_DRAFT_API=1
The installed cppzmqConfig.cmake is this:
# cppzmq cmake module
#
# The following import targets are created
#
# ::
#
# cppzmq-static
# cppzmq
#
# This module sets the following variables in your project::
#
# cppzmq_FOUND - true if cppzmq found on the system
# cppzmq_INCLUDE_DIR - the directory containing cppzmq headers
# cppzmq_LIBRARY - the ZeroMQ library for dynamic linking
# cppzmq_STATIC_LIBRARY - the ZeroMQ library for static linking
####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() #######
####### Any changes to this file will be overwritten by the next CMake run ####
####### The input file was cppzmqConfig.cmake.in ########
get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE)
macro(set_and_check _var _file)
set(${_var} "${_file}")
if(NOT EXISTS "${_file}")
message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !")
endif()
endmacro()
macro(check_required_components _NAME)
foreach(comp ${${_NAME}_FIND_COMPONENTS})
if(NOT ${_NAME}_${comp}_FOUND)
if(${_NAME}_FIND_REQUIRED_${comp})
set(${_NAME}_FOUND FALSE)
endif()
endif()
endforeach()
endmacro()
####################################################################################
include(CMakeFindDependencyMacro)
find_package(ZeroMQ QUIET)
# libzmq autotools install: fallback to pkg-config
if(NOT ZeroMQ_FOUND)
list (APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/libzmq-pkg-config)
find_package(ZeroMQ REQUIRED)
endif()
if(NOT ZeroMQ_FOUND)
message(FATAL_ERROR "ZeroMQ was NOT found!")
endif()
if(NOT TARGET cppzmq)
include("${CMAKE_CURRENT_LIST_DIR}/cppzmqTargets.cmake")
get_target_property(cppzmq_INCLUDE_DIR cppzmq INTERFACE_INCLUDE_DIRECTORIES)
endif()
Now, when I build a library that uses it, I expected that by adding to the target’s link libraries, I would inherit compilation flags. Other packages I’ve used work that way. But I was wrong.
add_library( ${myTarget} SHARED )
target_sources( ${myTarget} PRIVATE
mySource.cpp
)
target_link_libraries( ${myTarget} PUBLIC
cppzmq
)
# This should have been defined when ZMQ was brought in. Empirically, it is not. I require it to
# enable the active_poller_t
target_compile_definitions( ${myTarget} PUBLIC ZMQ_BUILD_DRAFT_API )
The last line is what I didn’t want to do. Since pkg-config knows about the additional #define
I need, shouldn’t I be able to “inherit” it automagically? How, short of hard-coding like I did, can I get the installed configuration of a tool?