Browse Source

Merge pull request #532 from saschazelzer/improve-external-dependency-handling

Improve external dependency handling
Sascha Zelzer 10 years ago
parent
commit
d52dc0419a

+ 110 - 0
CMake/CMakeFindDependencyMacro.cmake

@@ -0,0 +1,110 @@
+#.rst:
+# CMakeFindDependencyMacro
+# -------------------------
+#
+# ::
+#
+#     find_dependency(<dep> [<version> [EXACT]])
+#
+#
+# ``find_dependency()`` wraps a :command:`find_package` call for a package
+# dependency. It is designed to be used in a <package>Config.cmake file, and it
+# forwards the correct parameters for EXACT, QUIET and REQUIRED which were
+# passed to the original :command:`find_package` call.  It also sets an
+# informative diagnostic message if the dependency could not be found.
+#
+
+#=============================================================================
+# Copyright 2013 Stephen Kelly <steveire@gmail.com>
+#
+# CMake - Cross Platform Makefile Generator
+# Copyright 2000-2014 Kitware, Inc.
+# Copyright 2000-2011 Insight Software Consortium
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+#
+# * Neither the names of Kitware, Inc., the Insight Software Consortium,
+#   nor the names of their contributors may be used to endorse or promote
+#   products derived from this software without specific prior written
+#   permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#=============================================================================
+
+macro(find_dependency dep)
+  if (NOT ${dep}_FOUND)
+    set(cmake_fd_version)
+    if (${ARGC} GREATER 1)
+      if ("${ARGV1}" STREQUAL "")
+        message(FATAL_ERROR "Invalid arguments to find_dependency. VERSION is empty")
+      endif()
+      if ("${ARGV1}" STREQUAL EXACT)
+        message(FATAL_ERROR "Invalid arguments to find_dependency. EXACT may only be specified if a VERSION is specified")
+      endif()
+      set(cmake_fd_version ${ARGV1})
+    endif()
+    set(cmake_fd_exact_arg)
+    if(${ARGC} GREATER 2)
+      if (NOT "${ARGV2}" STREQUAL EXACT)
+        message(FATAL_ERROR "Invalid arguments to find_dependency")
+      endif()
+      set(cmake_fd_exact_arg EXACT)
+    endif()
+    if(${ARGC} GREATER 3)
+      message(FATAL_ERROR "Invalid arguments to find_dependency")
+    endif()
+    set(cmake_fd_quiet_arg)
+    if(${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY)
+      set(cmake_fd_quiet_arg QUIET)
+    endif()
+    set(cmake_fd_required_arg)
+    if(${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED)
+      set(cmake_fd_required_arg REQUIRED)
+    endif()
+
+    get_property(cmake_fd_alreadyTransitive GLOBAL PROPERTY
+      _CMAKE_${dep}_TRANSITIVE_DEPENDENCY
+    )
+
+    find_package(${dep} ${cmake_fd_version}
+        ${cmake_fd_exact_arg}
+        ${cmake_fd_quiet_arg}
+        ${cmake_fd_required_arg}
+    )
+
+    if(NOT DEFINED cmake_fd_alreadyTransitive OR cmake_fd_alreadyTransitive)
+      set_property(GLOBAL PROPERTY _CMAKE_${dep}_TRANSITIVE_DEPENDENCY TRUE)
+    endif()
+
+    if (NOT ${dep}_FOUND)
+      set(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE "${CMAKE_FIND_PACKAGE_NAME} could not be found because dependency ${dep} could not be found.")
+      set(${CMAKE_FIND_PACKAGE_NAME}_FOUND False)
+      return()
+    endif()
+    set(cmake_fd_version)
+    set(cmake_fd_required_arg)
+    set(cmake_fd_quiet_arg)
+    set(cmake_fd_exact_arg)
+  endif()
+endmacro()

+ 16 - 3
CMake/CTKConfig.cmake.in

@@ -8,6 +8,10 @@
 
 @PACKAGE_INIT@
 
+# Help finding external projects which might have been
+# installed with CTK in the same install location
+list(APPEND CMAKE_PREFIX_PATH ${PACKAGE_PREFIX_DIR})
+
 # CMake extension module directory
 set_and_check(CTK_CMAKE_DIR "@PACKAGE_CTK_CMAKE_DIR_CONFIG@")
 set_and_check(CTK_CMAKE_UTILITIES_DIR "@PACKAGE_CTK_CMAKE_UTILITIES_DIR_CONFIG@")
@@ -31,6 +35,9 @@ set_and_check(CTK_EXPORT_HEADER_TEMPLATE "@PACKAGE_CTK_EXPORT_HEADER_TEMPLATE_DI
 set_and_check(CTK_LIBRARY_DIR "@PACKAGE_CTK_LIBRARY_DIR_CONFIG@")
 set(CTK_LIBRARY_DIRS ${CTK_LIBRARY_DIR})
 
+# CTK specific variables
+set(CTK_CMAKE_DEBUG_POSTFIX "@CMAKE_DEBUG_POSTFIX@")
+
 # Import CTK targets
 if(NOT TARGET CTKCore)
   include(${CTK_TARGETS})
@@ -64,6 +71,12 @@ include("${CTK_CMAKE_DIR}/ctkFunctionGetPluginDependencies.cmake")
 include("${CTK_CMAKE_DIR}/ctkMacroSetupPlugins.cmake")
 include("${CTK_CMAKE_DIR}/ctkMacroGenerateMocs.cmake")
 
+if(CMAKE_VERSION VERSION_LESS 3)
+  include("${CTK_CMAKE_DIR}/CMakeFindDependencyMacro.cmake")
+else()
+  include(CMakeFindDependencyMacro)
+endif()
+
 # List all libraries
 SET(CTK_LIBRARIES @CTK_LIBRARIES@)
 
@@ -73,9 +86,6 @@ SET(CTK_WRAPPED_LIBRARIES_PYTHONQT @CTK_WRAPPED_LIBRARIES_PYTHONQT@)
 # Include CTK Plugin specific variables
 include(${CTK_PLUGIN_USE_FILE})
 
-# CTK external projects variables
-@CTK_SUPERBUILD_EP_VARS_CONFIG@
-
 # Qt configuration
 set(CTK_QT_VERSION "@CTK_QT_VERSION@")
 set(CTK_QT5_COMPONENTS @CTK_QT5_COMPONENTS@)
@@ -109,3 +119,6 @@ set(CTK_INSTALL_QTPLUGIN_DIR "@CTK_INSTALL_QTPLUGIN_DIR@")
 # that build tree (only one will ever be set).
 SET(CTK_CONFIGURATION_TYPES @CTK_CONFIGURATION_TYPES_CONFIG@)
 SET(CTK_BUILD_TYPE @CTK_BUILD_TYPE_CONFIG@)
+
+# CTK external projects variables
+@CTK_SUPERBUILD_EP_VARS_CONFIG@

+ 26 - 8
CMake/LastConfigureStep/CTKGenerateCTKConfig.cmake

@@ -71,14 +71,6 @@ else()
   set(CTK_PLUGIN_LIBRARIES_DIR_CONFIG "${CMAKE_${_plugin_output_type}_OUTPUT_DIRECTORY}/plugins")
 endif()
 
-# CTK external projects variables
-set(CTK_SUPERBUILD_EP_VARS_CONFIG)
-foreach(varname ${CTK_EP_LABEL_FIND_PACKAGE})
-  set(CTK_SUPERBUILD_EP_VARS_CONFIG
-   "${CTK_SUPERBUILD_EP_VARS_CONFIG}
-set(CTK_${varname} \"${${varname}}\")")
-endforeach()
-
 # CMake extension module directory.
 set(CTK_CMAKE_DIR_CONFIG ${CTK_CMAKE_DIR})
 set(CTK_CMAKE_UTILITIES_DIR_CONFIG ${CTK_CMAKE_UTILITIES_DIR})
@@ -128,6 +120,20 @@ install(EXPORT CTKExports DESTINATION ${CTK_INSTALL_CMAKE_DIR})
 #-----------------------------------------------------------------------------
 # Configure 'CTKConfig.cmake' for a build tree
 
+# CTK external projects variables
+set(CTK_SUPERBUILD_EP_VARS_CONFIG)
+foreach(varname ${CTK_EP_LABEL_FIND_PACKAGE_VARS} ${CTK_EP_LABEL_FIND_PACKAGE})
+  set(CTK_SUPERBUILD_EP_VARS_CONFIG
+   "${CTK_SUPERBUILD_EP_VARS_CONFIG}
+set(${varname} \"${${varname}}\")")
+endforeach()
+foreach(varname ${CTK_EP_LABEL_FIND_PACKAGE})
+  string(REPLACE "_DIR" "" package_name "${varname}")
+  set(CTK_SUPERBUILD_EP_VARS_CONFIG
+   "${CTK_SUPERBUILD_EP_VARS_CONFIG}
+find_dependency(${package_name})")
+endforeach()
+
 set(CTK_CONFIG_DIR_CONFIG ${CTK_SUPERBUILD_BINARY_DIR})
 set(CTK_CMAKE_DIR_CONFIG ${CTK_CMAKE_DIR})
 set(CTK_CMAKE_UTILITIES_DIR_CONFIG ${CTK_CMAKE_UTILITIES_DIR})
@@ -187,6 +193,18 @@ configure_package_config_file(
 #-----------------------------------------------------------------------------
 # Configure 'CTKConfig.cmake' for an install tree
 
+# CTK external projects. We rely on externally set
+# _DIR variables or a proper CMAKE_PREFIX_PATH such
+# that find_dependency/find_package can successfully
+# find the external project. 
+set(CTK_SUPERBUILD_EP_VARS_CONFIG)
+foreach(varname ${CTK_EP_LABEL_FIND_PACKAGE})
+  string(REPLACE "_DIR" "" package_name "${varname}")
+  set(CTK_SUPERBUILD_EP_VARS_CONFIG
+   "${CTK_SUPERBUILD_EP_VARS_CONFIG}
+find_dependency(${package_name})")
+endforeach()
+
 set(CTK_CONFIG_DIR_CONFIG ${CTK_INSTALL_CMAKE_DIR})
 set(CTK_CMAKE_DIR_CONFIG ${CTK_INSTALL_CMAKE_DIR})
 set(CTK_CMAKE_UTILITIES_DIR_CONFIG ${CTK_INSTALL_CMAKE_DIR})

+ 7 - 0
CMakeExternals/DCMTK.cmake

@@ -83,3 +83,10 @@ mark_as_superbuild(
   LABELS "FIND_PACKAGE"
   )
 
+# If an external DCMTK was provided via DCMTK_DIR and the external DCMTK
+# build/install used a CMAKE_DEBUG_POSTFIX value for distinguishing debug
+# and release libraries in the same build/install tree, the same debug
+# postfix needs to be passed to the CTK configure step. The FindDCMTK
+# script then takes the DCMTK_CMAKE_DEBUG_POSTFIX variable into account
+# when looking for DCMTK debug libraries.
+mark_as_superbuild(DCMTK_CMAKE_DEBUG_POSTFIX:STRING)

+ 1 - 1
CMakeExternals/KWStyle.cmake

@@ -55,5 +55,5 @@ endif()
 
 mark_as_superbuild(
   VARS KWSTYLE_EXECUTABLE:FILEPATH
-  LABELS "FIND_PACKAGE"
+  LABELS "FIND_PACKAGE_VARS"
   )

+ 8 - 0
CMakeExternals/PythonQt.cmake

@@ -89,6 +89,7 @@ if(NOT DEFINED PYTHONQT_INSTALL_DIR)
       ${ep_common_cache_args}
       -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}
       -DPYTHON_INCLUDE_DIR:PATH=${PYTHON_INCLUDE_DIR}
+      -DPYTHON_INCLUDE_DIR2:PATH=${PYTHON_INCLUDE_DIR2}
       -DPYTHON_LIBRARY:FILEPATH=${PYTHON_LIBRARY}
       ${ep_PythonQt_args}
     DEPENDS
@@ -100,11 +101,18 @@ else()
   ExternalProject_Add_Empty(${proj} DEPENDS ${${proj}_DEPENDENCIES})
 endif()
 
+set(PythonQt_DIR ${PYTHONQT_INSTALL_DIR})
+
 mark_as_superbuild(
   VARS
     PYTHONQT_INSTALL_DIR:PATH
     PYTHON_EXECUTABLE:FILEPATH # FindPythonInterp expects PYTHON_EXECUTABLE variable to be defined
     PYTHON_INCLUDE_DIR:PATH # FindPythonQt expects PYTHON_INCLUDE_DIR variable to be defined
+    PYTHON_INCLUDE_DIR2:PATH
     PYTHON_LIBRARY:FILEPATH # FindPythonQt expects PYTHON_LIBRARY variable to be defined
+  LABELS "FIND_PACKAGE_VARS"
+  )
+mark_as_superbuild(
+  VARS PythonQt_DIR:PATH
   LABELS "FIND_PACKAGE"
   )

+ 5 - 3
CMakeExternals/QtTesting.cmake

@@ -71,8 +71,10 @@ else()
 endif()
 
 mark_as_superbuild(
-  VARS
-    QtTesting_INSTALL_DIR:PATH
-    QtTesting_DIR:PATH
+  VARS QtTesting_INSTALL_DIR:PATH
+  LABELS "FIND_PACKAGE_VARS"
+  )
+mark_as_superbuild(
+  VARS QtTesting_DIR:PATH
   LABELS "FIND_PACKAGE"
   )

+ 7 - 1
CMakeLists.txt

@@ -79,7 +79,12 @@ if(NOT CMAKE_CONFIGURATION_TYPES)
   mark_as_superbuild(VARS CMAKE_BUILD_TYPE ALL_PROJECTS)
 endif()
 
-mark_as_superbuild(CMAKE_PREFIX_PATH)
+mark_as_superbuild(
+  VARS
+    CMAKE_PREFIX_PATH:STRING
+    CMAKE_DEBUG_POSTFIX:STRING
+  ALL_PROJECTS
+  )
 
 #-----------------------------------------------------------------------------
 # Superbuild Option - Enabled by default
@@ -238,6 +243,7 @@ foreach(file
   Libs/ctkExport.h.in
   CMake/ctkLinkerAsNeededFlagCheck.cmake
   CMake/ctk_compile_python_scripts.cmake.in
+  CMake/CMakeFindDependencyMacro.cmake
   )
   install(FILES ${file} DESTINATION ${CTK_INSTALL_CMAKE_DIR} COMPONENT Development)
 endforeach()

+ 5 - 1
Libs/DICOM/Core/CMakeLists.txt

@@ -71,9 +71,13 @@ set_source_files_properties(
 #     added to be able to build against DCMTK 3.6.0 available by default on linux
 #     distribution. Let's skip it in the case of multi configuration system and
 #     assume DCMTK provides 'dcmtk::log4cplus::Logger'.
+#     We also skip this test if DCMTK_CMAKE_DEBUG_POSTFIX is set, because then the
+#     DCMTK_LIBRARIES variable will have a value similar to "debug <lib1> ..." which
+#     will not link the DCMTK debug libraries in the try_compile call because
+#     BUILD_TYPE cannot be set for the generated CMakeLists.txt file.
 # TODO When build as external project, the config of the parent project could be passed to CTK
 #      and used as a hint. We need to define what would be the convention for such hint.
-if(CMAKE_CONFIGURATION_TYPES AND NOT DEFINED HAVE_DCMTK_LOG4CPLUS_LOGGER)
+if(DCMTK_CMAKE_DEBUG_POSTFIX OR (CMAKE_CONFIGURATION_TYPES AND NOT DEFINED HAVE_DCMTK_LOG4CPLUS_LOGGER))
   set(HAVE_DCMTK_LOG4CPLUS_LOGGER 1 CACHE INTERNAL "Test HAVE_DCMTK_LOG4CPLUS_LOGGER")
 endif()
 # Check if DCMTK provides 'dcmtk::log4cplus::Logger', if not fallback to 'log4cplus::Logger'.

+ 1 - 1
Utilities/CMake/FindDCMTK.cmake

@@ -191,7 +191,7 @@ foreach(lib
 
   # Find Debug libraries
   find_library(DCMTK_${lib}_LIBRARY_DEBUG
-    ${lib}
+    ${lib}${DCMTK_CMAKE_DEBUG_POSTFIX}
     PATHS
     ${DCMTK_DIR}/${lib}/libsrc
     ${DCMTK_DIR}/${lib}/libsrc/Debug

+ 14 - 2
Utilities/CMake/FindPythonQt.cmake

@@ -11,11 +11,20 @@ endif()
 
 find_path(PYTHONQT_INSTALL_DIR include/PythonQt/PythonQt.h DOC "Directory where PythonQt was installed.")
 find_path(PYTHONQT_INCLUDE_DIR PythonQt.h "${PYTHONQT_INSTALL_DIR}/include/PythonQt" DOC "Path to the PythonQt include directory")
-find_library(PYTHONQT_LIBRARY PythonQt PATHS "${PYTHONQT_INSTALL_DIR}/lib" DOC "The PythonQt library.")
+find_library(PYTHONQT_LIBRARY_RELEASE PythonQt PATHS "${PYTHONQT_INSTALL_DIR}/lib" DOC "The PythonQt library.")
+find_library(PYTHONQT_LIBRARY_DEBUG NAMES PythonQt${CTK_CMAKE_DEBUG_POSTFIX} PythonQt${CMAKE_DEBUG_POSTFIX} PythonQt PATHS "${PYTHONQT_INSTALL_DIR}/lib" DOC "The PythonQt library.")
+set(PYTHONQT_LIBRARY)
+if(PYTHONQT_LIBRARY_RELEASE)
+  list(APPEND PYTHONQT_LIBRARY optimized ${PYTHONQT_LIBRARY_RELEASE})
+endif()
+if(PYTHONQT_LIBRARY_DEBUG)
+  list(APPEND PYTHONQT_LIBRARY debug ${PYTHONQT_LIBRARY_DEBUG})
+endif()
 
 mark_as_advanced(PYTHONQT_INSTALL_DIR)
 mark_as_advanced(PYTHONQT_INCLUDE_DIR)
-mark_as_advanced(PYTHONQT_LIBRARY)
+mark_as_advanced(PYTHONQT_LIBRARY_RELEASE)
+mark_as_advanced(PYTHONQT_LIBRARY_DEBUG)
 
 # On linux, also find libutil
 if(UNIX AND NOT APPLE)
@@ -23,11 +32,14 @@ if(UNIX AND NOT APPLE)
   mark_as_advanced(PYTHONQT_LIBUTIL)
 endif()
 
+# All upper case _FOUND variable is maintained for backwards compatibility.
 set(PYTHONQT_FOUND 0)
+set(PythonQt_FOUND 0)
 if(PYTHONQT_INCLUDE_DIR AND PYTHONQT_LIBRARY)
   # Currently CMake'ified PythonQt only supports building against a python Release build. 
   # This applies independently of CTK build type (Release, Debug, ...)
   add_definitions(-DPYTHONQT_USE_RELEASE_PYTHON_FALLBACK)
   set(PYTHONQT_FOUND 1)
+  set(PythonQt_FOUND ${PYTHONQT_FOUND})
   set(PYTHONQT_LIBRARIES ${PYTHONQT_LIBRARY} ${PYTHONQT_LIBUTIL})
 endif()