Quellcode durchsuchen

Merge topic 'FindBoost-imported-targets'

d60cef77 Help: Add notes for topic 'FindBoost-imported-targets.rst'
9fd98750 Tests: Add FindBoost testcase for imported targets
3f9b081f FindBoost: Add imported targets
01c80acd FindBoost: Automatically add missing component dependencies
5183c6e5 FindBoost: Embed component dependency table
8a60e696 Utilities: Add BoostScanDeps script
Brad King vor 10 Jahren
Ursprung
Commit
65dc4170f8

+ 5 - 0
Help/release/dev/FindBoost-imported-targets.rst

@@ -0,0 +1,5 @@
+FindBoost-imported-targets
+--------------------------
+
+* The :module:`FindBoost` module now provides imported targets
+  such as ``Boost::boost`` and ``Boost::filesystem``.

+ 386 - 0
Modules/FindBoost.cmake

@@ -54,6 +54,33 @@
 #   Boost_<C>_LIBRARY_DEBUG   - Component <C> library debug variant
 #   Boost_<C>_LIBRARY_RELEASE - Component <C> library release variant
 #
+# The following :prop_tgt:`IMPORTED` targets are also defined::
+#
+#   Boost::boost                  - Target for header-only dependencies
+#                                   (Boost include directory)
+#   Boost::<C>                    - Target for specific component dependency
+#                                   (shared or static library); <C> is lower-
+#                                   case
+#   Boost::diagnostic_definitions - interface target to enable diagnostic
+#                                   information about Boost's automatic linking
+#                                   during compilation (adds BOOST_LIB_DIAGNOSTIC)
+#   Boost::disable_autolinking    - interface target to disable automatic
+#                                   linking with MSVC (adds BOOST_ALL_NO_LIB)
+#   Boost::dynamic_linking        - interface target to enable dynamic linking
+#                                   linking with MSVC (adds BOOST_ALL_DYN_LINK)
+#
+# Implicit dependencies such as Boost::filesystem requiring
+# Boost::system will be automatically detected and satisfied, even
+# if system is not specified when using find_package and if
+# Boost::system is not added to target_link_libraries.  If using
+# Boost::thread, then Thread::Thread will also be added automatically.
+#
+# It is important to note that the imported targets behave differently
+# than variables created by this module: multiple calls to
+# find_package(Boost) in the same directory or sub-directories with
+# different options (e.g. static or shared) will not override the
+# values of the targets created by the first call.
+#
 # Users may set these hints or results as cache entries.  Projects
 # should not read these entries directly but instead use the above
 # result variables.  Note that some hint names start in upper-case
@@ -142,6 +169,14 @@
 #     add_executable(foo foo.cc)
 #   endif()
 #
+# Example to find Boost libraries and use imported targets::
+#
+#   find_package(Boost 1.56 REQUIRED COMPONENTS
+#                date_time filesystem iostreams)
+#   add_executable(foo foo.cc)
+#   target_link_libraries(foo Boost::date_time Boost::filesystem
+#                             Boost::iostreams)
+#
 # Example to find Boost headers and some *static* libraries::
 #
 #   set(Boost_USE_STATIC_LIBS        ON) # only find static libs
@@ -471,6 +506,262 @@ function(_Boost_GUESS_COMPILER_PREFIX _ret)
   set(${_ret} ${_boost_COMPILER} PARENT_SCOPE)
 endfunction()
 
+#
+# Get component dependencies.  Requires the dependencies to have been
+# defined for the Boost release version.
+#
+# component - the component to check
+# _ret - list of library dependencies
+#
+function(_Boost_COMPONENT_DEPENDENCIES component _ret)
+  # Note: to add a new Boost release, run
+  #
+  #   % cmake -DBOOST_DIR=/path/to/boost/source -P Utilities/Scripts/BoostScanDeps.cmake
+  #
+  # The output may be added in a new block below.  If it's the same as
+  # the previous release, simply update the version range of the block
+  # for the previous release.
+  #
+  # This information was originally generated by running
+  # BoostScanDeps.cmake against every boost release to date supported
+  # by FindBoost:
+  #
+  #   % for version in /path/to/boost/sources/*
+  #     do
+  #       cmake -DBOOST_DIR=$version -P Utilities/Scripts/BoostScanDeps.cmake
+  #     done
+  #
+  # The output was then updated by search and replace with these regexes:
+  #
+  # - Strip message(STATUS) prefix dashes
+  #   s;^-- ;;
+  # - Indent
+  #   s;^set(;    set(;;
+  # - Add conditionals
+  #   s;Scanning /path/to/boost/sources/boost_\(.*\)_\(.*\)_\(.*);  elseif(NOT Boost_VERSION VERSION_LESS \10\20\3 AND Boost_VERSION VERSION_LESS xxxx);
+  #
+  # This results in the logic seen below, but will require the xxxx
+  # replacing with the following Boost release version (or the next
+  # minor version to be released, e.g. 1.59 was the latest at the time
+  # of writing, making 1.60 the next, so 106000 is the needed version
+  # number).  Identical consecutive releases were then merged together
+  # by updating the end range of the first block and removing the
+  # following redundant blocks.
+  #
+  # Running the script against all historical releases should be
+  # required only if the BoostScanDeps.cmake script logic is changed.
+  # The addition of a new release should only require it to be run
+  # against the new release.
+  set(_Boost_IMPORTED_TARGETS TRUE)
+  if(NOT Boost_VERSION VERSION_LESS 103300 AND Boost_VERSION VERSION_LESS 103500)
+    set(_Boost_IOSTREAMS_DEPENDENCIES regex thread)
+    set(_Boost_REGEX_DEPENDENCIES thread)
+    set(_Boost_WAVE_DEPENDENCIES filesystem thread)
+    set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+  elseif(NOT Boost_VERSION VERSION_LESS 103500 AND Boost_VERSION VERSION_LESS 103600)
+    set(_Boost_FILESYSTEM_DEPENDENCIES system)
+    set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+    set(_Boost_MPI_DEPENDENCIES serialization)
+    set(_Boost_MPI_PYTHON_DEPENDENCIES python mpi serialization)
+    set(_Boost_WAVE_DEPENDENCIES filesystem system thread)
+    set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+  elseif(NOT Boost_VERSION VERSION_LESS 103600 AND Boost_VERSION VERSION_LESS 103800)
+    set(_Boost_FILESYSTEM_DEPENDENCIES system)
+    set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+    set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l)
+    set(_Boost_MPI_DEPENDENCIES serialization)
+    set(_Boost_MPI_PYTHON_DEPENDENCIES python mpi serialization)
+    set(_Boost_WAVE_DEPENDENCIES filesystem system thread)
+    set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+  elseif(NOT Boost_VERSION VERSION_LESS 103800 AND Boost_VERSION VERSION_LESS 104300)
+    set(_Boost_FILESYSTEM_DEPENDENCIES system)
+    set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+    set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l)
+    set(_Boost_MPI_DEPENDENCIES serialization)
+    set(_Boost_MPI_PYTHON_DEPENDENCIES python mpi serialization)
+    set(_Boost_THREAD_DEPENDENCIES date_time)
+    set(_Boost_WAVE_DEPENDENCIES filesystem system thread date_time)
+    set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+  elseif(NOT Boost_VERSION VERSION_LESS 104300 AND Boost_VERSION VERSION_LESS 104400)
+    set(_Boost_FILESYSTEM_DEPENDENCIES system)
+    set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+    set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random)
+    set(_Boost_MPI_DEPENDENCIES serialization)
+    set(_Boost_MPI_PYTHON_DEPENDENCIES python mpi serialization)
+    set(_Boost_THREAD_DEPENDENCIES date_time)
+    set(_Boost_WAVE_DEPENDENCIES filesystem system thread date_time)
+    set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+  elseif(NOT Boost_VERSION VERSION_LESS 104400 AND Boost_VERSION VERSION_LESS 104500)
+    set(_Boost_FILESYSTEM_DEPENDENCIES system)
+    set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+    set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random serialization)
+    set(_Boost_MPI_DEPENDENCIES serialization)
+    set(_Boost_MPI_PYTHON_DEPENDENCIES python mpi serialization)
+    set(_Boost_THREAD_DEPENDENCIES date_time)
+    set(_Boost_WAVE_DEPENDENCIES serialization filesystem system thread date_time)
+    set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+  elseif(NOT Boost_VERSION VERSION_LESS 104500 AND Boost_VERSION VERSION_LESS 104700)
+    set(_Boost_FILESYSTEM_DEPENDENCIES system)
+    set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+    set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random)
+    set(_Boost_MPI_DEPENDENCIES serialization)
+    set(_Boost_MPI_PYTHON_DEPENDENCIES python mpi serialization)
+    set(_Boost_THREAD_DEPENDENCIES date_time)
+    set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread date_time)
+    set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+  elseif(NOT Boost_VERSION VERSION_LESS 104700 AND Boost_VERSION VERSION_LESS 104800)
+    set(_Boost_CHRONO_DEPENDENCIES system)
+    set(_Boost_FILESYSTEM_DEPENDENCIES system)
+    set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+    set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random)
+    set(_Boost_MPI_DEPENDENCIES serialization)
+    set(_Boost_MPI_PYTHON_DEPENDENCIES python mpi serialization)
+    set(_Boost_THREAD_DEPENDENCIES date_time)
+    set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread date_time)
+    set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+  elseif(NOT Boost_VERSION VERSION_LESS 104800 AND Boost_VERSION VERSION_LESS 105000)
+    set(_Boost_CHRONO_DEPENDENCIES system)
+    set(_Boost_FILESYSTEM_DEPENDENCIES system)
+    set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+    set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random)
+    set(_Boost_MPI_DEPENDENCIES serialization)
+    set(_Boost_MPI_PYTHON_DEPENDENCIES python mpi serialization)
+    set(_Boost_THREAD_DEPENDENCIES date_time)
+    set(_Boost_TIMER_DEPENDENCIES chrono system)
+    set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread date_time)
+    set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+  elseif(NOT Boost_VERSION VERSION_LESS 105000 AND Boost_VERSION VERSION_LESS 105300)
+    set(_Boost_CHRONO_DEPENDENCIES system)
+    set(_Boost_FILESYSTEM_DEPENDENCIES system)
+    set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+    set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l regex random)
+    set(_Boost_MPI_DEPENDENCIES serialization)
+    set(_Boost_MPI_PYTHON_DEPENDENCIES python mpi serialization)
+    set(_Boost_THREAD_DEPENDENCIES chrono system date_time)
+    set(_Boost_TIMER_DEPENDENCIES chrono system)
+    set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time)
+    set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+  elseif(NOT Boost_VERSION VERSION_LESS 105300 AND Boost_VERSION VERSION_LESS 105400)
+    set(_Boost_ATOMIC_DEPENDENCIES thread chrono system date_time)
+    set(_Boost_CHRONO_DEPENDENCIES system)
+    set(_Boost_FILESYSTEM_DEPENDENCIES system)
+    set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+    set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l regex random)
+    set(_Boost_MPI_DEPENDENCIES serialization)
+    set(_Boost_MPI_PYTHON_DEPENDENCIES python mpi serialization)
+    set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic)
+    set(_Boost_TIMER_DEPENDENCIES chrono system)
+    set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time)
+    set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+  elseif(NOT Boost_VERSION VERSION_LESS 105400 AND Boost_VERSION VERSION_LESS 105500)
+    set(_Boost_ATOMIC_DEPENDENCIES thread chrono system date_time)
+    set(_Boost_CHRONO_DEPENDENCIES system)
+    set(_Boost_FILESYSTEM_DEPENDENCIES system)
+    set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+    set(_Boost_LOG_DEPENDENCIES log_setup date_time system filesystem thread regex chrono)
+    set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l regex random)
+    set(_Boost_MPI_DEPENDENCIES serialization)
+    set(_Boost_MPI_PYTHON_DEPENDENCIES python mpi serialization)
+    set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic)
+    set(_Boost_TIMER_DEPENDENCIES chrono system)
+    set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic)
+    set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+  elseif(NOT Boost_VERSION VERSION_LESS 105500 AND Boost_VERSION VERSION_LESS 105600)
+    set(_Boost_CHRONO_DEPENDENCIES system)
+    set(_Boost_COROUTINE_DEPENDENCIES context system)
+    set(_Boost_FILESYSTEM_DEPENDENCIES system)
+    set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+    set(_Boost_LOG_DEPENDENCIES log_setup date_time system filesystem thread regex chrono)
+    set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l regex random)
+    set(_Boost_MPI_DEPENDENCIES serialization)
+    set(_Boost_MPI_PYTHON_DEPENDENCIES python mpi serialization)
+    set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic)
+    set(_Boost_TIMER_DEPENDENCIES chrono system)
+    set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic)
+    set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+  elseif(NOT Boost_VERSION VERSION_LESS 105600 AND Boost_VERSION VERSION_LESS 105900)
+    set(_Boost_CHRONO_DEPENDENCIES system)
+    set(_Boost_COROUTINE_DEPENDENCIES context system)
+    set(_Boost_FILESYSTEM_DEPENDENCIES system)
+    set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+    set(_Boost_LOG_DEPENDENCIES log_setup date_time system filesystem thread regex chrono)
+    set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic)
+    set(_Boost_MPI_DEPENDENCIES serialization)
+    set(_Boost_MPI_PYTHON_DEPENDENCIES python mpi serialization)
+    set(_Boost_RANDOM_DEPENDENCIES system)
+    set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic)
+    set(_Boost_TIMER_DEPENDENCIES chrono system)
+    set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic)
+    set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+  elseif(NOT Boost_VERSION VERSION_LESS 105900 AND Boost_VERSION VERSION_LESS 106000)
+    set(_Boost_CHRONO_DEPENDENCIES system)
+    set(_Boost_COROUTINE_DEPENDENCIES context system)
+    set(_Boost_FILESYSTEM_DEPENDENCIES system)
+    set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+    set(_Boost_LOG_DEPENDENCIES log_setup date_time system filesystem thread regex chrono atomic)
+    set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic)
+    set(_Boost_MPI_DEPENDENCIES serialization)
+    set(_Boost_MPI_PYTHON_DEPENDENCIES python mpi serialization)
+    set(_Boost_RANDOM_DEPENDENCIES system)
+    set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic)
+    set(_Boost_TIMER_DEPENDENCIES chrono system)
+    set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic)
+    set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+  else()
+    message(WARNING "Imported targets not available for Boost version ${Boost_VERSION}")
+    set(_Boost_IMPORTED_TARGETS FALSE)
+  endif()
+
+  string(TOUPPER ${component} uppercomponent)
+  set(${_ret} ${_Boost_${uppercomponent}_DEPENDENCIES} PARENT_SCOPE)
+  set(_Boost_IMPORTED_TARGETS ${_Boost_IMPORTED_TARGETS} PARENT_SCOPE)
+
+  string(REGEX REPLACE ";" " " _boost_DEPS_STRING "${_Boost_${uppercomponent}_DEPENDENCIES}")
+  if (NOT _boost_DEPS_STRING)
+    set(_boost_DEPS_STRING "(none)")
+  endif()
+  # message(STATUS "Dependencies for Boost::${component}: ${_boost_DEPS_STRING}")
+endfunction()
+
+#
+# Determine if any missing dependencies require adding to the component list.
+#
+# Sets _Boost_${COMPONENT}_DEPENDENCIES for each required component,
+# plus _Boost_IMPORTED_TARGETS (TRUE if imported targets should be
+# defined; FALSE if dependency information is unavailable).
+#
+# componentvar - the component list variable name
+#
+#
+function(_Boost_MISSING_DEPENDENCIES componentvar)
+  # _boost_unprocessed_components - list of components requiring processing
+  # _boost_processed_components - components already processed (or currently being processed)
+  # _boost_new_components - new components discovered for future processing
+  #
+  list(APPEND _boost_unprocessed_components ${${componentvar}})
+
+  while(_boost_unprocessed_components)
+    list(APPEND _boost_processed_components ${_boost_unprocessed_components})
+    foreach(component ${_boost_unprocessed_components})
+      string(TOUPPER ${component} uppercomponent)
+  set(${_ret} ${_Boost_${uppercomponent}_DEPENDENCIES} PARENT_SCOPE)
+      _Boost_COMPONENT_DEPENDENCIES("${component}" _Boost_${uppercomponent}_DEPENDENCIES)
+      set(_Boost_${uppercomponent}_DEPENDENCIES ${_Boost_${uppercomponent}_DEPENDENCIES} PARENT_SCOPE)
+      set(_Boost_IMPORTED_TARGETS ${_Boost_IMPORTED_TARGETS} PARENT_SCOPE)
+      foreach(componentdep ${_Boost_${uppercomponent}_DEPENDENCIES})
+        list(FIND _boost_processed_components "${componentdep}" _boost_component_found)
+        list(FIND _boost_new_components "${componentdep}" _boost_component_new)
+        if (_boost_component_found EQUAL -1 AND _boost_component_new EQUAL -1)
+          list(APPEND _boost_new_components ${componentdep})
+        endif()
+      endforeach()
+    endforeach()
+    set(_boost_unprocessed_components ${_boost_new_components})
+    unset(_boost_new_components)
+  endwhile()
+  set(${componentvar} ${_boost_processed_components} PARENT_SCOPE)
+endfunction()
+
 #
 # End functions/macros
 #
@@ -511,6 +802,10 @@ if(Boost_FIND_VERSION_EXACT)
 else()
   # The user has not requested an exact version.  Among known
   # versions, find those that are acceptable to the user request.
+  #
+  # Note: When adding a new Boost release, also update the dependency
+  # information in _Boost_COMPONENT_DEPENDENCIES.  See the
+  # instructions at the top of _Boost_COMPONENT_DEPENDENCIES.
   set(_Boost_KNOWN_VERSIONS ${Boost_ADDITIONAL_VERSIONS}
 
     "1.59.0" "1.59" "1.58.0" "1.58" "1.57.0" "1.57" "1.56.0" "1.56" "1.55.0" "1.55"
@@ -562,6 +857,16 @@ if(Boost_DEBUG)
                  "Boost_NO_SYSTEM_PATHS = ${Boost_NO_SYSTEM_PATHS}")
 endif()
 
+# Supply Boost_LIB_DIAGNOSTIC_DEFINITIONS as a convenience target. It
+# will only contain any interface definitions on WIN32, but is created
+# on all platforms to keep end user code free from platform dependent
+# code.  Also provide convenience targets to disable autolinking and
+# enable dynamic linking.
+if(NOT TARGET Boost::diagnostic_definitions)
+  add_library(Boost::diagnostic_definitions INTERFACE IMPORTED)
+  add_library(Boost::disable_autolinking INTERFACE IMPORTED)
+  add_library(Boost::dynamic_linking INTERFACE IMPORTED)
+endif()
 if(WIN32)
   # In windows, automatic linking is performed, so you do not have
   # to specify the libraries.  If you are linking to a dynamic
@@ -581,6 +886,12 @@ if(WIN32)
   # code to emit a #pragma message each time a library is selected
   # for linking.
   set(Boost_LIB_DIAGNOSTIC_DEFINITIONS "-DBOOST_LIB_DIAGNOSTIC")
+  set_target_properties(Boost::diagnostic_definitions PROPERTIES
+    INTERFACE_COMPILE_DEFINITIONS "BOOST_LIB_DIAGNOSTIC")
+  set_target_properties(Boost::disable_autolinking PROPERTIES
+    INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_NO_LIB")
+  set_target_properties(Boost::dynamic_linking PROPERTIES
+    INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_DYN_LINK")
 endif()
 
 _Boost_CHECK_SPELLING(Boost_ROOT)
@@ -979,6 +1290,17 @@ if(Boost_VERSION AND Boost_FIND_COMPONENTS)
    endif()
 endif()
 
+# Additional components may be required via component dependencies.
+# Add any missing components to the list.
+_Boost_MISSING_DEPENDENCIES(Boost_FIND_COMPONENTS)
+
+# If thread is required, get the thread libs as a dependency
+list(FIND Boost_FIND_COMPONENTS thread _Boost_THREAD_DEPENDENCY_LIBS)
+if(NOT _Boost_THREAD_DEPENDENCY_LIBS EQUAL -1)
+  include(CMakeFindDependencyMacro)
+  find_dependency(Threads)
+endif()
+
 # If the user changed any of our control inputs flush previous results.
 if(_Boost_CHANGE_LIBDIR OR _Boost_CHANGE_LIBNAME)
   foreach(COMPONENT ${_Boost_COMPONENTS_SEARCHED})
@@ -1221,6 +1543,70 @@ else()
   endforeach()
 endif()
 
+# ------------------------------------------------------------------------
+#  Add imported targets
+# ------------------------------------------------------------------------
+
+if(Boost_FOUND AND _Boost_IMPORTED_TARGETS)
+  # For header-only libraries
+  if(NOT TARGET Boost::boost)
+    add_library(Boost::boost INTERFACE IMPORTED)
+    if(Boost_INCLUDE_DIRS)
+      set_target_properties(Boost::boost PROPERTIES
+        INTERFACE_INCLUDE_DIRECTORIES "${Boost_INCLUDE_DIRS}")
+    endif()
+  endif()
+
+  foreach(COMPONENT ${Boost_FIND_COMPONENTS})
+    if(NOT TARGET Boost::${COMPONENT})
+      string(TOUPPER ${COMPONENT} UPPERCOMPONENT)
+      if(Boost_${UPPERCOMPONENT}_FOUND)
+        if(Boost_USE_STATIC_LIBS)
+          add_library(Boost::${COMPONENT} STATIC IMPORTED)
+        else()
+          # Even if Boost_USE_STATIC_LIBS is OFF, we might have static
+          # libraries as a result.
+          add_library(Boost::${COMPONENT} UNKNOWN IMPORTED)
+        endif()
+        if(Boost_INCLUDE_DIRS)
+          set_target_properties(Boost::${COMPONENT} PROPERTIES
+            INTERFACE_INCLUDE_DIRECTORIES "${Boost_INCLUDE_DIRS}")
+        endif()
+        if(EXISTS "${Boost_${UPPERCOMPONENT}_LIBRARY}")
+          set_target_properties(Boost::${COMPONENT} PROPERTIES
+            IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
+            IMPORTED_LOCATION "${Boost_${UPPERCOMPONENT}_LIBRARY}")
+        endif()
+        if(EXISTS "${Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG}")
+          set_property(TARGET Boost::${COMPONENT} APPEND PROPERTY
+            IMPORTED_CONFIGURATIONS DEBUG)
+          set_target_properties(Boost::${COMPONENT} PROPERTIES
+            IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX"
+            IMPORTED_LOCATION_DEBUG "${Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG}")
+        endif()
+        if(EXISTS "${Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE}")
+          set_property(TARGET Boost::${COMPONENT} APPEND PROPERTY
+            IMPORTED_CONFIGURATIONS RELEASE)
+          set_target_properties(Boost::${COMPONENT} PROPERTIES
+            IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX"
+            IMPORTED_LOCATION_RELEASE "${Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE}")
+        endif()
+        if(_Boost_${UPPERCOMPONENT}_DEPENDENCIES)
+          unset(_Boost_${UPPERCOMPONENT}_TARGET_DEPENDENCIES)
+          foreach(dep ${_Boost_${UPPERCOMPONENT}_DEPENDENCIES})
+            list(APPEND _Boost_${UPPERCOMPONENT}_TARGET_DEPENDENCIES Boost::${dep})
+          endforeach()
+          if(COMPONENT STREQUAL "thread")
+            list(APPEND _Boost_${UPPERCOMPONENT}_TARGET_DEPENDENCIES Threads::Threads)
+          endif()
+          set_target_properties(Boost::${COMPONENT} PROPERTIES
+            INTERFACE_LINK_LIBRARIES "${_Boost_${UPPERCOMPONENT}_TARGET_DEPENDENCIES}")
+        endif()
+      endif()
+    endif()
+  endforeach()
+endif()
+
 # ------------------------------------------------------------------------
 #  Notification to end user about what was found
 # ------------------------------------------------------------------------

+ 4 - 0
Tests/CMakeLists.txt

@@ -1356,6 +1356,10 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
     endif()
   endif()
 
+  if(CMake_TEST_FindBoost)
+    add_subdirectory(FindBoost)
+  endif()
+
   if(CMake_TEST_FindGSL)
     add_subdirectory(FindGSL)
   endif()

+ 10 - 0
Tests/FindBoost/CMakeLists.txt

@@ -0,0 +1,10 @@
+add_test(NAME FindBoost.Test COMMAND
+  ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+  --build-and-test
+  "${CMake_SOURCE_DIR}/Tests/FindBoost/Test"
+  "${CMake_BINARY_DIR}/Tests/FindBoost/Test"
+  ${build_generator_args}
+  --build-project TestFindBoost
+  --build-options ${build_options}
+  --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+  )

+ 18 - 0
Tests/FindBoost/Test/CMakeLists.txt

@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.1)
+project(TestFindBoost CXX)
+include(CTest)
+
+find_package(Boost REQUIRED COMPONENTS filesystem thread)
+
+add_executable(test_boost_tgt main.cxx)
+target_link_libraries(test_boost_tgt
+                      Boost::dynamic_linking
+                      Boost::disable_autolinking
+                      Boost::filesystem
+                      Boost::thread)
+add_test(NAME test_boost_tgt COMMAND test_boost_tgt)
+
+add_executable(test_boost_var main.cxx)
+target_include_directories(test_boost_var PRIVATE ${Boost_INCLUDE_DIRS})
+target_link_libraries(test_boost_var PRIVATE ${Boost_FILESYSTEM_LIBRARIES} ${Boost_SYSTEM_LIBRARIES} ${Boost_THREAD_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
+add_test(NAME test_boost_var COMMAND test_boost_var)

+ 26 - 0
Tests/FindBoost/Test/main.cxx

@@ -0,0 +1,26 @@
+#include <boost/filesystem.hpp>
+#include <boost/thread.hpp>
+
+namespace
+{
+
+  boost::mutex m1;
+  boost::recursive_mutex m2;
+
+  void
+  threadmain()
+  {
+    boost::lock_guard<boost::mutex> lock1(m1);
+    boost::lock_guard<boost::recursive_mutex> lock2(m2);
+
+    boost::filesystem::path p(boost::filesystem::current_path());
+  }
+
+}
+
+int main() {
+  boost::thread foo(threadmain);
+  foo.join();
+
+  return 0;
+}

+ 217 - 0
Utilities/Scripts/BoostScanDeps.cmake

@@ -0,0 +1,217 @@
+# Scan the Boost headers and determine the library dependencies.  Note
+# that this script only scans one Boost version at once; invoke once
+# for each Boost release.  Note that this does require the headers for
+# a given component to match the library name, since this computes
+# inter-library dependencies.  Library components for which this
+# assumption does not hold true and which have dependencies on other
+# Boost libraries will require special-casing.  It also doesn't handle
+# private dependencies not described in the headers, for static
+# library dependencies--this is also a limitation of auto-linking, and
+# I'm unaware of any specific instances where this would be
+# problematic.
+#
+# Invoke in script mode, defining these variables:
+# BOOST_DIR - the root of the boost includes
+#
+# The script will process each directory under the root as a
+# "component".  For each component, all the headers will be scanned to
+# determine the components it depends upon by following all the
+# possible includes from this component.  This is to match the
+# behaviour of autolinking.
+
+# Written by Roger Leigh <[email protected]>
+
+#=============================================================================
+# Copyright 2014-2015 University of Dundee
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+# Determine header dependencies on libraries using the embedded dependency information.
+#
+# component - the component to check (uses all headers from boost/${component})
+# includedir - the path to the Boost headers
+# _ret_libs - list of library dependencies
+#
+function(_Boost_FIND_COMPONENT_DEPENDENCIES component includedir _ret_libs)
+  # _boost_unprocessed_headers - list of headers requiring parsing
+  # _boost_processed_headers - headers already parsed (or currently being parsed)
+  # _boost_new_headers - new headers discovered for future processing
+
+  set(library_component FALSE)
+
+  # Start by finding all headers for the component; header
+  # dependencies via #include will be solved by future passes
+
+  # Special-case since it is part of mpi; look only in boost/mpi/python*
+  if(component STREQUAL "mpi_python")
+    set(_boost_DEPS "python")
+    set(library_component TRUE)
+    file(GLOB_RECURSE _boost_unprocessed_headers
+         RELATIVE "${includedir}"
+         "${includedir}/boost/mpi/python/*")
+    list(INSERT _boost_unprocessed_headers 0 "${includedir}/boost/mpi/python.hpp")
+  # Special-case since it is a serialization variant; look in boost/serialization
+  elseif(component STREQUAL "wserialization")
+    set(library_component TRUE)
+    file(GLOB_RECURSE _boost_unprocessed_headers
+         RELATIVE "${includedir}"
+         "${includedir}/boost/serialization/*")
+    list(INSERT _boost_unprocessed_headers 0 "${includedir}/boost/serialization.hpp")
+  # Not really a library in its own right, but treat it as one
+  elseif(component STREQUAL "math")
+    set(library_component TRUE)
+    file(GLOB_RECURSE _boost_unprocessed_headers
+         RELATIVE "${includedir}"
+         "${includedir}/boost/math/*")
+    list(INSERT _boost_unprocessed_headers 0 "${includedir}/boost/math.hpp")
+  # Single test header
+  elseif(component STREQUAL "unit_test_framework")
+    set(library_component TRUE)
+    set(_boost_unprocessed_headers "${BOOST_DIR}/test/unit_test.hpp")
+  # Single test header
+  elseif(component STREQUAL "prg_exec_monitor")
+    set(library_component TRUE)
+    set(_boost_unprocessed_headers "${BOOST_DIR}/test/prg_exec_monitor.hpp")
+  # Single test header
+  elseif(component STREQUAL "test_exec_monitor")
+    set(library_component TRUE)
+    set(_boost_unprocessed_headers "${BOOST_DIR}/test/test_exec_monitor.hpp")
+  else()
+    # Default behaviour where header directory is the same as the library name.
+    file(GLOB_RECURSE _boost_unprocessed_headers
+         RELATIVE "${includedir}"
+         "${includedir}/boost/${component}/*")
+    list(INSERT _boost_unprocessed_headers 0 "${includedir}/boost/${component}.hpp")
+  endif()
+
+  while(_boost_unprocessed_headers)
+    list(APPEND _boost_processed_headers ${_boost_unprocessed_headers})
+    foreach(header ${_boost_unprocessed_headers})
+      if(EXISTS "${includedir}/${header}")
+        file(STRINGS "${includedir}/${header}" _boost_header_includes REGEX "^#[ \t]*include[ \t]*<boost/[^>][^>]*>")
+        # The optional whitespace before "#" is intentional
+        # (boost/serialization/config.hpp bug).
+        file(STRINGS "${includedir}/${header}" _boost_header_deps REGEX "^[ \t]*#[ \t]*define[ \t][ \t]*BOOST_LIB_NAME[ \t][ \t]*boost_")
+
+        foreach(line ${_boost_header_includes})
+          string(REGEX REPLACE "^#[ \t]*include[ \t]*<(boost/[^>][^>]*)>.*" "\\1" _boost_header_match "${line}")
+          list(FIND _boost_processed_headers "${_boost_header_match}" _boost_header_processed)
+          list(FIND _boost_new_headers "${_boost_header_match}" _boost_header_new)
+          if (_boost_header_processed EQUAL -1 AND _boost_header_new EQUAL -1)
+            list(APPEND _boost_new_headers ${_boost_header_match})
+          endif()
+        endforeach()
+
+        foreach(line ${_boost_header_deps})
+          string(REGEX REPLACE "^[ \t]*#[ \t]*define[ \t][ \t]*BOOST_LIB_NAME[ \t][ \t]*boost_([^ \t][^ \t]*).*" "\\1" _boost_component_match "${line}")
+          list(FIND _boost_DEPS "${_boost_component_match}" _boost_dep_found)
+          if(_boost_component_match STREQUAL "bzip2" OR
+             _boost_component_match STREQUAL "zlib")
+            # These components may or may not be required; not
+            # possible to tell without knowing where and when
+            # BOOST_BZIP2_BINARY and BOOST_ZLIB_BINARY are defined.
+            # If building against an external zlib or bzip2, this is
+            # undesirable.
+            continue()
+          endif()
+          if(component STREQUAL "mpi" AND
+             (_boost_component_match STREQUAL "mpi_python" OR
+              _boost_component_match STREQUAL "python"))
+            # Optional python dependency; skip to avoid making it a
+            # hard dependency (handle as special-case for mpi_python).
+            continue()
+          endif()
+          if (_boost_dep_found EQUAL -1 AND
+              NOT "${_boost_component_match}" STREQUAL "${component}")
+            list(APPEND _boost_DEPS "${_boost_component_match}")
+          endif()
+          if("${_boost_component_match}" STREQUAL "${component}")
+            set(library_component TRUE)
+          endif()
+        endforeach()
+      endif()
+    endforeach()
+    set(_boost_unprocessed_headers ${_boost_new_headers})
+    unset(_boost_new_headers)
+  endwhile()
+
+  # message(STATUS "Unfiltered dependencies for Boost::${component}: ${_boost_DEPS}")
+
+  if(NOT library_component)
+    unset(_boost_DEPS)
+  endif()
+  set(${_ret_libs} ${_boost_DEPS} PARENT_SCOPE)
+
+  #string(REGEX REPLACE ";" " " _boost_DEPS_STRING "${_boost_DEPS}")
+  #if (NOT _boost_DEPS_STRING)
+  #  set(_boost_DEPS_STRING "(none)")
+  #endif()
+  #message(STATUS "Dependencies for Boost::${component}: ${_boost_DEPS_STRING}")
+endfunction()
+
+
+message(STATUS "Scanning ${BOOST_DIR}")
+
+# List of all directories and files
+file(GLOB boost_contents RELATIVE "${BOOST_DIR}/boost" "${BOOST_DIR}/boost/*")
+
+# Components as directories
+foreach(component ${boost_contents})
+  if(IS_DIRECTORY "${BOOST_DIR}/boost/${component}")
+    list(APPEND boost_components "${component}")
+  endif()
+endforeach()
+
+# The following components are not top-level directories, so require
+# special-casing:
+
+# Special-case mpi_python, since it's a part of mpi
+if(IS_DIRECTORY "${BOOST_DIR}/boost/mpi" AND
+   IS_DIRECTORY "${BOOST_DIR}/boost/python")
+ list(APPEND boost_components "mpi_python")
+endif()
+# Special-case wserialization, which is a variant of serialization
+if(IS_DIRECTORY "${BOOST_DIR}/boost/serialization")
+ list(APPEND boost_components "wserialization")
+endif()
+# Special-case math* since there are six libraries, but no actual math
+# library component.  Handle specially when scanning above.
+#
+# Special-case separate test libraries, which are all part of test
+if(EXISTS "${BOOST_DIR}/test/unit_test.hpp")
+ list(APPEND boost_components "unit_test_framework")
+endif()
+if(EXISTS "${BOOST_DIR}/test/prg_exec_monitor.hpp")
+ list(APPEND boost_components "prg_exec_monitor")
+endif()
+if(EXISTS "${BOOST_DIR}/test/test_exec_monitor.hpp")
+ list(APPEND boost_components "test_exec_monitor")
+endif()
+
+if(boost_components)
+  list(SORT boost_components)
+endif()
+
+# Process each component defined above
+foreach(component ${boost_components})
+  string(TOUPPER ${component} UPPERCOMPONENT)
+  _Boost_FIND_COMPONENT_DEPENDENCIES("${component}" "${BOOST_DIR}"
+                                     _Boost_${UPPERCOMPONENT}_LIBRARY_DEPENDENCIES)
+endforeach()
+
+# Output results
+foreach(component ${boost_components})
+  string(TOUPPER ${component} UPPERCOMPONENT)
+  if(_Boost_${UPPERCOMPONENT}_LIBRARY_DEPENDENCIES)
+    string(REGEX REPLACE ";" " " _boost_DEPS_STRING "${_Boost_${UPPERCOMPONENT}_LIBRARY_DEPENDENCIES}")
+    message(STATUS "set(_Boost_${UPPERCOMPONENT}_DEPENDENCIES ${_boost_DEPS_STRING})")
+  endif()
+endforeach()