Home | History | Annotate | Download | only in test
      1 # -*- Python -*-
      2 
      3 import os
      4 import platform
      5 import re
      6 import subprocess
      7 import tempfile
      8 
      9 
     10 # Configuration file for the 'lit' test runner.
     11 
     12 # name: The name of this test suite.
     13 config.name = 'Clang'
     14 
     15 # Tweak PATH for Win32
     16 if platform.system() == 'Windows':
     17     # Seek sane tools in directories and set to $PATH.
     18     path = getattr(config, 'lit_tools_dir', None)
     19     path = lit.getToolsPath(path,
     20                             config.environment['PATH'],
     21                             ['cmp.exe', 'grep.exe', 'sed.exe'])
     22     if path is not None:
     23         path = os.path.pathsep.join((path,
     24                                      config.environment['PATH']))
     25         config.environment['PATH'] = path
     26 
     27 # Choose between lit's internal shell pipeline runner and a real shell.  If
     28 # LIT_USE_INTERNAL_SHELL is in the environment, we use that as an override.
     29 use_lit_shell = os.environ.get("LIT_USE_INTERNAL_SHELL")
     30 if use_lit_shell:
     31     # 0 is external, "" is default, and everything else is internal.
     32     execute_external = (use_lit_shell == "0")
     33 else:
     34     # Otherwise we default to internal on Windows and external elsewhere, as
     35     # bash on Windows is usually very slow.
     36     execute_external = (not sys.platform in ['win32'])
     37 
     38 # testFormat: The test format to use to interpret tests.
     39 #
     40 # For now we require '&&' between commands, until they get globally killed and
     41 # the test runner updated.
     42 config.test_format = lit.formats.ShTest(execute_external)
     43 
     44 # suffixes: A list of file extensions to treat as test files.
     45 config.suffixes = ['.c', '.cpp', '.m', '.mm', '.cu', '.ll', '.cl', '.s']
     46 
     47 # test_source_root: The root path where tests are located.
     48 config.test_source_root = os.path.dirname(__file__)
     49 
     50 # test_exec_root: The root path where tests should be run.
     51 clang_obj_root = getattr(config, 'clang_obj_root', None)
     52 if clang_obj_root is not None:
     53     config.test_exec_root = os.path.join(clang_obj_root, 'test')
     54 
     55 # Set llvm_{src,obj}_root for use by others.
     56 config.llvm_src_root = getattr(config, 'llvm_src_root', None)
     57 config.llvm_obj_root = getattr(config, 'llvm_obj_root', None)
     58 
     59 # Clear some environment variables that might affect Clang.
     60 #
     61 # This first set of vars are read by Clang, but shouldn't affect tests
     62 # that aren't specifically looking for these features, or are required
     63 # simply to run the tests at all.
     64 #
     65 # FIXME: Should we have a tool that enforces this?
     66 
     67 # safe_env_vars = ('TMPDIR', 'TEMP', 'TMP', 'USERPROFILE', 'PWD',
     68 #                  'MACOSX_DEPLOYMENT_TARGET', 'IPHONEOS_DEPLOYMENT_TARGET',
     69 #                  'IOS_SIMULATOR_DEPLOYMENT_TARGET',
     70 #                  'VCINSTALLDIR', 'VC100COMNTOOLS', 'VC90COMNTOOLS',
     71 #                  'VC80COMNTOOLS')
     72 possibly_dangerous_env_vars = ['COMPILER_PATH', 'RC_DEBUG_OPTIONS',
     73                                'CINDEXTEST_PREAMBLE_FILE', 'LIBRARY_PATH',
     74                                'CPATH', 'C_INCLUDE_PATH', 'CPLUS_INCLUDE_PATH',
     75                                'OBJC_INCLUDE_PATH', 'OBJCPLUS_INCLUDE_PATH',
     76                                'LIBCLANG_TIMING', 'LIBCLANG_OBJTRACKING',
     77                                'LIBCLANG_LOGGING', 'LIBCLANG_BGPRIO_INDEX',
     78                                'LIBCLANG_BGPRIO_EDIT', 'LIBCLANG_NOTHREADS',
     79                                'LIBCLANG_RESOURCE_USAGE',
     80                                'LIBCLANG_CODE_COMPLETION_LOGGING']
     81 # Clang/Win32 may refer to %INCLUDE%. vsvarsall.bat sets it.
     82 if platform.system() != 'Windows':
     83     possibly_dangerous_env_vars.append('INCLUDE')
     84 for name in possibly_dangerous_env_vars:
     85   if name in config.environment:
     86     del config.environment[name]
     87 
     88 # Tweak the PATH to include the tools dir and the scripts dir.
     89 if clang_obj_root is not None:
     90     llvm_tools_dir = getattr(config, 'llvm_tools_dir', None)
     91     if not llvm_tools_dir:
     92         lit.fatal('No LLVM tools dir set!')
     93     path = os.path.pathsep.join((llvm_tools_dir, config.environment['PATH']))
     94     config.environment['PATH'] = path
     95     llvm_libs_dir = getattr(config, 'llvm_libs_dir', None)
     96     if not llvm_libs_dir:
     97         lit.fatal('No LLVM libs dir set!')
     98     path = os.path.pathsep.join((llvm_libs_dir,
     99                                  config.environment.get('LD_LIBRARY_PATH','')))
    100     config.environment['LD_LIBRARY_PATH'] = path
    101 
    102 # Propagate path to symbolizer for ASan/MSan.
    103 for symbolizer in ['ASAN_SYMBOLIZER_PATH', 'MSAN_SYMBOLIZER_PATH']:
    104     if symbolizer in os.environ:
    105         config.environment[symbolizer] = os.environ[symbolizer]
    106 
    107 ###
    108 
    109 # Check that the object root is known.
    110 if config.test_exec_root is None:
    111     # Otherwise, we haven't loaded the site specific configuration (the user is
    112     # probably trying to run on a test file directly, and either the site
    113     # configuration hasn't been created by the build system, or we are in an
    114     # out-of-tree build situation).
    115 
    116     # Check for 'clang_site_config' user parameter, and use that if available.
    117     site_cfg = lit.params.get('clang_site_config', None)
    118     if site_cfg and os.path.exists(site_cfg):
    119         lit.load_config(config, site_cfg)
    120         raise SystemExit
    121 
    122     # Try to detect the situation where we are using an out-of-tree build by
    123     # looking for 'llvm-config'.
    124     #
    125     # FIXME: I debated (i.e., wrote and threw away) adding logic to
    126     # automagically generate the lit.site.cfg if we are in some kind of fresh
    127     # build situation. This means knowing how to invoke the build system though,
    128     # and I decided it was too much magic. We should solve this by just having
    129     # the .cfg files generated during the configuration step.
    130 
    131     llvm_config = lit.util.which('llvm-config', config.environment['PATH'])
    132     if not llvm_config:
    133         lit.fatal('No site specific configuration available!')
    134 
    135     # Get the source and object roots.
    136     llvm_src_root = lit.util.capture(['llvm-config', '--src-root']).strip()
    137     llvm_obj_root = lit.util.capture(['llvm-config', '--obj-root']).strip()
    138     clang_src_root = os.path.join(llvm_src_root, "tools", "clang")
    139     clang_obj_root = os.path.join(llvm_obj_root, "tools", "clang")
    140 
    141     # Validate that we got a tree which points to here, using the standard
    142     # tools/clang layout.
    143     this_src_root = os.path.dirname(config.test_source_root)
    144     if os.path.realpath(clang_src_root) != os.path.realpath(this_src_root):
    145         lit.fatal('No site specific configuration available!')
    146 
    147     # Check that the site specific configuration exists.
    148     site_cfg = os.path.join(clang_obj_root, 'test', 'lit.site.cfg')
    149     if not os.path.exists(site_cfg):
    150         lit.fatal('No site specific configuration available! You may need to '
    151                   'run "make test" in your Clang build directory.')
    152 
    153     # Okay, that worked. Notify the user of the automagic, and reconfigure.
    154     lit.note('using out-of-tree build at %r' % clang_obj_root)
    155     lit.load_config(config, site_cfg)
    156     raise SystemExit
    157 
    158 ###
    159 
    160 # Discover the 'clang' and 'clangcc' to use.
    161 
    162 import os
    163 
    164 def inferClang(PATH):
    165     # Determine which clang to use.
    166     clang = os.getenv('CLANG')
    167 
    168     # If the user set clang in the environment, definitely use that and don't
    169     # try to validate.
    170     if clang:
    171         return clang
    172 
    173     # Otherwise look in the path.
    174     clang = lit.util.which('clang', PATH)
    175 
    176     if not clang:
    177         lit.fatal("couldn't find 'clang' program, try setting "
    178                   "CLANG in your environment")
    179 
    180     return clang
    181 
    182 config.clang = inferClang(config.environment['PATH']).replace('\\', '/')
    183 if not lit.quiet:
    184     lit.note('using clang: %r' % config.clang)
    185 
    186 # Note that when substituting %clang_cc1 also fill in the include directory of
    187 # the builtin headers. Those are part of even a freestanding environment, but
    188 # Clang relies on the driver to locate them.
    189 def getClangBuiltinIncludeDir(clang):
    190     # FIXME: Rather than just getting the version, we should have clang print
    191     # out its resource dir here in an easy to scrape form.
    192     cmd = subprocess.Popen([clang, '-print-file-name=include'],
    193                            stdout=subprocess.PIPE)
    194     if not cmd.stdout:
    195       lit.fatal("Couldn't find the include dir for Clang ('%s')" % clang)
    196     dir = cmd.stdout.read().strip()
    197     if sys.platform in ['win32'] and execute_external:
    198         # Don't pass dosish path separator to msys bash.exe.
    199         dir = dir.replace('\\', '/')
    200     return dir
    201 
    202 config.substitutions.append( ('%clang_cc1', '%s -cc1 -internal-isystem %s'
    203                               % (config.clang,
    204                                  getClangBuiltinIncludeDir(config.clang))) )
    205 config.substitutions.append( ('%clang_cpp', ' ' + config.clang +
    206                               ' --driver-mode=cpp '))
    207 config.substitutions.append( ('%clang_cl', ' ' + config.clang +
    208                               ' --driver-mode=cl '))
    209 config.substitutions.append( ('%clangxx', ' ' + config.clang +
    210                               ' --driver-mode=g++ '))
    211 config.substitutions.append( ('%clang', ' ' + config.clang + ' ') )
    212 config.substitutions.append( ('%test_debuginfo', ' ' + config.llvm_src_root + '/utils/test_debuginfo.pl ') )
    213 
    214 # FIXME: Find nicer way to prohibit this.
    215 config.substitutions.append(
    216     (' clang ', """*** Do not use 'clang' in tests, use '%clang'. ***""") )
    217 config.substitutions.append(
    218     (' clang\+\+ ', """*** Do not use 'clang++' in tests, use '%clangxx'. ***"""))
    219 config.substitutions.append(
    220     (' clang-cc ',
    221      """*** Do not use 'clang-cc' in tests, use '%clang_cc1'. ***""") )
    222 config.substitutions.append(
    223     (' clang -cc1 ',
    224      """*** Do not use 'clang -cc1' in tests, use '%clang_cc1'. ***""") )
    225 config.substitutions.append(
    226     (' %clang-cc1 ',
    227      """*** invalid substitution, use '%clang_cc1'. ***""") )
    228 config.substitutions.append(
    229     (' %clang-cpp ',
    230      """*** invalid substitution, use '%clang_cpp'. ***""") )
    231 config.substitutions.append(
    232     (' %clang-cl ',
    233      """*** invalid substitution, use '%clang_cl'. ***""") )
    234 
    235 ###
    236 
    237 # Set available features we allow tests to conditionalize on.
    238 #
    239 # As of 2011.08, crash-recovery tests still do not pass on FreeBSD.
    240 if platform.system() not in ['FreeBSD']:
    241     config.available_features.add('crash-recovery')
    242 
    243 # Shell execution
    244 if execute_external:
    245     config.available_features.add('shell')
    246 
    247 # Exclude MSYS due to transforming '/' to 'X:/mingwroot/'.
    248 if not platform.system() in ['Windows'] or not execute_external:
    249     config.available_features.add('shell-preserves-root')
    250 
    251 # ANSI escape sequences in non-dumb terminal
    252 if platform.system() not in ['Windows']:
    253     config.available_features.add('ansi-escape-sequences')
    254 
    255 # Case-insensitive file system
    256 def is_filesystem_case_insensitive():
    257     handle, path = tempfile.mkstemp(prefix='case-test', dir=config.test_exec_root)
    258     isInsensitive = os.path.exists(
    259         os.path.join(
    260             os.path.dirname(path),
    261             os.path.basename(path).upper()
    262             ))
    263     os.close(handle)
    264     os.remove(path)
    265     return isInsensitive
    266 
    267 if is_filesystem_case_insensitive():
    268     config.available_features.add('case-insensitive-filesystem')
    269 
    270 # Tests that require the /dev/fd filesystem.
    271 if os.path.exists("/dev/fd/0") and sys.platform not in ['cygwin']:
    272     config.available_features.add('dev-fd-fs')
    273 
    274 # [PR8833] LLP64-incompatible tests
    275 if not re.match(r'^x86_64.*-(win32|mingw32)$', config.target_triple):
    276     config.available_features.add('LP64')
    277 
    278 # [PR12920] "clang-driver" -- set if gcc driver is not used.
    279 if not re.match(r'.*-(cygwin|mingw32)$', config.target_triple):
    280     config.available_features.add('clang-driver')
    281 
    282 # Registered Targets
    283 def get_llc_props(tool):
    284     set_of_targets = set()
    285     enable_assertions = False
    286 
    287     cmd = subprocess.Popen([tool, '-version'], stdout=subprocess.PIPE)
    288 
    289     # Parse the stdout to get the list of registered targets.
    290     parse_targets = False
    291     for line in cmd.stdout:
    292         if parse_targets:
    293             m = re.match( r'(.*) - ', line)
    294             if m is not None:
    295                 set_of_targets.add(m.group(1).strip() + '-registered-target')
    296             else:
    297                 break
    298         elif "Registered Targets:" in line:
    299             parse_targets = True
    300 
    301         if re.search(r'with assertions', line):
    302             enable_assertions = True
    303 
    304     return {"set_of_targets":    set_of_targets,
    305             "enable_assertions": enable_assertions}
    306 
    307 llc_props = get_llc_props(os.path.join(llvm_tools_dir, 'llc'))
    308 if len(llc_props['set_of_targets']) > 0:
    309     config.available_features.update(llc_props['set_of_targets'])
    310 else:
    311     lit.fatal('No Targets Registered with the LLVM Tools!')
    312 
    313 if llc_props['enable_assertions']:
    314     config.available_features.add('asserts')
    315 
    316 if lit.util.which('xmllint'):
    317     config.available_features.add('xmllint')
    318 
    319 # Sanitizers.
    320 if config.llvm_use_sanitizer == "Address":
    321     config.available_features.add("asan")
    322 if (config.llvm_use_sanitizer == "Memory" or
    323         config.llvm_use_sanitizer == "MemoryWithOrigins"):
    324     config.available_features.add("msan")
    325 
    326 # Check if we should run long running tests.
    327 if lit.params.get("run_long_tests", None) == "true":
    328     config.available_features.add("long_tests")
    329 
    330 # Check if we should use gmalloc.
    331 use_gmalloc_str = lit.params.get('use_gmalloc', None)
    332 if use_gmalloc_str is not None:
    333     if use_gmalloc_str.lower() in ('1', 'true'):
    334         use_gmalloc = True
    335     elif use_gmalloc_str.lower() in ('', '0', 'false'):
    336         use_gmalloc = False
    337     else:
    338         lit.fatal('user parameter use_gmalloc should be 0 or 1')
    339 else:
    340     # Default to not using gmalloc
    341     use_gmalloc = False
    342 
    343 # Allow use of an explicit path for gmalloc library.
    344 # Will default to '/usr/lib/libgmalloc.dylib' if not set.
    345 gmalloc_path_str = lit.params.get('gmalloc_path', '/usr/lib/libgmalloc.dylib')
    346 
    347 if use_gmalloc:
    348      config.environment.update({'DYLD_INSERT_LIBRARIES' : gmalloc_path_str})
    349