aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--README-CMake.md12
-rw-r--r--cmake/find_llvm.cmake16
-rw-r--r--unittests/CMakeLists.txt162
-rw-r--r--unittests/TestMain.cpp6
4 files changed, 150 insertions, 46 deletions
diff --git a/README-CMake.md b/README-CMake.md
index 4deb8860..2687c86b 100644
--- a/README-CMake.md
+++ b/README-CMake.md
@@ -61,9 +61,11 @@ cmake -DCMAKE_BUILD_TYPE=Release /path/to/klee/src
* `ENABLE_ZLIB` (BOOLEAN) - Enable zlib support.
-* `GTEST_SRC_DIR` (STRING) - Path to GTest source tree.
+* `GTEST_SRC_DIR` (STRING) - Path to Google Test source tree. If it is not
+ specified and `USE_CMAKE_FIND_PACKAGE_LLVM` is used, CMake will try to reuse
+ the version included within the LLVM source tree.
-* `GTEST_INCLUDE_DIR` (STRING) - Path to GTest include directory,
+* `GTEST_INCLUDE_DIR` (STRING) - Path to Google Test include directory,
if it is not under `GTEST_SRC_DIR`.
* `KLEE_ENABLE_TIMESTAMP` (BOOLEAN) - Enable timestamps in KLEE sources.
@@ -81,6 +83,10 @@ cmake -DCMAKE_BUILD_TYPE=Release /path/to/klee/src
only relevant if `USE_CMAKE_FIND_PACKAGE_LLVM` is `FALSE`. This is used
to detect the LLVM version and find libraries.
+* `LLVM_DIR` (STRING) - Path to `LLVMConfig.cmake`. This is only relevant if
+ `USE_CMAKE_FIND_PACKAGE_LLVM` is `TRUE`. This can be used to tell CMake where
+ it can find LLVM outside of standard directories.
+
* `MAKE_BINARY` (STRING) - Path to `make` binary used to build KLEE's runtime.
* `metaSMT_DIR` (STRING) - Provides a hint to CMake, where the metaSMT constraint
@@ -94,6 +100,6 @@ cmake -DCMAKE_BUILD_TYPE=Release /path/to/klee/src
against STP in a build directory or an installed copy.
* `USE_CMAKE_FIND_PACKAGE_LLVM` (BOOLEAN) - Use `find_package(LLVM CONFIG)`
- to find LLVM.
+ to find LLVM (instead of using `llvm-config` with `LLVM_CONFIG_BINARY`).
* `WARNINGS_AS_ERRORS` (BOOLEAN) - Treat warnings as errors when building KLEE.
diff --git a/cmake/find_llvm.cmake b/cmake/find_llvm.cmake
index 02c99960..874bd1ae 100644
--- a/cmake/find_llvm.cmake
+++ b/cmake/find_llvm.cmake
@@ -20,8 +20,14 @@
option(USE_CMAKE_FIND_PACKAGE_LLVM "Use find_package(LLVM CONFIG) to find LLVM" OFF)
if (USE_CMAKE_FIND_PACKAGE_LLVM)
+ # Use find_package() to detect LLVM in the user's environment.
+ # The user can force a particular copy by passing
+ # `-DLLVM_DIR=/path/to/LLVMConfig.cmake` to CMake.
find_package(LLVM CONFIG REQUIRED)
+ list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}")
+ include(AddLLVM)
+
# Provide function to map LLVM components to libraries.
function(klee_get_llvm_libs output_var)
llvm_map_components_to_libnames(${output_var} ${ARGN})
@@ -31,9 +37,8 @@ if (USE_CMAKE_FIND_PACKAGE_LLVM)
set(LLVM_ENABLE_VISIBILITY_INLINES_HIDDEN OFF)
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.
+ # 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}")
@@ -142,6 +147,11 @@ else()
_run_llvm_config(LLVM_TOOLS_BINARY_DIR "--bindir")
_run_llvm_config(TARGET_TRIPLE "--host-target")
+ _run_llvm_config(LLVM_BUILD_MAIN_SRC_DIR "--src-root")
+ if (NOT EXISTS "${LLVM_BUILD_MAIN_SRC_DIR}")
+ set(LLVM_BUILD_MAIN_SRC_DIR "")
+ endif()
+
# Provide function to map LLVM components to libraries.
function(klee_get_llvm_libs OUTPUT_VAR)
_run_llvm_config(_llvm_libs "--libfiles" ${ARGN})
diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt
index d6e58183..ef052f9b 100644
--- a/unittests/CMakeLists.txt
+++ b/unittests/CMakeLists.txt
@@ -7,41 +7,128 @@
#
#===------------------------------------------------------------------------===#
-# Build GTest. We don't use a pre-built version due to
-# https://github.com/google/googletest/blob/master/googletest/docs/FAQ.md#why-is-it-not-recommended-to-install-a-pre-compiled-copy-of-google-test-for-example-into-usrlocal
-set(GTEST_SRC_DIR
- "/usr/src/gtest"
- CACHE
- PATH
- "Path to GTest source directory"
-)
+if (TARGET gtest AND TARGET gtest_main)
+ # try to reuse LLVM's targets
+
+ message(WARNING "LLVM exports 'gtest' and 'gtest_main' targets (for Google "
+ "Test), so KLEE cannot create them. By default, KLEE will reuse "
+ "LLVM's 'gtest' and 'gtest_main' targets if they are available. This is, "
+ "however, only recommended if LLVM and KLEE were build with the same "
+ "compiler and linker flags to prevent any compatibility issues.\n"
+ "To prevent CMake from reusing the targets or to use a different version "
+ "of Google Test, try either of the following:\n"
+ "- Point LLVM_DIR to the directory containing the `LLVMConfig.cmake` file "
+ "of an installed copy of LLVM instead of a build tree.\n"
+ "- Pass -DLLVM_INCLUDE_TESTS=OFF to CMake when building LLVM. This "
+ "prevents building unit tests in LLVM (but not in KLEE) and exporting the "
+ "target to the build tree.")
+
+ if (GTEST_SRC_DIR)
+ message(FATAL_ERROR "Cannot use GTEST_SRC_DIR when targets 'gtest' and "
+ "'gtest_main' are already defined.\n"
+ "Either reuse LLVM's Google Test setup by not setting GTEST_SRC_DIR or "
+ "choose one of the options to prevent LLVM from exporting these targets.")
+ endif()
+
+ # check if it's really LLVM that exports them
+ list(FIND LLVM_EXPORTED_TARGETS "gtest" _GTEST_INDEX)
+ list(FIND LLVM_EXPORTED_TARGETS "test_main" _GTEST_MAIN_INDEX)
+ if (${_GTEST_INDEX} GREATER -1 AND ${_GTEST_MAIN_INDEX})
+ message(STATUS "Google Test: Reusing LLVM's 'gtest' and 'gtest_main' targets.")
+ # in this case, only include directory has to be set
+ if (LLVM_BUILD_MAIN_SRC_DIR)
+ set(GTEST_INCLUDE_DIR
+ "${LLVM_BUILD_MAIN_SRC_DIR}/utils/unittest/googletest/include"
+ CACHE
+ PATH
+ "Path to Google Test include directory"
+ )
+ endif()
+ else()
+ message(FATAL_ERROR "Reusing Google Test targets from LLVM failed:"
+ "LLVM_EXPORTED_TARGETS does not contain 'gtest' or 'gtest_main'.")
+ endif()
+else()
+ # LLVM's targets are not reused
+
+ if (NOT GTEST_SRC_DIR)
+ if (USE_CMAKE_FIND_PACKAGE_LLVM AND LLVM_BUILD_MAIN_SRC_DIR)
+ # build from LLVM's utils directory
+ # NOTE: This can only be done using USE_CMAKE_FIND_PACKAGE_LLVM as
+ # LLVM replaced Google Test's CMakeLists.txt with its own,
+ # requiring add_llvm_library() from AddLLVM.cmake.
+ message(STATUS "Google Test: Building from LLVM's source tree.")
+
+ set(GTEST_INCLUDE_DIR
+ "${LLVM_BUILD_MAIN_SRC_DIR}/utils/unittest/googletest/include"
+ CACHE
+ PATH
+ "Path to Google Test include directory"
+ )
+
+ add_subdirectory("${LLVM_BUILD_MAIN_SRC_DIR}/utils/unittest/"
+ "${CMAKE_CURRENT_BINARY_DIR}/gtest_build")
+
+ # add includes for LLVM's modifications
+ target_include_directories(gtest BEFORE PRIVATE ${LLVM_INCLUDE_DIRS})
+ target_include_directories(gtest_main BEFORE PRIVATE ${LLVM_INCLUDE_DIRS})
+ else()
+ # try to find Google Test, as GTEST_SRC_DIR is not manually specified
+ find_path(GTEST_SRC_DIR
+ "src/gtest.cc"
+
+ HINTS
+ "/usr/src/gtest"
+
+ # prevent CMake from finding gtest.cc in LLVM's utils directory
+ NO_DEFAULT_PATH
-if (NOT EXISTS "${GTEST_SRC_DIR}")
- message(FATAL_ERROR "GTest source directory \"${GTEST_SRC_DIR}\" cannot be found.\n"
- "Try passing -DGTEST_SRC_DIR=<path_to_gtest_source> to cmake where "
- "<path_to_gtest_source> is the path to the GoogleTest source tree.\n"
- "Alternatively you can disable unit tests by passing "
- "-DENABLE_UNIT_TESTS=OFF to cmake.")
+ DOC
+ "Path to Google Test source directory"
+ )
+ endif()
+ endif()
+
+ if (NOT (TARGET gtest AND TARGET gtest_main))
+ # building from GTEST_SRC_DIR, not from LLVM's utils directory
+ find_path(GTEST_INCLUDE_DIR
+ "gtest/gtest.h"
+
+ HINTS
+ "${GTEST_SRC_DIR}/include"
+
+ NO_DEFAULT_PATH
+
+ DOC
+ "Path to Google Test include directory"
+ )
+
+ if (NOT EXISTS "${GTEST_SRC_DIR}")
+ message(FATAL_ERROR "Google Test source directory \"${GTEST_SRC_DIR}\" "
+ "cannot be found.\n"
+ "Try passing -DGTEST_SRC_DIR=<path_to_gtest_source> to CMake where "
+ "<path_to_gtest_source> is the path to the Google Test source tree.\n"
+ "Alternatively, you can disable unit tests by passing "
+ "-DENABLE_UNIT_TESTS=OFF to CMake.")
+ endif()
+ message(STATUS "Google Test: Building from source.")
+ message(STATUS "GTEST_SRC_DIR: ${GTEST_SRC_DIR}")
+
+ # Prevent Google Test from adding to our install target.
+ # Required for >= 1.8.0, but can only be disabled starting with 1.8.1
+ set(GTEST_INSTALL OFF CACHE BOOL "disable installing Google Test" FORCE)
+
+ # Build Google Test as part of our project
+ add_subdirectory(${GTEST_SRC_DIR} "${CMAKE_CURRENT_BINARY_DIR}/gtest_build")
+ endif()
+
+ # build Google Test with KLEE's defines and compile flags
+ target_compile_definitions(gtest PRIVATE ${KLEE_COMPONENT_CXX_DEFINES})
+ target_compile_definitions(gtest_main PRIVATE ${KLEE_COMPONENT_CXX_DEFINES})
+ target_compile_options(gtest PRIVATE ${KLEE_COMPONENT_CXX_FLAGS})
+ target_compile_options(gtest_main PRIVATE ${KLEE_COMPONENT_CXX_FLAGS})
endif()
-# It's important that GTest is built with KLEE's compile flags
-# so set them here.
-set(_OLD_CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
-foreach (f ${KLEE_COMPONENT_CXX_FLAGS})
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${f}")
-endforeach()
-foreach (f ${KLEE_COMPONENT_CXX_DEFINES})
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${f}")
-endforeach()
-
-# Build GTest as part of our project
-# FIXME: Prevent GTest from adding to our install target.
-# This is a problem for GTest >= 1.8. I've filled a PR to fix the issue
-# ( https://github.com/google/googletest/pull/921 ). If it gets accepted
-# we can do `set(gtest_enable_install FALSE)` to fix this.
-add_subdirectory(${GTEST_SRC_DIR} "${CMAKE_CURRENT_BINARY_DIR}/gtest_build")
-
-set(CMAKE_CXX_FLAGS "${_OLD_CMAKE_CXX_FLAGS}") # Restore the flags
# This keeps track of all the unit test
# targets so we can ensure they are built
@@ -52,22 +139,17 @@ define_property(GLOBAL
FULL_DOCS "KLEE unit tests"
)
-set(GTEST_INCLUDE_DIR
- "${GTEST_SRC_DIR}/include"
- CACHE
- PATH
- "Path to GTest include directory"
-)
-
if (NOT IS_DIRECTORY "${GTEST_INCLUDE_DIR}")
message(FATAL_ERROR
- "Cannot find GTest include directory \"${GTEST_INCLUDE_DIR}\"")
+ "Cannot find Google Test include directory \"${GTEST_INCLUDE_DIR}\"")
endif()
+message(STATUS "GTEST_INCLUDE_DIR: ${GTEST_INCLUDE_DIR}")
function(add_klee_unit_test target_name)
add_executable(${target_name} ${ARGN})
target_link_libraries(${target_name} PRIVATE gtest_main)
target_include_directories(${target_name} BEFORE PRIVATE "${GTEST_INCLUDE_DIR}")
+ target_include_directories(${target_name} BEFORE PRIVATE ${KLEE_COMPONENT_EXTRA_INCLUDE_DIRS})
set_target_properties(${target_name}
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/unittests/"
diff --git a/unittests/TestMain.cpp b/unittests/TestMain.cpp
index 095076b2..9a64a4af 100644
--- a/unittests/TestMain.cpp
+++ b/unittests/TestMain.cpp
@@ -9,6 +9,12 @@
#include "gtest/gtest.h"
+// WARNING: If LLVM's gtest_main target is reused
+// or is built from LLVM's source tree,
+// this file is ignored. Instead, LLVM's
+// utils/unittest/UnitTestMain/TestMain.cpp
+// is used.
+
int main(int argc, char **argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();