summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Samsonov <samsonov@google.com>2012-12-19 12:33:39 +0000
committerAlexey Samsonov <samsonov@google.com>2012-12-19 12:33:39 +0000
commit02dcc63dde3106c24999040768a5eb52f99fedda (patch)
treee13d730e565297f827bbe9e4e88dda2c95d16177
parent37a14418e494d3dfb27cd6bddcd9855df2c80ff5 (diff)
Significantly change the way we build ASan unittests in CMake
build tree. Now just-built Clang is used to: 1) compile instrumented sources (as before); 2) compile non-instrumented sources; 3) compile our own instrumented version of googletest; 4) link it all together using -fsanitize=address flag (instead of trying to copy linker behavior in CMake build rules). This makes ASan unittests pretty much self-consistent and independent of other LLVM libraries. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@170541 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--CMakeLists.txt8
-rw-r--r--cmake/Modules/CompilerRTCompile.cmake16
-rw-r--r--cmake/Modules/CompilerRTUnittests.cmake30
-rw-r--r--lib/asan/tests/CMakeLists.txt186
4 files changed, 145 insertions, 95 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4544f1580..bbf41f773 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -15,6 +15,14 @@ include(LLVMParseArguments)
# runtime libraries.
cmake_minimum_required(VERSION 2.8.8)
+# Add path for custom modules
+set(CMAKE_MODULE_PATH
+ ${CMAKE_MODULE_PATH}
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules"
+ )
+
+set(COMPILER_RT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+
# FIXME: Below we assume that the target build of LLVM/Clang is x86, which is
# not at all valid. Much of this can be fixed just by switching to use
# a just-built-clang binary for the compiles.
diff --git a/cmake/Modules/CompilerRTCompile.cmake b/cmake/Modules/CompilerRTCompile.cmake
new file mode 100644
index 000000000..2794cabe5
--- /dev/null
+++ b/cmake/Modules/CompilerRTCompile.cmake
@@ -0,0 +1,16 @@
+include(LLVMParseArguments)
+
+# Compile a source into an object file with just-built Clang using
+# a provided compile flags and dependenices.
+# clang_compile(<object> <source>
+# CFLAGS <list of compile flags>
+# DEPS <list of dependencies>)
+macro(clang_compile object_file source)
+ parse_arguments(SOURCE "CFLAGS;DEPS" "" ${ARGN})
+ get_filename_component(source_rpath ${source} REALPATH)
+ add_custom_command(
+ OUTPUT ${object_file}
+ COMMAND clang ${SOURCE_CFLAGS} -c -o "${object_file}" ${source_rpath}
+ MAIN_DEPENDENCY ${source}
+ DEPENDS clang ${SOURCE_DEPS})
+endmacro()
diff --git a/cmake/Modules/CompilerRTUnittests.cmake b/cmake/Modules/CompilerRTUnittests.cmake
new file mode 100644
index 000000000..96ad67310
--- /dev/null
+++ b/cmake/Modules/CompilerRTUnittests.cmake
@@ -0,0 +1,30 @@
+include(AddLLVM)
+include(LLVMParseArguments)
+
+set(COMPILER_RT_GTEST_PATH ${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest)
+set(COMPILER_RT_GTEST_SOURCE ${COMPILER_RT_GTEST_PATH}/gtest-all.cc)
+set(COMPILER_RT_GTEST_INCLUDE_CFLAGS
+ -DGTEST_NO_LLVM_RAW_OSTREAM=1
+ -I${COMPILER_RT_GTEST_PATH}/include
+)
+
+# Use Clang to link objects into a single executable with just-built
+# Clang, using specific link flags. Make executable a part of provided
+# test_suite.
+# add_compiler_rt_test(<test_suite> <test_name>
+# OBJECTS <object files>
+# DEPS <deps (e.g. runtime libs)>
+# LINK_FLAGS <link flags>)
+macro(add_compiler_rt_test test_suite test_name)
+ parse_arguments(TEST "OBJECTS;DEPS;LINK_FLAGS" "" ${ARGN})
+ get_unittest_directory(OUTPUT_DIR)
+ set(output_bin "${OUTPUT_DIR}/${test_name}")
+ add_custom_command(
+ OUTPUT ${output_bin}
+ COMMAND clang ${TEST_OBJECTS} -o "${output_bin}"
+ ${TEST_LINK_FLAGS}
+ DEPENDS clang ${TEST_DEPS} ${TEST_OBJECTS})
+ add_custom_target(${test_name} DEPENDS ${output_bin})
+ # Make the test suite depend on the binary.
+ add_dependencies(${test_suite} ${test_name})
+endmacro()
diff --git a/lib/asan/tests/CMakeLists.txt b/lib/asan/tests/CMakeLists.txt
index 44f188cfa..7db5af76c 100644
--- a/lib/asan/tests/CMakeLists.txt
+++ b/lib/asan/tests/CMakeLists.txt
@@ -10,15 +10,20 @@
# instrumentation against the just-built runtime library.
include(CheckCXXCompilerFlag)
+include(CompilerRTCompile)
+include(CompilerRTUnittests)
include_directories(..)
include_directories(../..)
set(ASAN_UNITTEST_COMMON_CFLAGS
+ ${COMPILER_RT_GTEST_INCLUDE_CFLAGS}
+ -I${COMPILER_RT_SOURCE_DIR}/include
+ -I${COMPILER_RT_SOURCE_DIR}/lib
+ -I${COMPILER_RT_SOURCE_DIR}/lib/asan
-Wall
-Wno-format
-Werror
- -fvisibility=hidden
-g
-O2
)
@@ -46,26 +51,29 @@ else()
)
endif()
+set(ASAN_LINK_FLAGS -fsanitize=address)
+if(ANDROID)
+ list(APPEND ASAN_LINK_FLAGS -pie)
+elseif(APPLE)
+ # Unit tests on Mac depend on Foundation.
+ list(APPEND ASAN_LINK_FLAGS -framework Foundation)
+endif()
+# Unit tests require libstdc++.
+list(APPEND ASAN_LINK_FLAGS -lstdc++)
+
# Support 64-bit and 32-bit builds.
if(LLVM_BUILD_32_BITS)
list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -m32)
+ list(APPEND ASAN_LINK_FLAGS -m32)
else()
list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -m64)
+ list(APPEND ASAN_LINK_FLAGS -m64)
endif()
-set(ASAN_GTEST_INCLUDE_CFLAGS
- -I${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest/include
- -I${LLVM_MAIN_SRC_DIR}/include
- -I${LLVM_BINARY_DIR}/include
- -D__STDC_CONSTANT_MACROS
- -D__STDC_LIMIT_MACROS
-)
-
set(ASAN_BLACKLIST_FILE "${CMAKE_CURRENT_SOURCE_DIR}/asan_test.ignore")
set(ASAN_UNITTEST_INSTRUMENTED_CFLAGS
${ASAN_UNITTEST_COMMON_CFLAGS}
- ${ASAN_GTEST_INCLUDE_CFLAGS}
-fsanitize=address
-mllvm "-asan-blacklist=${ASAN_BLACKLIST_FILE}"
-mllvm -asan-stack=1
@@ -75,103 +83,91 @@ set(ASAN_UNITTEST_INSTRUMENTED_CFLAGS
-mllvm -asan-use-after-return=0
)
-function(add_asan_test testsuite testname)
- add_unittest(${testsuite} ${testname} ${ARGN})
- if (APPLE)
- # Darwin-specific linker flags.
- set_property(TARGET ${testname} APPEND PROPERTY
- LINK_FLAGS "-framework Foundation")
- target_link_libraries(${testname} clang_rt.asan_osx)
- elseif (ANDROID)
- target_link_libraries(${testname} clang_rt.asan-arm-android)
- elseif (UNIX)
- # Linux-specific linker flags.
- set_property(TARGET ${testname} APPEND PROPERTY
- LINK_FLAGS "-lpthread -ldl -rdynamic")
- if(LLVM_BUILD_32_BITS)
- target_link_libraries(${testname} clang_rt.asan-i386)
- else()
- target_link_libraries(${testname} clang_rt.asan-x86_64)
- endif()
- endif()
- set(add_compile_flags "")
- get_property(compile_flags TARGET ${testname} PROPERTY COMPILE_FLAGS)
- foreach(arg ${ASAN_UNITTEST_COMMON_CFLAGS})
- set(add_compile_flags "${add_compile_flags} ${arg}")
- endforeach(arg ${ASAN_UNITTEST_COMMON_CFLAGS})
- set_property(TARGET ${testname} PROPERTY COMPILE_FLAGS
- "${compile_flags} ${add_compile_flags}")
-endfunction()
-
-set(ASAN_NOINST_TEST_SOURCES
- asan_noinst_test.cc
- asan_test_main.cc
-)
+# Compile source and add it to the object list using compiler
+# options in ${ARGN}.
+macro(asan_compile obj_list source)
+ get_filename_component(basename ${source} NAME)
+ set(output_obj "${basename}.o")
+ clang_compile(${output_obj} ${source}
+ CFLAGS ${ARGN}
+ DEPS gtest ${ASAN_RUNTIME_LIBRARIES}
+ ${ASAN_BLACKLIST_FILE})
+ list(APPEND ${obj_list} ${output_obj})
+endmacro()
+
+# Link ASan unit test from a set of objects in ${ARGN}.
+macro(add_asan_test test_suite test_name)
+ message(STATUS "Link flags: ${ASAN_LINK_FLAGS}")
+ add_compiler_rt_test(${test_suite} ${test_name}
+ OBJECTS ${ARGN}
+ DEPS ${ASAN_RUNTIME_LIBRARIES}
+ LINK_FLAGS ${ASAN_LINK_FLAGS})
+endmacro()
-set(ASAN_INST_TEST_OBJECTS)
+# Main AddressSanitizer unit tests.
+add_custom_target(AsanUnitTests)
+set_target_properties(AsanUnitTests PROPERTIES FOLDER "ASan unit tests")
+# ASan benchmarks (not actively used now).
+add_custom_target(AsanBenchmarks)
+set_target_properties(AsanBenchmarks PROPERTIES FOLDER "Asan benchmarks")
# We only support building instrumented tests when we're not cross compiling
# and targeting a unix-like system where we can predict viable compilation and
# linking strategies.
# We use a different approach to build these tests for Android. See below.
if("${CMAKE_HOST_SYSTEM}" STREQUAL "${CMAKE_SYSTEM}" AND UNIX AND NOT ANDROID)
-
- # This function is a custom routine to manage manually compiling source files
- # for unit tests with the just-built Clang binary, using the ASan
- # instrumentation, and linking them into a test executable.
- function(add_asan_compile_command source extra_cflags)
- set(output_obj "${source}.asan.o")
- add_custom_command(
- OUTPUT ${output_obj}
- COMMAND clang
- ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS}
- ${extra_cflags}
- -c -o "${output_obj}"
- ${CMAKE_CURRENT_SOURCE_DIR}/${source}
- MAIN_DEPENDENCY ${source}
- DEPENDS clang ${ASAN_RUNTIME_LIBRARIES} ${ASAN_BLACKLIST_FILE} ${ARGN}
- )
- endfunction()
-
- add_asan_compile_command(asan_globals_test.cc "")
- add_asan_compile_command(asan_test.cc "")
- list(APPEND ASAN_INST_TEST_OBJECTS asan_globals_test.cc.asan.o
- asan_test.cc.asan.o)
+ # Build gtest instrumented with ASan.
+ set(ASAN_INST_GTEST)
+ asan_compile(ASAN_INST_GTEST ${COMPILER_RT_GTEST_SOURCE}
+ ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
+ # Instrumented tests.
+ set(ASAN_INST_TEST_OBJECTS)
+ asan_compile(ASAN_INST_TEST_OBJECTS asan_globals_test.cc
+ ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
+ asan_compile(ASAN_INST_TEST_OBJECTS asan_test.cc
+ ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
if (APPLE)
- add_asan_compile_command(asan_mac_test.mm "-ObjC")
- list(APPEND ASAN_INST_TEST_OBJECTS asan_mac_test.mm.asan.o)
+ asan_compile(ASAN_INST_TEST_OBJECTS asan_mac_test.mm
+ ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} -ObjC)
endif()
-
- # Build benchmarks test instrumented with AddressSanitizer.
- add_asan_compile_command(asan_benchmarks_test.cc "")
- add_custom_target(AsanBenchmarks)
- set_target_properties(AsanBenchmarks PROPERTIES FOLDER "Asan benchmarks")
- add_asan_test(AsanBenchmarks AsanBenchmark asan_benchmarks_test.cc.asan.o)
+ # Uninstrumented tests.
+ set(ASAN_NOINST_TEST_OBJECTS)
+ asan_compile(ASAN_NOINST_TEST_OBJECTS asan_noinst_test.cc
+ ${ASAN_UNITTEST_COMMON_CFLAGS})
+ asan_compile(ASAN_NOINST_TEST_OBJECTS asan_test_main.cc
+ ${ASAN_UNITTEST_COMMON_CFLAGS})
+
+ # Link everything together.
+ add_asan_test(AsanUnitTests AsanTest ${ASAN_NOINST_TEST_OBJECTS}
+ ${ASAN_INST_TEST_OBJECTS} ${ASAN_INST_GTEST})
+
+ # Instrumented benchmarks.
+ set(ASAN_BENCHMARKS_OBJECTS)
+ asan_compile(ASAN_BENCHMARKS_OBJECTS asan_benchmarks_test.cc
+ ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
+ # Link benchmarks.
+ add_asan_test(AsanBenchmarks AsanBenchmark ${ASAN_BENCHMARKS_OBJECTS}
+ ${ASAN_INST_GTEST})
endif()
-# Main AddressSanitizer unit tests.
-add_custom_target(AsanUnitTests)
-set_target_properties(AsanUnitTests PROPERTIES FOLDER "ASan unit tests")
-
if(ANDROID)
+ # We assume that unit tests on Android are built in a build
+ # tree with fresh Clang as a host compiler.
+ set(ASAN_NOINST_TEST_SOURCES asan_noinst_test.cc asan_test_main.cc)
set(ASAN_INST_TEST_SOURCES asan_globals_test.cc asan_test.cc)
- add_library(asan_noinst_test OBJECT
- ${ASAN_NOINST_TEST_SOURCES}
- )
- set_target_compile_flags(asan_noinst_test
- ${ASAN_UNITTEST_COMMON_CFLAGS} ${ASAN_GTEST_INCLUDE_CFLAGS}
- )
- add_asan_test(AsanUnitTests AsanTest
- ${ASAN_INST_TEST_SOURCES}
+ add_library(asan_noinst_test OBJECT ${ASAN_NOINST_TEST_SOURCES})
+ set_target_compile_flags(asan_noinst_test ${ASAN_UNITTEST_COMMON_CFLAGS})
+ add_library(asan_inst_test OBJECT
+ ${ASAN_INST_TEST_SOURCES} ${COMPILER_RT_GTEST_SOURCE})
+ set_target_compile_flags(asan_inst_test ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
+ add_executable(AsanTest
$<TARGET_OBJECTS:asan_noinst_test>
- )
- set_target_compile_flags(AsanTest
- ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} ${ASAN_GTEST_INCLUDE_CFLAGS}
- )
- set_target_link_flags(AsanTest
- -pie
- )
-else()
- add_asan_test(AsanUnitTests AsanTest ${ASAN_NOINST_TEST_SOURCES}
- ${ASAN_INST_TEST_OBJECTS})
+ $<TARGET_OBJECTS:asan_inst_test>
+ )
+ # Setup correct output directory and link flags.
+ get_unittest_directory(OUTPUT_DIR)
+ set_target_properties(AsanTest PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIR})
+ set_target_link_flags(AsanTest ${ASAN_LINK_FLAGS})
+ add_dependencies(AsanUnitTests AsanTest)
endif()