Cleanup exception handling in `clang_utils.py`.
http://reviews.llvm.org/D7542
Files:
CMakeLists.txt
cmake/Modules/GetCompilerRTOptions.cmake
lib/CMakeLists.txt
test/libcxx/clang_utils.py
test/libcxx/compiler.py
test/libcxx/test/config.py
EMAIL PREFERENCES
http://reviews.llvm.org/settings/panel/emailpreferences/
Index: CMakeLists.txt
===================================================================
--- CMakeLists.txt
+++ CMakeLists.txt
@@ -96,9 +96,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 "")
@@ -213,7 +216,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 +271,29 @@
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}")
+# 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}")
+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/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
@@ -50,6 +50,7 @@
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.
Index: test/libcxx/clang_utils.py
===================================================================
--- /dev/null
+++ test/libcxx/clang_utils.py
@@ -0,0 +1,357 @@
+"""
+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)
+ exit(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)
+ exit(1)
+ try:
+ out = ';'.join(info_specs[spec]())
+ print(out)
+ except RuntimeError as e:
+ print('%s Exception thrown' % e)
+ exit(1)
+ except:
+ print('Unknown exception thrown')
+ exit(1)
+
+if __name__ == '__main__':
+ main()
+ exit(0)
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):
@@ -343,7 +344,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 +465,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 +484,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,9 +516,13 @@
'-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 '
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits