Index: CMakeLists.txt =================================================================== --- CMakeLists.txt +++ CMakeLists.txt @@ -10,6 +10,9 @@ if(POLICY CMP0042) cmake_policy(SET CMP0042 NEW) # Set MACOSX_RPATH=YES by default endif() +if(POLICY CMP0040) + cmake_policy(SET CMP0040 NEW) # Require add_custom_target(TARGET...) +endif() set(PACKAGE_NAME libcxx) set(PACKAGE_VERSION trunk-svn) @@ -61,8 +64,10 @@ This option may only be used when LIBCXX_ENABLE_THREADS=OFF." ON) option(LIBCXX_INSTALL_HEADERS "Install the libc++ headers." ON) option(LIBCXX_INSTALL_SUPPORT_HEADERS "Install libc++ support headers." ON) +option(LIBCXX_GENERATE_COVERAGE "Enable generating code coverage." OFF) set(LIBCXX_SYSROOT "" CACHE STRING "Use alternate sysroot.") set(LIBCXX_GCC_TOOLCHAIN "" CACHE STRING "Use alternate GCC toolchain.") +set(LIBCXX_CLANG_RESOURCE_DIR "" CACHE STRING "The Clang resource directory root.") if (LIBCXX_BUILT_STANDALONE) set(LLVM_USE_SANITIZER "" CACHE STRING "Define the sanitizer used to build the library and tests") @@ -96,9 +101,12 @@ # Declare libc++ configuration variables. # They are intended for use as follows: +# LIBCXX_TARGET_FLAGS: Compile and link flags that affect the output target or +# arch. ex: -m32 -target # LIBCXX_CXX_FLAGS: General flags for both the compiler and linker. # LIBCXX_COMPILE_FLAGS: Compile only flags. # LIBCXX_LINK_FLAGS: Linker only flags. +set(LIBCXX_TARGET_FLAGS "") set(LIBCXX_CXX_FLAGS "") set(LIBCXX_COMPILE_FLAGS "") set(LIBCXX_LINK_FLAGS "") @@ -107,6 +115,11 @@ include(config-ix) # Configure ABI library include(HandleLibCXXABI) +# Configure coverage options. +if (LIBCXX_GENERATE_COVERAGE) + include(CodeCoverage) + set(CMAKE_BUILD_TYPE "COVERAGE" CACHE STRING "" FORCE) +endif() #=============================================================================== # Setup Compiler Flags @@ -213,7 +226,7 @@ if (CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT WIN32) if (LIBCXX_BUILD_32_BITS) message(STATUS "Building 32 bits executables and libraries.") - list(APPEND LIBCXX_CXX_FLAGS "-m32") + list(APPEND LIBCXX_TARGET_FLAGS "-m32") endif() elseif(LIBCXX_BUILD_32_BITS) message(FATAL_ERROR "LIBCXX_BUILD_32_BITS=ON is not supported on this platform.") @@ -268,14 +281,35 @@ endif() endif() -append_if(LIBCXX_CXX_FLAGS LIBCXX_TARGET_TRIPLE +append_if(LIBCXX_TARGET_FLAGS LIBCXX_TARGET_TRIPLE "-target ${LIBCXX_TARGET_TRIPLE}") -append_if(LIBCXX_CXX_FLAGS LIBCXX_SYSROOT "--sysroot ${LIBCXX_SYSROOT}") -append_if(LIBCXX_CXX_FLAGS LIBCXX_GCC_TOOLCHAIN + +append_if(LIBCXX_TARGET_FLAGS LIBCXX_SYSROOT "--sysroot ${LIBCXX_SYSROOT}") +append_if(LIBCXX_TARGET_FLAGS LIBCXX_GCC_TOOLCHAIN "-gcc-toolchain ${LIBCXX_GCC_TOOLCHAIN}") +if (LLVM_USE_SANITIZER AND LIBCXX_GENERATE_COVERAGE) + message(FATAL_ERROR "LLVM_USE_SANITIZER cannot be used with LIBCXX_GENERATE_COVERAGE") +endif() + +# We need to probe and manually link the sanitizer libraries on OS X. +if (APPLE AND LLVM_USE_SANITIZER) + set(LIBCXX_COMPILER_RT_OPTION "${LLVM_USE_SANITIZER}") +elseif(LIBCXX_GENERATE_COVERAGE) + set(LIBCXX_COMPILER_RT_OPTION "Profile") +endif() + +# Manually link the required sanitizer libraries. +if (DEFINED LIBCXX_COMPILER_RT_OPTION) + include(GetCompilerRTOptions) + get_compiler_rt_option(LIBCXX_COMPILER_RT_LINK_LIBRARIES + "${LIBCXX_COMPILER_RT_OPTION}" + "${LIBCXX_TARGET_FLAGS}") +endif() + string(REPLACE ";" " " LIBCXX_CXX_FLAGS "${LIBCXX_CXX_FLAGS}") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LIBCXX_CXX_FLAGS}") +string(REPLACE ";" " " LIBCXX_TARGET_FLAGS "${LIBCXX_TARGET_FLAGS}") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LIBCXX_CXX_FLAGS} ${LIBCXX_TARGET_FLAGS}") #=============================================================================== # Setup Source Code Index: cmake/Modules/CodeCoverage.cmake =================================================================== --- /dev/null +++ cmake/Modules/CodeCoverage.cmake @@ -0,0 +1,36 @@ +find_program(CODE_COVERAGE_LCOV lcov) +if (NOT CODE_COVERAGE_LCOV) + message(FATAL_ERROR "Cannot find lcov...") +endif() + +find_program(CODE_COVERAGE_GENHTML genhtml) +if (NOT CODE_COVERAGE_GENHTML) + message(FATAL_ERROR "Cannot find genhtml...") +endif() + +set(CMAKE_CXX_FLAGS_COVERAGE "-g -O0 --coverage") + +function(setup_lcov_test_target_coverage target_name output_dir capture_dirs source_dirs) + file(MAKE_DIRECTORY ${output_dir}) + + set(CAPTURE_DIRS "") + foreach(cdir ${capture_dirs}) + list(APPEND CAPTURE_DIRS "-d;${cdir}") + endforeach() + + set(EXTRACT_DIRS "") + foreach(sdir ${source_dirs}) + list(APPEND EXTRACT_DIRS "'${sdir}/*'") + endforeach() + + message(STATUS "Capture Directories: ${CAPTURE_DIRS}") + message(STATUS "Extract Directories: ${EXTRACT_DIRS}") + + add_custom_target(generate-lib${target_name}-coverage + COMMAND ${CODE_COVERAGE_LCOV} --capture ${CAPTURE_DIRS} -o test_coverage.info + COMMAND ${CODE_COVERAGE_LCOV} --extract test_coverage.info ${EXTRACT_DIRS} -o test_coverage.info + COMMAND ${CODE_COVERAGE_GENHTML} --demangle-cpp test_coverage.info -o test_coverage + COMMAND ${CMAKE_COMMAND} -E remove test_coverage.info + WORKING_DIRECTORY ${output_dir} + COMMENT "Generating coverage results") +endfunction() \ No newline at end of file Index: cmake/Modules/GetCompilerRTOptions.cmake =================================================================== --- /dev/null +++ cmake/Modules/GetCompilerRTOptions.cmake @@ -0,0 +1,49 @@ +# An internal method to setup the python enviroment. +macro(_setup_python) + if (LIT_EXECUTABLE) + get_filename_component(LIT_MODULE_PATH ${LIT_EXECUTABLE} DIRECTORY) + else() + set(LIT_MODULE_PATH "${CMAKE_SOURCE_DIR}/utils/lit") + endif() + if (NOT IS_DIRECTORY ${LIT_MODULE_PATH}) + message(FATAL_ERROR "Failed to find the LIT module.") + endif() + set(LIBCXX_PYTHONPATH "${LIT_MODULE_PATH}:${LIBCXX_SOURCE_DIR}/test:$ENV{PYTHONPATH}") + set(ENV{PYTHONPATH} "${LIBCXX_PYTHONPATH}") + include(FindPythonInterp) + if(NOT PYTHONINTERP_FOUND) + message(FATAL_ERROR "Failed to find python executable") + endif() +endmacro() + +#=============================================================================== +# Get CompilerRT link flags +#=============================================================================== +# +# get_compiler_rt_option: Get link flags for a given compiler-rt library. +# +# Parameters: +# output_var: The variable to write the list of flags to. +# opt: The compiler-rt configuration to get the flags for. It can be one of +# Profile, Address, Memory, MemoryWithOrigins, Undefined, Thread. +# extra_flags: A list of extra compiler flags used to help find the +# compiler_rt libraries. +function(get_compiler_rt_option output_var opt extra_flags) + if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + message(FATAL_ERROR + "GetCompilerRTOptions can only be used with a Clang compiler") + endif() + _setup_python() + separate_arguments(extra_flags) + foreach(e ${extra_flags}) + list(APPEND EXTRA_FLAGS "--flag;${e}") + endforeach() + execute_process(COMMAND ${PYTHON_EXECUTABLE} ${LIBCXX_SOURCE_DIR}/test/libcxx/clang_utils.py --cxx ${CMAKE_CXX_COMPILER} ${EXTRA_FLAGS} ${opt} + RESULT_VARIABLE RES_VAR + OUTPUT_VARIABLE OUTPUT_VAR) + if (NOT RES_VAR EQUAL 0) + message(FATAL_ERROR "get_compiler_rt_option failed to get link options for ${opt}") + endif() + string(STRIP "${OUTPUT_VAR}" OUTPUT_VAR) + set(${output_var} "${OUTPUT_VAR}" PARENT_SCOPE) +endfunction() Index: lib/CMakeLists.txt =================================================================== --- lib/CMakeLists.txt +++ lib/CMakeLists.txt @@ -1,3 +1,5 @@ +set(LIBCXX_LIB_CMAKEFILES_DIR "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}" PARENT_SCOPE) + # Get sources file(GLOB LIBCXX_SOURCES ../src/*.cpp) if(WIN32) @@ -50,12 +52,14 @@ if (DEFINED LIBCXX_CXX_ABI_LIBRARY_PATH) target_link_libraries(cxx "-L${LIBCXX_CXX_ABI_LIBRARY_PATH}") endif() +target_link_libraries(cxx ${LIBCXX_COMPILER_RT_LINK_LIBRARIES}) target_link_libraries(cxx ${libraries}) # Setup flags. append_if(LIBCXX_COMPILE_FLAGS LIBCXX_HAS_FPIC_FLAG -fPIC) append_if(LIBCXX_LINK_FLAGS LIBCXX_HAS_NODEFAULTLIBS_FLAG -nodefaultlibs) + if ( APPLE ) if ( CMAKE_OSX_DEPLOYMENT_TARGET STREQUAL "10.6" ) list(APPEND LIBCXX_COMPILE_FLAGS "-U__STRICT_ANSI__") Index: test/CMakeLists.txt =================================================================== --- test/CMakeLists.txt +++ test/CMakeLists.txt @@ -44,6 +44,7 @@ pythonize_bool(LIBCXX_BUILD_32_BITS) pythonize_bool(LIBCXX_ENABLE_THREADS) pythonize_bool(LIBCXX_ENABLE_MONOTONIC_CLOCK) + pythonize_bool(LIBCXX_GENERATE_COVERAGE) set(AUTO_GEN_COMMENT "## Autogenerated by libcxx configuration.\n# Do not edit!") @@ -59,6 +60,14 @@ DEPENDS cxx COMMENT "Running libcxx tests" ${cmake_3_2_USES_TERMINAL}) + + if (LIBCXX_GENERATE_COVERAGE) + include(CodeCoverage) + set(output_dir "${CMAKE_CURRENT_BINARY_DIR}/coverage") + set(capture_dirs "${LIBCXX_LIB_CMAKEFILES_DIR}/cxx.dir/;${CMAKE_CURRENT_BINARY_DIR}") + set(extract_dirs "${LIBCXX_SOURCE_DIR}/include;${LIBCXX_SOURCE_DIR}/src") + setup_lcov_test_target_coverage("cxx" "${output_dir}" "${capture_dirs}" "${extract_dirs}") + endif() else() message(WARNING "LIT_EXECUTABLE not set, no check-libcxx target will be available!") Index: test/libcxx/clang_utils.py =================================================================== --- /dev/null +++ test/libcxx/clang_utils.py @@ -0,0 +1,354 @@ +""" +clang_utils - Utilities for linking with the clang compiler. +""" + +import os +import libcxx.compiler + + +class BasicClangLinkDriver(object): + """ + BasicClangLinkDriver - A linker driver that mimics how clang links + compiler-rt + """ + def __init__(self, cxx): + self.cxx = cxx + if cxx.type is None or 'clang' not in cxx.type: + raise RuntimeError('Compiler is not a clang variant') + search_paths = self.cxx.getLibrarySearchPaths() + if not search_paths: + raise RuntimeError('Failed to get search paths') + self.clang_resource_dir = search_paths[0] + if not os.path.isdir(self.clang_resource_dir): + raise RuntimeError('Clang resource directory does not exist') + self.target_info = self.cxx.getTargetInfo() + sys = self.target_info.sys + if sys.startswith('darwin'): + self.target_info.sys = 'darwin' + self.clang_library_dir = os.path.join( + self.clang_resource_dir, 'lib', self.target_info.sys) + if not os.path.isdir(self.clang_library_dir): + raise RuntimeError('clang library path does not exist: %s' % + self.clang_library_dir) + + def getClangResourceDir(self): + """ + Return clangs root resource dir. + + If clang is /path/to/bin/clang++ then the resource dir is usually + /path/to/bin/../lib/clang/../ + """ + return self.clang_resource_dir + + def getClangLibraryDir(self): + """ + Return clangs library dir. This directory contains the compiler-rt + libraries. + + If clang is /path/to/bin/clang++ then the library dir is usually + /path/to/bin/../lib/clang/../lib/ + """ + return self.clang_library_dir + + def getStaticCompilerRTLibrary(self, suffix, required=False): + """ + Return the full path to a static clang_rt library or None if it doesn't + exist. + + If required is True then the function will throw if the library is not + found. + """ + libname = 'libclang_rt.%s.a' % suffix + libpath = os.path.join(self.clang_library_dir, libname) + if os.path.isfile(libpath): + return libpath + elif required: + raise RuntimeError('Required library %s not found at %s' % + (libname, libpath)) + else: + return None + + def getStaticCompilerRTLibraryWithArch(self, name, required=False): + """ + Return the full path to a static architecture specific clang_rt library + or None if it doesn't exist. + + If required is True then the function will throw if the library is not + found. + """ + return self.getStaticCompilerRTLibrary( + '%s-%s' % (name, self.target_info.arch), required=required) + + def getSharedCompilerRTLibrary(self, suffix, required=False): + """ + Return the full path to a shared clang_rt library or None if it doesn't + exist. + + If required is True then the function will throw if the library is not + found. + """ + libname = 'libclang_rt.%s' % suffix + if self.target_info.sys == 'darwin': + libname += '.dylib' + else: + libname += '.so' + libpath = os.path.join(self.clang_library_dir, libname) + if os.path.isfile(libpath): + return libpath + elif required: + raise RuntimeError('Required library %s not found at %s' % + (libname, libpath)) + else: + return None + + def getSharedCompilerRTLibraryWithArch(self, name, required=False): + """ + Return the full path to a shared architecture specific clang_rt library + or None if it doesn't exist. + + If required is True then the function will throw if the library is not + found. + """ + return self.getSharedCompilerRTLibrary( + '%s-%s' % (name, self.target_info.arch), required=required) + + def getCompilerRTLibrary(self, name): + """ + Return the full path to a shared or static clang_rt library. Throw if + the library doesn't exist. + + This function will try looking for the shared library first and if that + is not found will search for the static version. + """ + ret = self.getSharedCompilerRTLibrary(name) + if ret is None: + ret = self.getStaticCompilerRTLibrary(name) + if ret is None: + raise RuntimeError('Failed to find library for name: %s' % name) + return ret + + def getCompilerRTLibraryWithArch(self, name): + """ + Return the full path to a shared or static architecture specific + clang_rt library. Throw if the library doesn't exist. + + This function will try looking for the shared library first and if that + is not found will search for the static version. + """ + ret = self.getSharedCompilerRTLibraryWithArch(name) + if ret is None: + ret = self.getStaticCompilerRTLibraryWithArch(name) + if ret is None: + raise RuntimeError('Failed to find library for name: %s' % name) + return ret + + def getProfileRTLinkOptions(self): + """ + Return a list of link options for ProfileRt + """ + raise NotImplementedError("abstract method for %s" % type(self)) + + def getASanLinkOptions(self): + """ + Return a list of link options for ASAN + """ + raise NotImplementedError("abstract method for %s" % type(self)) + + def getMSanLinkOptions(self): + """ + Return a list of link options for MSAN + """ + raise NotImplementedError("abstract method for %s" % type(self)) + + def getUBSanLinkOptions(self): + """ + Return a list of link options for UBSAN + """ + raise NotImplementedError("abstract method for %s" % type(self)) + + def getTSanLinkOptions(self): + """ + Return a list of link options for TSAN + """ + raise NotImplementedError("abstract method for %s" % type(self)) + + +class DarwinClangLinkDriver(BasicClangLinkDriver): + """ + The implementation of BasicClangLinkDriver for stock clang on OS X. + """ + def __init__(self, cxx): + super(DarwinClangLinkDriver, self).__init__(cxx) + + def getProfileRTLinkOptions(self): + return [ + self.getCompilerRTLibrary('profile_osx'), + ] + + def getASanLinkOptions(self): + return [ + self.getCompilerRTLibrary('asan_osx_dynamic') + ] + + def getMSanLinkOptions(self): + raise RuntimeError("MSan not supported") + + def getUBSanLinkOptions(self): + return [ + self.getCompilerRTLibrary('ubsan_osx') + ] + + def getTSanLinkOptions(self): + raise RuntimeError("TSan not supported") + + +class DarwinAppleClangLinkDriver(BasicClangLinkDriver): + """ + The implementation of BasicClangLinkDriver for apple clang on OS X. + """ + def __init__(self, cxx): + super(DarwinAppleClangLinkDriver, self).__init__(cxx) + + def getProfileRTLinkOptions(self): + return [ + self.getCompilerRTLibrary('profile_osx'), + '-lSystem', + self.getCompilerRTLibrary('osx') + ] + + def getASanLinkOptions(self): + return [ + self.getCompilerRTLibrary('asan_osx_dynamic'), + '-lSystem', + self.getCompilerRTLibrary('osx') + ] + + def getMSanLinkOptions(self): + raise RuntimeError("MSan not supported") + + def getUBSanLinkOptions(self): + return [ + self.getCompilerRTLibrary('ubsan_osx'), + '-lSystem', + self.getCompilerRTLibrary('osx') + ] + + def getTSanLinkOptions(self): + raise RuntimeError("TSan not supported") + + +class LinuxClangLinkDriver(BasicClangLinkDriver): + """ + The implementation of BasicClangLinkDriver for clang on linux. + """ + def __init__(self, cxx): + super(LinuxClangLinkDriver, self).__init__(cxx) + + def _getStaticLib(self, name): + return self.getStaticCompilerRTLibraryWithArch(name, required=True) + + def _getWholeStaticLib(self, name): + libpath = self._getStaticLib(name) + return ['-Wl,--whole-archive', libpath, '-Wl,--no-whole-archive'] + + def _getWholeStaticLibWithSyms(self, name): + libpath = self._getStaticLib(name) + return ['-Wl,--whole-archive', libpath, '-Wl,--no-whole-archive', + '-Wl,--dynamic-list=' + libpath + '.syms'] + + def getProfileRTLinkOptions(self): + return [ + self._getStaticLib('profile') + ] + + def getASanLinkOptions(self): + args = [] + args += self._getWholeStaticLibWithSyms('asan') + args += self._getWholeStaticLibWithSyms('asan_cxx') + return args + + def getMSanLinkOptions(self): + return self._getWholeStaticLibWithSyms('msan') + + def getUBSanLinkOptions(self): + args = [] + args += self._getWholeStaticLib('san') + args += self._getWholeStaticLibWithSyms('ubsan') + args += self._getWholeStaticLibWithSyms('ubsan_cxx') + return args + + def getTSanLinkOptions(self): + return self._getWholeStaticLibWithSyms('tsan') + + +def getClangLinkDriver(cxx): + """ + Return the implementation of the Clang linker driver for a giver platform + and compiler. + """ + if cxx.type is None: + raise RuntimeError('Compiler type could not be determined') + elif 'clang' not in cxx.type: + raise RuntimeError('Compiler %s is not clang' % cxx.type) + elif cxx.type == 'apple-clang': + return DarwinAppleClangLinkDriver(cxx) + else: # cxx.type == 'clang' + trip = cxx.getTriple() + if 'darwin' in trip: + return DarwinClangLinkDriver(cxx) + elif 'linux' in trip: + return LinuxClangLinkDriver(cxx) + else: + raise RuntimeError('Unsupported target: %s' % trip) + assert False + + +def main(): + """ + Print a semi-colon list of compiler-rt link flags based on the compiler + and arguments. + + clang-utils.py [--cxx compiler] [--flag cxx_flag]... Spec + options: + --cxx - The cxx compiler to use + --flag - A list of extra flags to configure with + Spec - One of Profile, Address, Memory, MemoryWithAddress, Undefined, + Thread. + """ + from optparse import OptionParser + parser = OptionParser("usage: %prog [options] {CompilerRT Spec}") + parser.add_option('-c', '--cxx', dest='compiler', + help='The compiler to use', + type=str, action='store', default='clang++') + parser.add_option("-f", "--flag", dest="extraFlags", + metavar="NAME=VAL", + help="Add 'NAME' = 'VAL' to the flags used", + type=str, action='append', default=[]) + (opts, args) = parser.parse_args() + cxx = libcxx.compiler.CXXCompiler(opts.compiler, flags=opts.extraFlags) + driver = getClangLinkDriver(cxx) + if len(args) != 1: + print('Invalid args: %s' % args) + raise SystemExit(1) + spec = args[0] + info_specs = { + 'Profile': driver.getProfileRTLinkOptions, + 'Address': driver.getASanLinkOptions, + 'Memory': driver.getMSanLinkOptions, + 'MemoryWithAddress': driver.getMSanLinkOptions, + 'Undefined': driver.getUBSanLinkOptions, + 'Thread': driver.getUBSanLinkOptions + } + if spec not in info_specs.keys(): + print('%s is not a valid spec' % spec) + raise SystemExit(1) + try: + out = ';'.join(info_specs[spec]()) + print(out) + except RuntimeError as e: + print('%s Exception thrown' % e) + SystemError(1) + +if __name__ == '__main__': + main() + raise SystemExit Index: test/libcxx/compiler.py =================================================================== --- test/libcxx/compiler.py +++ test/libcxx/compiler.py @@ -1,8 +1,17 @@ import os +import re import lit.util import libcxx.util +class TargetInfo: + def __init__(self, arch=None, sys=None, vendor=None, abi=None): + self.arch = arch + self.sys = sys + self.vendor = vendor + self.abi = abi + + class CXXCompiler(object): def __init__(self, path, flags=None, compile_flags=None, link_flags=None, use_ccache=False): @@ -133,4 +142,41 @@ def getTriple(self): cmd = [self.path] + self.flags + ['-dumpmachine'] - return lit.util.capture(cmd).strip() + out, err, rc = lit.util.executeCommand(cmd) + if rc != 0: + raise Exception() + return out.strip() + + def getTargetInfo(self): + triple = self.getTriple() + parts = triple.split('-') + assert len(parts) == 3 or len(parts) == 4 + info = TargetInfo(parts[0]) + if len(parts) == 3: + if parts[1] in ['apple'] or parts[2] in ['linux']: + info.vendor = parts[1] + info.sys = parts[2] + else: + info.vendor = 'unknown' + info.sys = parts[1] + info.abi = parts[2] + if info.sys == 'linux': + info.abi = 'gnu' + else: + info.vendor = parts[1] + info.sys = parts[2] + info.abi = parts[3] + return info + + kSearchDirsRe = re.compile('libraries: =([^\n]*)\n') + + def getLibrarySearchPaths(self): + cmd = [self.path] + self.flags + ['-print-search-dirs'] + out, err, rc = lit.util.executeCommand(cmd) + if rc != 0: + raise Exception() + match = CXXCompiler.kSearchDirsRe.search(out) + assert match is not None + dir_list = match.group(1).strip().split(':') + assert len(dir_list) != 0 + return dir_list Index: test/libcxx/test/config.py =================================================================== --- test/libcxx/test/config.py +++ test/libcxx/test/config.py @@ -11,6 +11,7 @@ from libcxx.test.format import LibcxxTestFormat from libcxx.compiler import CXXCompiler +from libcxx.clang_utils import getClangLinkDriver def loadSiteConfig(lit_config, config, param_name, env_name): @@ -94,6 +95,7 @@ self.configure_link_flags() self.configure_warnings() self.configure_sanitizer() + self.configure_coverage() self.configure_substitutions() self.configure_features() @@ -343,7 +345,9 @@ def configure_compile_flags_header_includes(self): support_path = os.path.join(self.libcxx_src_root, 'test/support') self.cxx.compile_flags += ['-I' + support_path] - self.cxx.compile_flags += ['-include', os.path.join(support_path, 'nasty_macros.hpp')] + self.cxx.compile_flags += [ + '-include', os.path.join(support_path, 'nasty_macros.hpp') + ] libcxx_headers = self.get_lit_conf( 'libcxx_headers', os.path.join(self.libcxx_src_root, 'include')) if not os.path.isdir(libcxx_headers): @@ -462,8 +466,8 @@ enable_warnings = self.get_lit_bool('enable_warnings', False) if enable_warnings: self.cxx.compile_flags += ['-Wsystem-headers', '-Wall', '-Werror'] - if ('clang' in self.config.available_features or - 'apple-clang' in self.config.available_features): + if ('clang' in self.config.available_features + or 'apple-clang' in self.config.available_features): self.cxx.compile_flags += ['-Wno-user-defined-literals'] def configure_sanitizer(self): @@ -481,18 +485,30 @@ symbolizer_search_paths) # Setup the sanitizer compile flags self.cxx.flags += ['-g', '-fno-omit-frame-pointer'] + manual_link = ('darwin' in self.config.target_triple and + '-nodefaultlibs' in self.cxx.link_flags) + link_cxx = CXXCompiler(self.cxx.path, self.cxx.flags) + link_driver = getClangLinkDriver(link_cxx) + if manual_link: + self.cxx.link_flags += [ + '-Wl,-rpath,' + link_driver.getClangLibraryDir() + ] if sys.platform.startswith('linux'): self.cxx.link_flags += ['-ldl'] if san == 'Address': self.cxx.flags += ['-fsanitize=address'] if llvm_symbolizer is not None: self.env['ASAN_SYMBOLIZER_PATH'] = llvm_symbolizer + if manual_link: + self.cxx.link_flags += link_driver.getASanLinkOptions() self.config.available_features.add('asan') elif san == 'Memory' or san == 'MemoryWithOrigins': self.cxx.flags += ['-fsanitize=memory'] if san == 'MemoryWithOrigins': self.cxx.compile_flags += [ '-fsanitize-memory-track-origins'] + if manual_link: + self.cxx.link_flags += link_driver.getMSanLinkOptions() if llvm_symbolizer is not None: self.env['MSAN_SYMBOLIZER_PATH'] = llvm_symbolizer self.config.available_features.add('msan') @@ -501,14 +517,29 @@ '-fno-sanitize=vptr,function', '-fno-sanitize-recover'] self.cxx.compile_flags += ['-O3'] + if manual_link: + self.cxx.link_flags += link_driver.getUBSanLinkOptions() self.config.available_features.add('ubsan') elif san == 'Thread': self.cxx.flags += ['-fsanitize=thread'] + if manual_link: + self.cxx.link_flags += link_driver.getTSanLinkOptions() self.config.available_features.add('tsan') else: self.lit_config.fatal('unsupported value for ' 'use_sanitizer: {0}'.format(san)) + def configure_coverage(self): + self.generate_coverage = self.get_lit_bool('generate_coverage', False) + if self.generate_coverage: + self.cxx.flags += ['-g', '--coverage'] + self.cxx.compile_flags += ['-O0'] + if '-nodefaultlibs' in self.cxx.link_flags: + other_cxx = CXXCompiler(self.cxx.path, self.cxx.flags) + link_driver = getClangLinkDriver(other_cxx) + self.cxx.link_flags = (link_driver.getProfileRTLinkOptions() + + self.cxx.link_flags) + def configure_substitutions(self): sub = self.config.substitutions # Configure compiler substitions Index: test/lit.site.cfg.in =================================================================== --- test/lit.site.cfg.in +++ test/lit.site.cfg.in @@ -17,6 +17,7 @@ config.target_triple = "@LIBCXX_TARGET_TRIPLE@" config.sysroot = "@LIBCXX_SYSROOT@" config.gcc_toolchain = "@LIBCXX_GCC_TOOLCHAIN@" +config.generate_coverage = "@LIBCXX_GENERATE_COVERAGE@" # Let the main config do the real work. lit_config.load_config(config, "@LIBCXX_SOURCE_DIR@/test/lit.cfg")