> On 11/30/2015 11:54 AM, rle...@codelibre.net wrote:
>> I do worry about the maintenance burden of hardcoding the information in
>> the script.
>
> I do too.  We already have to update the script for each Boost release.
> This is among the reasons the work is better integrated with upstream
> Boost instead.

I'd definitely like to see this for future Boost releases, though for
historical releases we're a bit stuck.  I'll revisit the work I pointed to
and see if I can figure out bjam/boost-build and integrate this, since it
would effectively give us CMake configuration "for free" off the back of
the autolink data, and would also come directly from the compiler so
wouldn't require parsing all the headers by hand.

>> How should this cater for dependency changes between boost releases?
>> How far back in time does this dependency information need to go?
>
> One would need to fill out tables per version and then detect the
> version to populate the info.  Just don't provide imported targets
> if the version does not have dependency info available.  If someone
> needs it they can run something to fill out the tables for their
> version and submit a patch.

I've attached an updated version of the patch which does this.  The
behaviour is otherwise identical to the earlier patches.  It's less awful
than I expected--the information for many Boost releases was the same so
it could be reduced in size significantly.  This also includes a utility
script to do the parsing, so it can be potentially used for future Boost
releases as well.  I've run the script against all versions of Boost
supported by the script, and it's verified with the unit test for some of
the components.

Just FYI, the boost components in 1.59 are as follows:

Header          Library             Mismatched name
--------------- ------------------- ---------------
archive         serialization       *
archive         wserialization      *
atomic          atomic
chrono          chrono
container       container
context         context
coroutine2      coroutine           *
coroutine       coroutine
date_time       date_time
endian          endian
filesystem      filesystem
iostreams       iostreams
locale          locale
log             date_time           (*)
log             log
log             log_setup
math            math_c99            *
math            math_c99f           *
math            math_c99l           *
math            math_tr1            *
math            math_tr1f           *
math            math_tr1l           *
mpi             mpi
mpi             mpi_python          *
program_options program_options
python          python
random          random
regex           regex
serialization   serialization
signals         signals
system          system
test            prg_exec_monitor    *
test            test_exec_monitor   *
test            unit_test_framework *
thread          thread
timer           timer
wave            wave

The dependency parsing handles the case where the component library name
matches the include directory name.  For most cases, this is correct, but
there are cases marked * where it isn't.  These cases require the user to
request the appropriate component name by hand with find_package (since
the include directory name isn't a valid component name).  For most cases
we can't make the assumption since e.g. if you use <boost/archive> we have
no idea which serialisation library to use; and if you use <boost/math> we
don't know which of the math_* libraries you /might/ use.  We have to
leave that up to the user.  Likewise for <boost/test>.  For these
libraries we also need to special-case the dependency info since we can't
easily get it via the headers; currently only mpi_python needed handling
in this way; the others have no dependencies.

The above isn't really a problem, it's just something to be aware of which
limits just how user-friendly we can make things.  The granularity of the
FindBoost component selection means the user will need to know which
libraries they need when they use certain headers; but this was already
the case for the variables, and is no different for the imported targets.


Regards,
Roger
>From cbfb157c60ab7bdc22833db1534d1663f869ae4e Mon Sep 17 00:00:00 2001
From: Roger Leigh <rle...@dundee.ac.uk>
Date: Mon, 16 Nov 2015 13:21:33 +0000
Subject: [PATCH] FindBoost: Add imported targets

---
 Modules/FindBoost.cmake             | 295 ++++++++++++++++++++++++++++++++++++
 Tests/CMakeLists.txt                |   4 +
 Tests/FindBoost/CMakeLists.txt      |  10 ++
 Tests/FindBoost/Test/CMakeLists.txt |  18 +++
 Tests/FindBoost/Test/main.cxx       |  26 ++++
 Utilities/Boost/ScanDeps.cmake      | 156 +++++++++++++++++++
 6 files changed, 509 insertions(+)
 create mode 100644 Tests/FindBoost/CMakeLists.txt
 create mode 100644 Tests/FindBoost/Test/CMakeLists.txt
 create mode 100644 Tests/FindBoost/Test/main.cxx
 create mode 100644 Utilities/Boost/ScanDeps.cmake

diff --git a/Modules/FindBoost.cmake b/Modules/FindBoost.cmake
index 33e6a49..a3e8474 100644
--- a/Modules/FindBoost.cmake
+++ b/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
@@ -472,6 +507,172 @@ function(_Boost_GUESS_COMPILER_PREFIX _ret)
 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/Boost/ScanDeps.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.
+  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)
+  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)
+    set(_Boost_WAVE_DEPENDENCIES filesystem system thread)
+  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_MPI_PYTHON_DEPENDENCIES python)
+    set(_Boost_WAVE_DEPENDENCIES filesystem system thread)
+  elseif(NOT Boost_VERSION VERSION_LESS 103800 AND Boost_VERSION VERSION_LESS 104700)
+    set(_Boost_FILESYSTEM_DEPENDENCIES system)
+    set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+    set(_Boost_MPI_PYTHON_DEPENDENCIES python)
+    set(_Boost_THREAD_DEPENDENCIES date_time)
+    set(_Boost_WAVE_DEPENDENCIES filesystem system thread date_time)
+  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_MPI_PYTHON_DEPENDENCIES python)
+    set(_Boost_THREAD_DEPENDENCIES date_time)
+    set(_Boost_WAVE_DEPENDENCIES filesystem system thread date_time)
+  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_MPI_PYTHON_DEPENDENCIES python)
+    set(_Boost_THREAD_DEPENDENCIES date_time)
+    set(_Boost_TIMER_DEPENDENCIES chrono system)
+    set(_Boost_WAVE_DEPENDENCIES filesystem system thread date_time)
+  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_MPI_PYTHON_DEPENDENCIES python)
+    set(_Boost_THREAD_DEPENDENCIES chrono system date_time)
+    set(_Boost_TIMER_DEPENDENCIES chrono system)
+    set(_Boost_WAVE_DEPENDENCIES filesystem system thread chrono date_time)
+  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_MPI_PYTHON_DEPENDENCIES python)
+    set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic)
+    set(_Boost_TIMER_DEPENDENCIES chrono system)
+    set(_Boost_WAVE_DEPENDENCIES filesystem system thread chrono date_time)
+  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_MPI_PYTHON_DEPENDENCIES python)
+    set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic)
+    set(_Boost_TIMER_DEPENDENCIES chrono system)
+    set(_Boost_WAVE_DEPENDENCIES filesystem system thread chrono date_time atomic)
+  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_MPI_PYTHON_DEPENDENCIES python)
+    set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic)
+    set(_Boost_TIMER_DEPENDENCIES chrono system)
+    set(_Boost_WAVE_DEPENDENCIES filesystem system thread chrono date_time atomic)
+  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_MPI_PYTHON_DEPENDENCIES python)
+    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 thread chrono date_time atomic)
+  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_MPI_PYTHON_DEPENDENCIES python)
+    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 thread chrono date_time atomic)
+  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 +712,9 @@ 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
   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 +766,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 +795,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 +1199,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})
@@ -1222,6 +1453,70 @@ else()
 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
 # ------------------------------------------------------------------------
 
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 5fd7159..6c4567d 100644
--- a/Tests/CMakeLists.txt
+++ b/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()
diff --git a/Tests/FindBoost/CMakeLists.txt b/Tests/FindBoost/CMakeLists.txt
new file mode 100644
index 0000000..259ee26
--- /dev/null
+++ b/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>
+  )
diff --git a/Tests/FindBoost/Test/CMakeLists.txt b/Tests/FindBoost/Test/CMakeLists.txt
new file mode 100644
index 0000000..ce50fc7
--- /dev/null
+++ b/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)
diff --git a/Tests/FindBoost/Test/main.cxx b/Tests/FindBoost/Test/main.cxx
new file mode 100644
index 0000000..0f44f30
--- /dev/null
+++ b/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;
+}
diff --git a/Utilities/Boost/ScanDeps.cmake b/Utilities/Boost/ScanDeps.cmake
new file mode 100644
index 0000000..37e4112
--- /dev/null
+++ b/Utilities/Boost/ScanDeps.cmake
@@ -0,0 +1,156 @@
+# 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 <rle...@codelibre.net>
+
+#=============================================================================
+# 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
+
+  # Start by finding all headers for the component; header
+  # dependencies will be solved by future passes
+  file(GLOB_RECURSE _boost_unprocessed_headers
+       RELATIVE "${includedir}"
+       "${includedir}/boost/${component}/*")
+  list(INSERT _boost_unprocessed_headers 0 "${includedir}/boost/${component}.hpp")
+
+  set(library_component FALSE)
+
+  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/[^>][^>]*>")
+        file(STRINGS "${includedir}/${header}" _boost_header_deps REGEX "^#[ \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]*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((_boost_component_match STREQUAL "mpi_python" OR
+              _boost_component_match STREQUAL "python") AND
+             component STREQUAL "mpi")
+            # Optional python dependency; skip to avoid making it a
+            # hard dependency (handle as special-case, below).
+            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()
+
+  if(component STREQUAL "mpi_python") # Special-case since it is part of mpi
+    set(_boost_DEPS "python")
+    set(library_component TRUE)
+  endif()
+
+  if(NOT library_component)
+    unset(_boost_DEPS)
+  endif()
+
+  set(${_ret_libs} ${_boost_DEPS} PARENT_SCOPE)
+  string(TOUPPER ${component} uppercomponent)
+  set(_Boost_${uppercomponent}_DEPENDENCIES ${_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 "Finding dependencies for Boost::${component} (libraries): ${_boost_DEPS_STRING}")
+
+endfunction()
+
+
+message(STATUS "Scanning ${BOOST_DIR}")
+
+file(GLOB boost_contents RELATIVE "${BOOST_DIR}/boost" "${BOOST_DIR}/boost/*")
+
+foreach(component ${boost_contents})
+  if(IS_DIRECTORY "${BOOST_DIR}/boost/${component}")
+    list(APPEND boost_components "${component}")
+  endif()
+endforeach()
+if(IS_DIRECTORY "${BOOST_DIR}/boost/mpi" AND
+   IS_DIRECTORY "${BOOST_DIR}/boost/python")
+ list(APPEND boost_components "mpi_python")
+endif()
+if(boost_components)
+  list(SORT boost_components)
+endif()
+
+foreach(component ${boost_components})
+  _Boost_FIND_COMPONENT_DEPENDENCIES("${component}" "${BOOST_DIR}"
+                                     _Boost_${component}_LIBRARY_DEPENDENCIES)
+endforeach()
+
+foreach(component ${boost_components})
+  if(_Boost_${component}_LIBRARY_DEPENDENCIES)
+    string(TOUPPER ${component} UPPERCOMPONENT)
+    string(REGEX REPLACE ";" " " _boost_DEPS_STRING "${_Boost_${component}_LIBRARY_DEPENDENCIES}")
+    message(STATUS "set(_Boost_${UPPERCOMPONENT}_DEPENDENCIES ${_boost_DEPS_STRING})")
+  endif()
+endforeach()
-- 
2.5.0
-- 

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: 
http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more 
information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at 
http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake-developers

Reply via email to