BoostScanDeps.cmake 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. # Scan the Boost headers and determine the library dependencies. Note
  2. # that this script only scans one Boost version at once; invoke once
  3. # for each Boost release. Note that this does require the headers for
  4. # a given component to match the library name, since this computes
  5. # inter-library dependencies. Library components for which this
  6. # assumption does not hold true and which have dependencies on other
  7. # Boost libraries will require special-casing. It also doesn't handle
  8. # private dependencies not described in the headers, for static
  9. # library dependencies--this is also a limitation of auto-linking, and
  10. # I'm unaware of any specific instances where this would be
  11. # problematic.
  12. #
  13. # Invoke in script mode, defining these variables:
  14. # BOOST_DIR - the root of the boost includes
  15. #
  16. # The script will process each directory under the root as a
  17. # "component". For each component, all the headers will be scanned to
  18. # determine the components it depends upon by following all the
  19. # possible includes from this component. This is to match the
  20. # behaviour of autolinking.
  21. # Written by Roger Leigh <[email protected]>
  22. #=============================================================================
  23. # Copyright 2014-2015 University of Dundee
  24. #
  25. # Distributed under the OSI-approved BSD License (the "License");
  26. # see accompanying file Copyright.txt for details.
  27. #
  28. # This software is distributed WITHOUT ANY WARRANTY; without even the
  29. # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  30. # See the License for more information.
  31. #=============================================================================
  32. # (To distribute this file outside of CMake, substitute the full
  33. # License text for the above reference.)
  34. # Determine header dependencies on libraries using the embedded dependency information.
  35. #
  36. # component - the component to check (uses all headers from boost/${component})
  37. # includedir - the path to the Boost headers
  38. # _ret_libs - list of library dependencies
  39. #
  40. function(_Boost_FIND_COMPONENT_DEPENDENCIES component includedir _ret_libs)
  41. # _boost_unprocessed_headers - list of headers requiring parsing
  42. # _boost_processed_headers - headers already parsed (or currently being parsed)
  43. # _boost_new_headers - new headers discovered for future processing
  44. set(library_component FALSE)
  45. # Start by finding all headers for the component; header
  46. # dependencies via #include will be solved by future passes
  47. # Special-case since it is part of mpi; look only in boost/mpi/python*
  48. if(component STREQUAL "mpi_python")
  49. set(_boost_DEPS "python")
  50. set(library_component TRUE)
  51. file(GLOB_RECURSE _boost_unprocessed_headers
  52. RELATIVE "${includedir}"
  53. "${includedir}/boost/mpi/python/*")
  54. list(INSERT _boost_unprocessed_headers 0 "${includedir}/boost/mpi/python.hpp")
  55. # Special-case since it is a serialization variant; look in boost/serialization
  56. elseif(component STREQUAL "wserialization")
  57. set(library_component TRUE)
  58. file(GLOB_RECURSE _boost_unprocessed_headers
  59. RELATIVE "${includedir}"
  60. "${includedir}/boost/serialization/*")
  61. list(INSERT _boost_unprocessed_headers 0 "${includedir}/boost/serialization.hpp")
  62. # Not really a library in its own right, but treat it as one
  63. elseif(component STREQUAL "math")
  64. set(library_component TRUE)
  65. file(GLOB_RECURSE _boost_unprocessed_headers
  66. RELATIVE "${includedir}"
  67. "${includedir}/boost/math/*")
  68. list(INSERT _boost_unprocessed_headers 0 "${includedir}/boost/math.hpp")
  69. # Single test header
  70. elseif(component STREQUAL "unit_test_framework")
  71. set(library_component TRUE)
  72. set(_boost_unprocessed_headers "${BOOST_DIR}/test/unit_test.hpp")
  73. # Single test header
  74. elseif(component STREQUAL "prg_exec_monitor")
  75. set(library_component TRUE)
  76. set(_boost_unprocessed_headers "${BOOST_DIR}/test/prg_exec_monitor.hpp")
  77. # Single test header
  78. elseif(component STREQUAL "test_exec_monitor")
  79. set(library_component TRUE)
  80. set(_boost_unprocessed_headers "${BOOST_DIR}/test/test_exec_monitor.hpp")
  81. else()
  82. # Default behaviour where header directory is the same as the library name.
  83. file(GLOB_RECURSE _boost_unprocessed_headers
  84. RELATIVE "${includedir}"
  85. "${includedir}/boost/${component}/*")
  86. list(INSERT _boost_unprocessed_headers 0 "${includedir}/boost/${component}.hpp")
  87. endif()
  88. while(_boost_unprocessed_headers)
  89. list(APPEND _boost_processed_headers ${_boost_unprocessed_headers})
  90. foreach(header ${_boost_unprocessed_headers})
  91. if(EXISTS "${includedir}/${header}")
  92. file(STRINGS "${includedir}/${header}" _boost_header_includes REGEX "^#[ \t]*include[ \t]*<boost/[^>][^>]*>")
  93. # The optional whitespace before "#" is intentional
  94. # (boost/serialization/config.hpp bug).
  95. file(STRINGS "${includedir}/${header}" _boost_header_deps REGEX "^[ \t]*#[ \t]*define[ \t][ \t]*BOOST_LIB_NAME[ \t][ \t]*boost_")
  96. foreach(line ${_boost_header_includes})
  97. string(REGEX REPLACE "^#[ \t]*include[ \t]*<(boost/[^>][^>]*)>.*" "\\1" _boost_header_match "${line}")
  98. list(FIND _boost_processed_headers "${_boost_header_match}" _boost_header_processed)
  99. list(FIND _boost_new_headers "${_boost_header_match}" _boost_header_new)
  100. if (_boost_header_processed EQUAL -1 AND _boost_header_new EQUAL -1)
  101. list(APPEND _boost_new_headers ${_boost_header_match})
  102. endif()
  103. endforeach()
  104. foreach(line ${_boost_header_deps})
  105. string(REGEX REPLACE "^[ \t]*#[ \t]*define[ \t][ \t]*BOOST_LIB_NAME[ \t][ \t]*boost_([^ \t][^ \t]*).*" "\\1" _boost_component_match "${line}")
  106. list(FIND _boost_DEPS "${_boost_component_match}" _boost_dep_found)
  107. if(_boost_component_match STREQUAL "bzip2" OR
  108. _boost_component_match STREQUAL "zlib")
  109. # These components may or may not be required; not
  110. # possible to tell without knowing where and when
  111. # BOOST_BZIP2_BINARY and BOOST_ZLIB_BINARY are defined.
  112. # If building against an external zlib or bzip2, this is
  113. # undesirable.
  114. continue()
  115. endif()
  116. if(component STREQUAL "mpi" AND
  117. (_boost_component_match STREQUAL "mpi_python" OR
  118. _boost_component_match STREQUAL "python"))
  119. # Optional python dependency; skip to avoid making it a
  120. # hard dependency (handle as special-case for mpi_python).
  121. continue()
  122. endif()
  123. if (_boost_dep_found EQUAL -1 AND
  124. NOT "${_boost_component_match}" STREQUAL "${component}")
  125. list(APPEND _boost_DEPS "${_boost_component_match}")
  126. endif()
  127. if("${_boost_component_match}" STREQUAL "${component}")
  128. set(library_component TRUE)
  129. endif()
  130. endforeach()
  131. endif()
  132. endforeach()
  133. set(_boost_unprocessed_headers ${_boost_new_headers})
  134. unset(_boost_new_headers)
  135. endwhile()
  136. # message(STATUS "Unfiltered dependencies for Boost::${component}: ${_boost_DEPS}")
  137. if(NOT library_component)
  138. unset(_boost_DEPS)
  139. endif()
  140. set(${_ret_libs} ${_boost_DEPS} PARENT_SCOPE)
  141. #string(REGEX REPLACE ";" " " _boost_DEPS_STRING "${_boost_DEPS}")
  142. #if (NOT _boost_DEPS_STRING)
  143. # set(_boost_DEPS_STRING "(none)")
  144. #endif()
  145. #message(STATUS "Dependencies for Boost::${component}: ${_boost_DEPS_STRING}")
  146. endfunction()
  147. message(STATUS "Scanning ${BOOST_DIR}")
  148. # List of all directories and files
  149. file(GLOB boost_contents RELATIVE "${BOOST_DIR}/boost" "${BOOST_DIR}/boost/*")
  150. # Components as directories
  151. foreach(component ${boost_contents})
  152. if(IS_DIRECTORY "${BOOST_DIR}/boost/${component}")
  153. list(APPEND boost_components "${component}")
  154. endif()
  155. endforeach()
  156. # The following components are not top-level directories, so require
  157. # special-casing:
  158. # Special-case mpi_python, since it's a part of mpi
  159. if(IS_DIRECTORY "${BOOST_DIR}/boost/mpi" AND
  160. IS_DIRECTORY "${BOOST_DIR}/boost/python")
  161. list(APPEND boost_components "mpi_python")
  162. endif()
  163. # Special-case wserialization, which is a variant of serialization
  164. if(IS_DIRECTORY "${BOOST_DIR}/boost/serialization")
  165. list(APPEND boost_components "wserialization")
  166. endif()
  167. # Special-case math* since there are six libraries, but no actual math
  168. # library component. Handle specially when scanning above.
  169. #
  170. # Special-case separate test libraries, which are all part of test
  171. if(EXISTS "${BOOST_DIR}/test/unit_test.hpp")
  172. list(APPEND boost_components "unit_test_framework")
  173. endif()
  174. if(EXISTS "${BOOST_DIR}/test/prg_exec_monitor.hpp")
  175. list(APPEND boost_components "prg_exec_monitor")
  176. endif()
  177. if(EXISTS "${BOOST_DIR}/test/test_exec_monitor.hpp")
  178. list(APPEND boost_components "test_exec_monitor")
  179. endif()
  180. if(boost_components)
  181. list(SORT boost_components)
  182. endif()
  183. # Process each component defined above
  184. foreach(component ${boost_components})
  185. string(TOUPPER ${component} UPPERCOMPONENT)
  186. _Boost_FIND_COMPONENT_DEPENDENCIES("${component}" "${BOOST_DIR}"
  187. _Boost_${UPPERCOMPONENT}_LIBRARY_DEPENDENCIES)
  188. endforeach()
  189. # Output results
  190. foreach(component ${boost_components})
  191. string(TOUPPER ${component} UPPERCOMPONENT)
  192. if(_Boost_${UPPERCOMPONENT}_LIBRARY_DEPENDENCIES)
  193. string(REGEX REPLACE ";" " " _boost_DEPS_STRING "${_Boost_${UPPERCOMPONENT}_LIBRARY_DEPENDENCIES}")
  194. message(STATUS "set(_Boost_${UPPERCOMPONENT}_DEPENDENCIES ${_boost_DEPS_STRING})")
  195. endif()
  196. endforeach()