Hi, we are hoping that more and more libraries will install Config.cmake files (and for kdelibs this is actually happening right now), so we should make sure it is straighforward to create proper Config.cmake files.
IMO the most tricky issue is how to deal with the location of the various installed files and directories. Config.cmake files should be relocatable, i.e. their installation directory must be changeable at install time, i.e. not at cmake-time via CMAKE_INSTALL_PREFIX. This is typical under Windows, where the user decides at install-time of a binary package where to put it. This would be relatively straightforward if the install destinations e.g. for libs and headers would be relative directories. But users/packagers want to be able to change those install directories, and so we must expect that some of the install directories are absolute directories, and handle this case properly. Properly here means at least issue a useful error message if the package has been relocated, even better would be to adjust the install dirs to the changed location. IMO we can't expect the average developer to figure out all the details how to handle those install dirs correctly by himself, taking into accoutn wishes of users, packagers and also Windows people. Attached you can find an attempt to do so. The file CMakeConfigHelpers.cmake is intended to be included by Config.cmake files (or preloaded by cmake automatically when loading a Config.cmake file). It provides two functions: determine_installed_location() This function determines the current installation root of the package. For a not-relocated package this will be CMAKE_INSTALL_PREFIX. For a relocated package it detects that it has been relocated, and calculates the root dir. This needs some logic since even the directory where the Config.cmake file is installed to can be configured e.g. to an absolute path. This root dir is then used later on in set_absolute() to either adjust relative install dirs to their new install location, or to adjust absolute install dirs to their new location if the original absolute path was a subdir of the original CMAKE_INSTALL_PREFIX. What the developer needs to do is shown in BarConfig.cmake.in: * he must configure CMAKE_INSTALL_PREFIX into the Config.cmake file * he must configure the install dir of the Config.cmake file into the Config.cmake file (@CMAKECONFIG_INSTALL_DIR@) * he must call determine_installed_location() to calculate the current installation prefix dir * done that, he must use set_absolute() with the additional two argument of the original and the current install prefix dir to set the location variables to their current location: set(BAR_CMAKE_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@") determine_installed_location(_BAR_INSTALLED_PREFIX "${BAR_CMAKE_INSTALL_PREFIX}" "@CMAKECONFIG_INSTALL_DIR@") set_absolute(BAR_INCLUDE_DIR "@INCLUDE_INSTALL_DIR@" "${_BAR_INSTALLED_PREFIX}" "${BAR_CMAKE_INSTALL_PREFIX}") set_absolute(BAR_DATA_DIR "@DATA_INSTALL_DIR@" "${_BAR_INSTALLED_PREFIX}" "${BAR_CMAKE_INSTALL_PREFIX}") I would consider this an acceptable easy way to write Config.cmake files. The names of the macros/functions can of course be changed, and maybe the two additional parameters to set_absolute() could be hidden somewhere as global variables to save typing. But OTOH this would make the dependency that determine_installed_location() has to be called before set_absolute() invisible. What do you think ? An additional step would be to provide a macro which completely generates the Config.cmake file (similar to WriteBasicConfigVersionFile.cmake), e.g. a WriteBasicConfigFile.cmake. This would take a whole bunch of arguments, like e.g. which variables to put in the file, what the exports-file is, and which install directories to put into that file, and then generate the file. But I'm not sure I want to hide the Config.cmake file so much from the developers, I think developers should be aware of what can be done with a Config.cmake file, so they should write them themselves. OTOH this would result in quite standard-conforming Config.cmake files, without a lot of exotic stuff people might come up. Not sure. I think the macros above are a useful first step, independent from whether such a convenience macro will be provided or not. Additionally some helper files to make testing the installed Config.cmake files would be good. It is quite tedious to always write a small test program which tries to find the respective library and check that it works. Something to make this simple would be nice. Alex
include(CMakeConfigHelpers) # set the version of myself set(BAR_VERSION_MAJOR @BAR_VERSION_MAJOR@) set(BAR_VERSION_MINOR @BAR_VERSION_MINOR@) set(BAR_VERSION_PATCH @BAR_VERSION_PATCH@) set(BAR_VERSION ${BAR_VERSION_MAJOR}.${BAR_VERSION_MINOR}.${BAR_VERSION_PATCH} ) set(BAR_CMAKE_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@") determine_installed_location(_BAR_INSTALLED_PREFIX "${BAR_CMAKE_INSTALL_PREFIX}" "@CMAKECONFIG_INSTALL_DIR@") set_absolute(BAR_INCLUDE_DIR "@INCLUDE_INSTALL_DIR@" "${_BAR_INSTALLED_PREFIX}" "${BAR_CMAKE_INSTALL_PREFIX}") set_absolute(BAR_DATA_DIR "@DATA_INSTALL_DIR@" "${_BAR_INSTALLED_PREFIX}" "${BAR_CMAKE_INSTALL_PREFIX}") # what is my include directory set(BAR_INCLUDES "${BAR_INCLUDE_DIR}") # import the exported targets include(${CMAKE_CURRENT_LIST_DIR}/BarTargets.cmake) # set the expected library variable set(BAR_LIBRARIES bar )
function(SET_ABSOLUTE _var _dir _actualInstalledPrefix _installPrefix) if(IS_ABSOLUTE "${_dir}") # if it is an absolute path, if it was a subdir of the original CMAKE_INSTALL_PREFIX, # replace this original CMAKE_INSTALL_PREFIX with the actual prefix: string(REGEX REPLACE "^${_installPrefix}" "${_actualInstalledPrefix}" absPath "${_dir}") # or is this too clever and we should leave absolute install dirs simply as they are. # They could be interpreted as a sign that the package should not be relocated. #set(absPath "${_dir}") else() set(absPath "${_actualInstalledPrefix}/${_dir}" ) endif() if(NOT EXISTS "${absPath}") message(FATAL_ERROR "File or directory \"${absPath}\" referenced by variable ${_var} does not exist !") endif() set(${_var} ${absPath} PARENT_SCOPE) endfunction() function(determine_installed_location _var _install_prefix _cmakeconfig_install_dir) if(NOT IS_ABSOLUTE "${_cmakeconfig_install_dir}") set(_cmakeconfig_install_dir "${_install_prefix}/${_cmakeconfig_install_dir}") endif() file(RELATIVE_PATH _relative_cmakeconfig_install_dir "${_cmakeconfig_install_dir}" "${_install_prefix}" ) get_filename_component(rootDir1 ${CMAKE_CURRENT_LIST_DIR}/${_relative_cmakeconfig_install_dir} ABSOLUTE) #get_filename_component(rootDir2 ${CMAKE_CURRENT_LIST_DIR}/${_BAR_RELATIVE_CMAKECONFIG_INSTALL_DIR} REALPATH) if(NOT "${rootDir1}" STREQUAL "${_install_prefix}") message(STATUS "Package has been relocated during installation.") endif() set(${_var} ${rootDir1} PARENT_SCOPE) endfunction()
-- Powered by www.kitware.com Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ Follow this link to subscribe/unsubscribe: http://public.kitware.com/cgi-bin/mailman/listinfo/cmake-developers