| # Distributed under the OSI-approved BSD 3-Clause License. See accompanying | |
| # file LICENSE.rst or https://cmake.org/licensing for details. | |
| # 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 | |
| # behavior of autolinking. | |
| # Written by Roger Leigh <rleigh@codelibre.net> | |
| # 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 | |
| file(GLOB_RECURSE _boost_mpi_python_headers | |
| RELATIVE "${includedir}" | |
| "${includedir}/boost/mpi/python/*") | |
| list(INSERT _boost_mpi_python_headers 0 "boost/mpi/python.hpp") | |
| file(GLOB_RECURSE _boost_python_numpy_headers | |
| RELATIVE "${includedir}" | |
| "${includedir}/boost/python/numpy/*") | |
| list(INSERT _boost_python_numpy_headers 0 "boost/python/numpy.hpp") | |
| # Special-case since it is part of mpi; look only in boost/mpi/python* | |
| if(component STREQUAL "mpi_python") | |
| set(_boost_DEPS "python\${component_python_version}") | |
| set(library_component TRUE) | |
| set(_boost_unprocessed_headers ${_boost_mpi_python_headers}) | |
| # Special-case since it is part of python; look only in boost/python/numpy* | |
| elseif(component STREQUAL "numpy") | |
| set(_boost_DEPS "python\${component_python_version}") | |
| set(library_component TRUE) | |
| set(_boost_unprocessed_headers ${_boost_python_numpy_headers}) | |
| # 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 "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 "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 behavior 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 "boost/${component}.hpp") | |
| list(REMOVE_ITEM _boost_unprocessed_headers ${_boost_mpi_python_headers} ${_boost_python_numpy_headers}) | |
| 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}") | |
| string(REPLACE "python3" "python" _boost_component_match "${_boost_component_match}") | |
| string(REPLACE "numpy3" "numpy" _boost_component_match "${_boost_component_match}") | |
| 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(component STREQUAL "python" AND | |
| _boost_component_match STREQUAL "numpy") | |
| # Optional python dependency; skip to avoid making it a | |
| # hard dependency (handle as special-case for numpy). | |
| continue() | |
| endif() | |
| if(component STREQUAL "nowide" AND | |
| _boost_component_match STREQUAL "filesystem") | |
| # Optional filesystem dependency; skip to avoid making it a | |
| # hard dependency. | |
| 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 numpy, since it's a part of python | |
| if(IS_DIRECTORY "${BOOST_DIR}/boost/python" AND | |
| IS_DIRECTORY "${BOOST_DIR}/boost/python/numpy") | |
| list(APPEND boost_components "numpy") | |
| 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() |