Misc changes

http://reviews.llvm.org/D7542

Files:
  CMakeLists.txt
  cmake/Modules/CodeCoverage.cmake
  cmake/Modules/GetCompilerRTOptions.cmake
  lib/CMakeLists.txt
  test/CMakeLists.txt
  test/libcxx/clang_utils.py
  test/libcxx/compiler.py
  test/libcxx/test/config.py
  test/lit.site.cfg.in

EMAIL PREFERENCES
  http://reviews.llvm.org/settings/panel/emailpreferences/
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/<X>.<Y>.<Z>/
+        """
+        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/<X>.<Y>.<Z>/lib/<platform>
+        """
+        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")
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to