about summary refs log tree commit diff homepage
path: root/cmake/find_llvm.cmake
blob: 60d7b3e45064398344861b1105763ece5b5fe62a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#===------------------------------------------------------------------------===#
#
#                     The KLEE Symbolic Virtual Machine
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
#===------------------------------------------------------------------------===#
#
# This file provides multiple methods to detect LLVM.
#
# * llvm-config executable. This method is portable across LLVM build systems
# (i.e. works if LLVM was built with autoconf/Makefile or with CMake).
#
# * find_package(LLVM CONFIG). This method only works if LLVM was built with
# CMake or with LLVM >= 3.5 when built with the autoconf/Makefile build system
# This method relies on the `LLVMConfig.cmake` file generated to be generated
# by LLVM's build system.
#
#===------------------------------------------------------------------------===#

option(USE_CMAKE_FIND_PACKAGE_LLVM "Use find_package(LLVM CONFIG) to find LLVM" OFF)

if (USE_CMAKE_FIND_PACKAGE_LLVM)
  find_package(LLVM CONFIG REQUIRED)

  # Provide function to map LLVM components to libraries.
  function(klee_get_llvm_libs output_var)
    if (${LLVM_PACKAGE_VERSION} VERSION_LESS "3.5")
      llvm_map_components_to_libraries(${output_var} ${ARGN})
    else()
      llvm_map_components_to_libnames(${output_var} ${ARGN})
    endif()
    set(${output_var} ${${output_var}} PARENT_SCOPE)
  endfunction()
else()
  # Use the llvm-config binary to get the information needed.
  # Try to detect it in the user's environment. The user can
  # force a particular binary by passing `-DLLVM_CONFIG_BINARY=/path/to/llvm-config`
  # to CMake.
  find_program(LLVM_CONFIG_BINARY
    NAMES llvm-config)
  message(STATUS "LLVM_CONFIG_BINARY: ${LLVM_CONFIG_BINARY}")

  if (NOT LLVM_CONFIG_BINARY)
    message(FATAL_ERROR
      "Failed to find llvm-config.\n"
      "Try passing -DLLVM_CONFIG_BINARY=/path/to/llvm-config to cmake")
  endif()

  function(_run_llvm_config output_var)
    set(_command "${LLVM_CONFIG_BINARY}" ${ARGN})
    execute_process(COMMAND ${_command}
      RESULT_VARIABLE _exit_code
      OUTPUT_VARIABLE ${output_var}
      OUTPUT_STRIP_TRAILING_WHITESPACE
      ERROR_STRIP_TRAILING_WHITESPACE
    )
    if (NOT ("${_exit_code}" EQUAL "0"))
      message(FATAL_ERROR "Failed running ${_command}")
    endif()
    set(${output_var} ${${output_var}} PARENT_SCOPE)
  endfunction()

  # Get LLVM version
  _run_llvm_config(LLVM_PACKAGE_VERSION "--version")
  # Try x.y.z patern
  set(_llvm_version_regex "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$")
  if ("${LLVM_PACKAGE_VERSION}" MATCHES "${_llvm_version_regex}")
    string(REGEX REPLACE
      "${_llvm_version_regex}"
      "\\1"
      LLVM_VERSION_MAJOR
      "${LLVM_PACKAGE_VERSION}")
    string(REGEX REPLACE
      "${_llvm_version_regex}"
      "\\2"
      LLVM_VERSION_MINOR
      "${LLVM_PACKAGE_VERSION}")
    string(REGEX REPLACE
      "${_llvm_version_regex}"
      "\\3"
      LLVM_VERSION_PATCH
      "${LLVM_PACKAGE_VERSION}")
  else()
    # try x.y pattern
    set(_llvm_version_regex "^([0-9]+)\\.([0-9]+)$")
    if ("${LLVM_PACKAGE_VERSION}" MATCHES "${_llvm_version_regex}")
      string(REGEX REPLACE
        "${_llvm_version_regex}"
        "\\1"
        LLVM_VERSION_MAJOR
        "${LLVM_PACKAGE_VERSION}")
    string(REGEX REPLACE
      "${_llvm_version_regex}"
      "\\2"
      LLVM_VERSION_MINOR
      "${LLVM_PACKAGE_VERSION}")
    set(LLVM_VERSION_PATCH 0)
    else()
      message(FATAL_ERROR
        "Failed to parse LLVM version from \"${LLVM_PACKAGE_VERSION}\"")
    endif()
  endif()

  set(LLVM_DEFINITIONS "")
  _run_llvm_config(_llvm_cpp_flags "--cppflags")
  string_to_list("${_llvm_cpp_flags}" _llvm_cpp_flags_list)
  foreach (flag ${_llvm_cpp_flags_list})
    # Filter out -I flags by only looking for -D flags.
    if ("${flag}" MATCHES "^-D" AND NOT ("${flag}" STREQUAL "-D_DEBUG"))
      list(APPEND LLVM_DEFINITIONS "${flag}")
    endif()
  endforeach()

  set(LLVM_ENABLE_ASSERTIONS ON)
  set(LLVM_ENABLE_EH ON)
  set(LLVM_ENABLE_RTTI ON)
  _run_llvm_config(_llvm_cxx_flags "--cxxflags")
  string_to_list("${_llvm_cxx_flags}" _llvm_cxx_flags_list)
  foreach (flag ${_llvm_cxx_flags_list})
    if ("${flag}" STREQUAL "-DNDEBUG")
      # Note we don't rely on `llvm-config --build-mode` because
      # that seems broken when LLVM is built with CMake.
      set(LLVM_ENABLE_ASSERTIONS OFF)
    elseif ("${flag}" STREQUAL "-fno-exceptions")
      set(LLVM_ENABLE_EH OFF)
    elseif ("${flag}" STREQUAL "-fno-rtti")
      set(LLVM_ENABLE_RTTI OFF)
    endif()
  endforeach()

  set(LLVM_INCLUDE_DIRS "")
  foreach (flag ${_llvm_cpp_flags_list})
    # Filter out -D flags by only looking for -I flags.
    if ("${flag}" MATCHES "^-I")
      string(REGEX REPLACE "^-I(.+)$" "\\1" _include_dir "${flag}")
      list(APPEND LLVM_INCLUDE_DIRS "${_include_dir}")
    endif()
  endforeach()

  _run_llvm_config(LLVM_LIBRARY_DIRS "--libdir")
  _run_llvm_config(LLVM_TOOLS_BINARY_DIR "--bindir")
  _run_llvm_config(TARGET_TRIPLE "--host-target")

  # Provide function to map LLVM components to libraries.
  function(klee_get_llvm_libs OUTPUT_VAR)
    _run_llvm_config(_llvm_libs "--libfiles" ${ARGN})
    string_to_list("${_llvm_libs}" _llvm_libs_list)

    # Now find the system libs that are needed.
    # FIXME: This is a hack. We should really create imported
    # targets for the LLVM libraries and have them depend
    # on the necessary system libraries.
    _run_llvm_config(_system_libs "--ldflags")
    string_to_list("${_system_libs}" _system_libs_list)
    set(_filtered_system_libs_list "")
    foreach (l ${_system_libs_list})
      # Filter out `-L<path>`.
      if ("${l}" MATCHES "^-l")
        list(APPEND _filtered_system_libs_list "${l}")
      endif()
    endforeach()
    set(${OUTPUT_VAR} ${_llvm_libs_list} ${_system_libs} PARENT_SCOPE)
  endfunction()
endif()