cmake-basis/BASIS

Support standalone build of project modules

schuhschuh opened this issue · 0 comments

Issue by schuhschuh
Thursday Mar 03, 2016 at 17:43 GMT
Originally opened as cmake-basis/legacy#555


The standalone build of project modules currently yields a different result than when the modules would have been built as part of the top-level project. This affects mainly the CMake files in the <prefix>/lib/cmake/<package>/ directory. The standalone built of subprojects (see SUBPROJECT option of basis_project) is a different subject and should work already. This issue is also concerned with module that are tightly coupled with the top-level project and other modules. These share a common namespace named after the top-level project (see PACKAGE option of basis_project).

  • Name module configuration files <Pkg><Module>Config.cmake instead of <Pkg>Config.cmake
  • Append module to <Pkg>_MODULES and <Pkg>_MODULES_ENABLED lists
  • Include installed <Pkg><Module>InstallManifest.txt in uninstaller script
  • Skip <prefix>/bin/uninstall-<pkg> and <prefix>/lib/cmake/<pkg>/<Pkg>Uninstall.cmake files
  • Include exported targets in <Pkg><Module>Exports.cmake in <Pkg><Module>Use.cmake file which is to be included by <Pkg>Use.cmake file when the module was requested

Thoughts on the export/import of module targets

Best would be to write <Pkg><Module>Exports.cmake files for each module and include these in the respective <Pkg><Module>Config.cmake files. This, however, is not possible with CMake because it requires all (library) targets that depend on each other to be exported altogether. What can we do about this?

Can/shall we make use of the following glob expression that CMake generates? But this would include the files <Pkg>Exports-<Module>-<config>.cmake twice, once in <Pkg>Exports-<Module>.cmake and another time in <Pkg>Exports.cmake.

# Load information for each installed configuration.
get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
file(GLOB CONFIG_FILES "${_DIR}/MIRTKExports-*.cmake")
foreach(f ${CONFIG_FILES})
  include(${f})
endforeach()

It seems the following code at the top of the generated exports file guards against multiple inclusions:

# Protect against multiple inclusion, which would fail when already imported targets are added once more.
set(_targetsDefined)
set(_targetsNotDefined)
set(_expectedTargets)
foreach(_expectedTarget mirtk::lbfgs mirtk::LibNumerics)
  list(APPEND _expectedTargets ${_expectedTarget})
  if(NOT TARGET ${_expectedTarget})
    list(APPEND _targetsNotDefined ${_expectedTarget})
  endif()
  if(TARGET ${_expectedTarget})
    list(APPEND _targetsDefined ${_expectedTarget})
  endif()
endforeach()
if("${_targetsDefined}" STREQUAL "${_expectedTargets}")
  set(CMAKE_IMPORT_FILE_VERSION)
  cmake_policy(POP)
  return()
endif()
if(NOT "${_targetsDefined}" STREQUAL "")
  message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_targetsDefined}\nTargets not yet defined: ${_targetsNotDefined}\n")
endif()
unset(_targetsDefined)
unset(_targetsNotDefined)
unset(_expectedTargets)

It may be necessary to export all targets to a single file and then split this <Pkg>Exports.cmake into separate <Pkg><Module>Exports.cmake files using a Python script which filters only those parts that relate to the targets of the respective module.

Why not just including the <Pkg><Module>Exports.cmake file in the <Pkg><Module>Use.cmake file that is in turn included by <Pkg>Use.cmake file as long as the module is added to the list of requested modules. The <Pkg><Module>Exports.cmake file will only exist when the module was built and installed separate from the top-level project. When it is built and installed as part of the top-level project, its targets are in the <Pkg>Exports.cmake file which is included by the <Pkg>Use.cmake.