Installing CMake package config files for MacOS frameworks

I created a versioned MacOS framework with CMake and stumbled over the question where to install the package config files sample-config.cmake, sample-config-version.cmake, sample-exports.cmake, sample-exports-release.cmake.

The framework is versioned so the structure is roughly as follows:

<sample.framework>
   |-- Headers                 # link to Versions/Current/Headers
   |-- Resources               # link to Versions/Current/Resources
   +-- Versions
       |-- Current             # link to B
       +-- B
           |-- Headers
           +-- Resources
               |-- CMake
               +-- Info.plist

I use CMakes CMakePackageConfigHelpers macros to generate a package config file from a template sample-config.cmake.in with the content

@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/sample-export.cmake")

CMake does not mention versioned frameworks and recommends to install the files into the directory Resources/CMake.

I did so by calling

install(FILES "${CMAKE_CURRENT_BINARY_DIR}/sample-config.cmake"
  DESTINATION sample.framework/Resources/CMake
  COMPONENT development
)

The generated file looks like this:

####### 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 sample-config.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("${CMAKE_CURRENT_LIST_DIR}/sample-export.cmake")

Error:

There’s a difference in the generated config file whether I install those files to Resources/CMake or to Versions/B/Resources/CMake although both point to the same directory.

When installing via the Resources link to Resources/CMake the call to set PACKAGE_PREFIX_DIR is generated as

get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE)

but when installing via Versions/B/Resources/CMake it is generated as

get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../../../" ABSOLUTE)

As a consequence of this the package cannot be found by find_package(sample CONFIG) when installing to Versions/B/Resources/CMake.

Did anybody was facing this error before?

Thanks for any input on this.

It seems like also searching Versions/B for Resources/CMake is a reasonable thing to do to me. Thoughts @brad.king?

The find_package search procedure does search <prefix>/<name>.framework/Versions/*/Resources/CMake/ inside frameworks. One can see the implementation here.

@vre what actually goes wrong?

My question is why the PACKAGE_PREFIX_DIR is set to different values when installing to Resources/CMake and to Versions/B/Resources/CMake although both point to the same physical directory? If I have some variables dependent on PACKAGE_PREFIX_DIR they will not resolve properly when I use the one or the other path.

The logic generating the code to compute PACKAGE_PREFIX_DIR assumes that there are no symbolic links involved. I don’t know if anyone has actually used CMakePackageConfigHelpers for a package configuration file inside a framework before.

The presence of symbolic links inside the framework may be problematic. MyPackage_DIR can be set by users to be either

  • <prefix>/MyPackage.framework/Resources/CMake, or
  • <prefix>/MyPackage.framework/Versions/Current/Resources/CMake, or
  • <prefix>/MyPackage.framework/Versions/B/Resources/CMake.

In all of those cases we need to be able to recover the <prefix>, but the number of components that needs to be removed is not the same for all cases.

Thank you for the enlightening explanations. Good to know that symbolic links are problematic when placing configure files. I can work around that.