diff options
author | Roger Leigh <rleigh@codelibre.net> | 2015-12-01 21:50:03 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2015-12-02 14:40:17 (GMT) |
commit | 8a60e6961e84fc3177d2439fe6b2b5f972104cd9 (patch) | |
tree | 89f5eacb450cdd2c69d90db09127e2018760e31b | |
parent | 4e29a514ad83c5711e7ee894b825203e8c302269 (diff) | |
download | CMake-8a60e6961e84fc3177d2439fe6b2b5f972104cd9.zip CMake-8a60e6961e84fc3177d2439fe6b2b5f972104cd9.tar.gz CMake-8a60e6961e84fc3177d2439fe6b2b5f972104cd9.tar.bz2 |
Utilities: Add BoostScanDeps script
This script scans Boost headers in order to determine inter-library
dependencies, using the "autolink" information embedded in the
headers for automatic linking on Windows. This information is then
output in a form suitable for use in FindBoost.cmake.
-rw-r--r-- | Utilities/Scripts/BoostScanDeps.cmake | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/Utilities/Scripts/BoostScanDeps.cmake b/Utilities/Scripts/BoostScanDeps.cmake new file mode 100644 index 0000000..1fbea4b --- /dev/null +++ b/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 <rleigh@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 + + 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() |