EnableSanitizer.cmake 5.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. # Ceres Solver - A fast non-linear least squares minimizer
  2. # Copyright 2019 Google Inc. All rights reserved.
  3. # http://ceres-solver.org/
  4. #
  5. # Redistribution and use in source and binary forms, with or without
  6. # modification, are permitted provided that the following conditions are met:
  7. #
  8. # * Redistributions of source code must retain the above copyright notice,
  9. # this list of conditions and the following disclaimer.
  10. # * Redistributions in binary form must reproduce the above copyright notice,
  11. # this list of conditions and the following disclaimer in the documentation
  12. # and/or other materials provided with the distribution.
  13. # * Neither the name of Google Inc. nor the names of its contributors may be
  14. # used to endorse or promote products derived from this software without
  15. # specific prior written permission.
  16. #
  17. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  18. # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  21. # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  22. # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  23. # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  24. # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  25. # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  26. # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  27. # POSSIBILITY OF SUCH DAMAGE.
  28. #
  29. # Author: alexs.mac@gmail.com (Alex Stewart)
  30. # Usage: enable_sanitizer(REQUIRED_SANITIZERS) where REQUIRED_SANITIZERS should
  31. # contain the list of sanitizers to enable by updating CMAKE_CXX_FLAGS and
  32. # CMAKE_EXE_LINKER_FLAGS.
  33. #
  34. # The specified sanitizers will be checked both for compatibility with the
  35. # current compiler and with each other as some sanitizers are mutually
  36. # exclusive.
  37. macro(enable_sanitizer)
  38. # According to the Clang documentation [1] the following sanitizers are
  39. # mututally exclusive.
  40. # [1]: https://clang.llvm.org/docs/UsersManual.html#controlling-code-generation
  41. set(INCOMPATIBLE_SANITIZERS address thread memory)
  42. # Set the recommended additional common compile flags for any sanitizer to
  43. # get the best possible output, e.g [2] but make them visible in the cache
  44. # so that the user can edit them if required.
  45. # [2]: https://clang.llvm.org/docs/AddressSanitizer.html#usage
  46. set(COMMON_SANITIZER_COMPILE_OPTIONS
  47. "-g -fno-omit-frame-pointer -fno-optimize-sibling-calls"
  48. CACHE STRING "Common compile flags enabled for any sanitizer")
  49. # Check that the specified list of sanitizers to enable does not include
  50. # multiple entries from the incompatible list.
  51. set(MERGED_SANITIZERS ${ARGN} ${INCOMPATIBLE_SANITIZERS})
  52. list(LENGTH MERGED_SANITIZERS COMBINED_LENGTH)
  53. list(REMOVE_DUPLICATES MERGED_SANITIZERS)
  54. list(LENGTH MERGED_SANITIZERS COMBINED_LENGTH_NO_DUPLICATES)
  55. math(EXPR VALID_LENGTH "${COMBINED_LENGTH} - 1")
  56. if (COMBINED_LENGTH_NO_DUPLICATES LESS VALID_LENGTH)
  57. include(PrettyPrintCMakeList)
  58. pretty_print_cmake_list(REQUESTED_SANITIZERS ${ARGN})
  59. pretty_print_cmake_list(
  60. PRETTY_INCOMPATIBLE_SANITIZERS ${INCOMPATIBLE_SANITIZERS})
  61. message(FATAL_ERROR "Found incompatible sanitizers in requested set: "
  62. "${REQUESTED_SANITIZERS}. The following sanitizers are mutually "
  63. "exclusive: ${PRETTY_INCOMPATIBLE_SANITIZERS}")
  64. endif()
  65. # Until CMake 3.14 and CMAKE_REQUIRED_LINK_OPTIONS there was no equivalent to
  66. # CMAKE_REQUIRED_FLAGS for try_compile() for linker flags. However, in CMake
  67. # 3.2 CMP0056 was introduced that when enabled passes CMAKE_EXE_LINKER_FLAGS
  68. # to try_compile() which allows us to achieve the same effect.
  69. cmake_policy(SET CMP0056 NEW)
  70. include(CheckCXXCompilerFlag)
  71. unset(ADDED_SANITIZER)
  72. foreach(REQUESTED_SANITIZER ${ARGN})
  73. set(SANITIZER_FLAG -fsanitize=${REQUESTED_SANITIZER})
  74. # Save the current CMAKE_EXE_LINKER_FLAGS before modifying it to test for
  75. # the existence of the sanitizer flag so that we can revert after the test.
  76. set(INITIAL_CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
  77. set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${SANITIZER_FLAG}")
  78. check_cxx_compiler_flag(${SANITIZER_FLAG} HAVE_SANITIZER)
  79. set(CMAKE_EXE_LINKER_FLAGS "${INITIAL_CMAKE_EXE_LINKER_FLAGS}")
  80. if (NOT HAVE_SANITIZER)
  81. message(FATAL_ERROR "Specified sanitizer: ${REQUESTED_SANITIZER} is not "
  82. "supported by the compiler.")
  83. endif()
  84. message(STATUS "Enabling sanitizer: ${REQUESTED_SANITIZER}")
  85. set(ADDED_SANITIZER TRUE)
  86. # As per the Clang documentation, the sanitizer flags must be added to both
  87. # the compiler and linker flags.
  88. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SANITIZER_FLAG}")
  89. set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${SANITIZER_FLAG}")
  90. endforeach()
  91. if (ADDED_SANITIZER)
  92. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMMON_SANITIZER_COMPILE_OPTIONS}")
  93. endif()
  94. endmacro()