1#!/usr/bin/env python3 2# Copyright 2016 Google Inc. All Rights Reserved. 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS-IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16import yaml 17 18# "smoke tests" are run before other build matrix rows. 19build_matrix_smoke_test_rows = [] 20build_matrix_rows = [] 21 22def determine_compiler_kind(compiler): 23 if compiler.startswith('gcc'): 24 return 'gcc' 25 elif compiler.startswith('clang'): 26 return 'clang' 27 else: 28 raise Exception('Unexpected compiler: %s' % compiler) 29 30def determine_tests(asan, ubsan, smoke_tests, use_precompiled_headers_in_tests, exclude_tests, 31 include_only_tests): 32 tests = [] 33 has_debug_build = False 34 tests += ['ReleasePlain'] 35 if asan: 36 has_debug_build = True 37 if ubsan: 38 tests += ['DebugAsanUbsan'] 39 else: 40 tests += ['DebugAsan'] 41 if ubsan and not asan: 42 raise Exception('Enabling UBSan but not ASan is not currently supported.') 43 if not has_debug_build: 44 tests += ['DebugPlain'] 45 for smoke_test in smoke_tests: 46 if smoke_test not in tests: 47 tests += [smoke_test] 48 excessive_excluded_tests = set(exclude_tests) - set(tests) 49 if excessive_excluded_tests: 50 raise Exception( 51 'Some tests were excluded but were not going to run anyway: %s. ' 52 'Tests to run (ignoring the possible NoPch prefix): %s' 53 % (excessive_excluded_tests, tests)) 54 if include_only_tests is not None: 55 if exclude_tests != []: 56 raise Exception('Using exclude_tests and include_only_tests together is not supported.') 57 tests = include_only_tests 58 else: 59 tests = [test for test in tests if test not in exclude_tests] 60 if not use_precompiled_headers_in_tests: 61 tests = [test + 'NoPch' for test in tests] 62 return tests 63 64def generate_export_statements_for_env(env): 65 return ' '.join(['export %s=\'%s\';' % (var_name, value) for (var_name, value) in sorted(env.items())]) 66 67def generate_env_string_for_env(env): 68 return ' '.join(['%s=%s' % (var_name, value) for (var_name, value) in sorted(env.items())]) 69 70def add_ubuntu_tests(ubuntu_version, compiler, os='linux', stl=None, asan=True, ubsan=True, 71 use_precompiled_headers_in_tests=True, smoke_tests=[], exclude_tests=[], include_only_tests=None): 72 env = { 73 'UBUNTU': ubuntu_version, 74 'COMPILER': compiler 75 } 76 if stl is not None: 77 env['STL'] = stl 78 compiler_kind = determine_compiler_kind(compiler) 79 export_statements = 'export OS=' + os + '; ' + generate_export_statements_for_env(env=env) 80 test_environment_template = {'os': 'linux', 'compiler': compiler_kind, 81 'install': '%s extras/scripts/travis_ci_install_linux.sh' % export_statements} 82 tests = determine_tests(asan, ubsan, smoke_tests, 83 use_precompiled_headers_in_tests=use_precompiled_headers_in_tests, 84 exclude_tests=exclude_tests, 85 include_only_tests=include_only_tests) 86 for test in tests: 87 test_environment = test_environment_template.copy() 88 test_environment['script'] = '%s extras/scripts/postsubmit.sh %s' % (export_statements, test) 89 # The TEST variable has no effect on the test run, but allows to see the test name in the Travis CI dashboard. 90 test_environment['env'] = generate_env_string_for_env(env) + " TEST=%s" % test 91 if test in smoke_tests: 92 build_matrix_smoke_test_rows.append(test_environment) 93 else: 94 build_matrix_rows.append(test_environment) 95 96 97def add_osx_tests(compiler, xcode_version=None, stl=None, asan=True, ubsan=True, 98 use_precompiled_headers_in_tests=True, smoke_tests=[], exclude_tests=[], include_only_tests=None): 99 env = {'COMPILER': compiler} 100 if stl is not None: 101 env['STL'] = stl 102 compiler_kind = determine_compiler_kind(compiler) 103 export_statements = 'export OS=osx; ' + generate_export_statements_for_env(env=env) 104 test_environment_template = {'os': 'osx', 'compiler': compiler_kind, 105 'install': '%s extras/scripts/travis_ci_install_osx.sh' % export_statements} 106 if xcode_version is not None: 107 test_environment_template['osx_image'] = 'xcode%s' % xcode_version 108 109 tests = determine_tests(asan, ubsan, smoke_tests, 110 use_precompiled_headers_in_tests=use_precompiled_headers_in_tests, 111 exclude_tests=exclude_tests, include_only_tests=include_only_tests) 112 for test in tests: 113 test_environment = test_environment_template.copy() 114 test_environment['script'] = '%s extras/scripts/postsubmit.sh %s' % (export_statements, test) 115 # The TEST variable has no effect on the test run, but allows to see the test name in the Travis CI dashboard. 116 test_environment['env'] = generate_env_string_for_env(env) + " TEST=%s" % test 117 if test in smoke_tests: 118 build_matrix_smoke_test_rows.append(test_environment) 119 else: 120 build_matrix_rows.append(test_environment) 121 122 123def add_bazel_tests(ubuntu_version, smoke_tests=[]): 124 env = { 125 'UBUNTU': ubuntu_version, 126 'COMPILER': 'bazel', 127 } 128 test = 'DebugPlain' 129 export_statements = 'export OS=linux; ' + generate_export_statements_for_env(env=env) 130 test_environment = {'os': 'linux', 131 'compiler': 'gcc', 132 'env': generate_env_string_for_env(env), 133 'install': '%s extras/scripts/travis_ci_install_linux.sh' % export_statements, 134 'script': '%s extras/scripts/postsubmit.sh %s' % (export_statements, test)} 135 if test in smoke_tests: 136 build_matrix_smoke_test_rows.append(test_environment) 137 else: 138 build_matrix_rows.append(test_environment) 139 140# TODO: re-enable ASan/UBSan once they work in Travis CI. ATM (as of 18 November 2017) they fail due to https://github.com/google/sanitizers/issues/837 141add_ubuntu_tests(ubuntu_version='18.10', compiler='gcc-8', asan=False, ubsan=False, smoke_tests=['DebugPlain', 'ReleasePlain']) 142add_ubuntu_tests(ubuntu_version='18.10', compiler='clang-4.0', stl='libstdc++') 143add_ubuntu_tests(ubuntu_version='18.10', compiler='clang-7.0', stl='libstdc++', smoke_tests=['DebugPlain', 'DebugAsanUbsan', 'ReleasePlain']) 144 145add_bazel_tests(ubuntu_version='16.04', smoke_tests=['DebugPlain']) 146 147# ASan/UBSan are disabled for all these, the analysis on later versions is better anyway. 148# Also, in some combinations they wouldn't work. 149add_ubuntu_tests(ubuntu_version='14.04', compiler='gcc-5', asan=False, ubsan=False) 150add_ubuntu_tests(ubuntu_version='14.04', compiler='clang-3.5', stl='libstdc++', asan=False, ubsan=False) 151add_ubuntu_tests(ubuntu_version='14.04', compiler='clang-3.9', stl='libstdc++', asan=False, ubsan=False) 152add_ubuntu_tests(ubuntu_version='14.04', compiler='clang-3.5', stl='libc++', asan=False, ubsan=False) 153add_ubuntu_tests(ubuntu_version='14.04', compiler='clang-3.9', stl='libc++', asan=False, ubsan=False) 154 155# Asan/Ubsan are disabled because it generates lots of warnings like: 156# warning: direct access in [...] to global weak symbol guard variable for [...] means the weak symbol cannot be 157# overridden at runtime. This was likely caused by different translation units being compiled with different 158# visibility settings. 159# and the build eventually fails or times out. 160add_osx_tests(compiler='gcc-5', xcode_version='8', asan=False, ubsan=False) 161add_osx_tests(compiler='gcc-6', xcode_version='8', asan=False, ubsan=False, smoke_tests=['DebugPlain']) 162add_osx_tests(compiler='clang-4.0', xcode_version='8', stl='libc++', smoke_tests=['DebugPlain']) 163 164# UBSan is disabled because AppleClang does not support -fsanitize=undefined. 165add_osx_tests(compiler='clang-default', xcode_version='7.3', stl='libc++', ubsan=False) 166# UBSan is disabled because AppleClang does not support -fsanitize=undefined. 167add_osx_tests(compiler='clang-default', xcode_version='8.2', stl='libc++', ubsan=False) 168 169add_osx_tests(compiler='clang-default', xcode_version='9.4', stl='libc++') 170add_osx_tests(compiler='clang-default', xcode_version='10', stl='libc++', smoke_tests=['DebugPlain']) 171 172# ** Disabled combinations ** 173# 174# These fail with "'type_traits' file not found" (the <type_traits> header is missing). 175# 176# add_osx_tests('gcc-default', stl='libstdc++') 177# add_osx_tests('clang-default', stl='libstdc++') 178# add_osx_tests('clang-3.5', stl='libstdc++') 179# add_osx_tests('clang-3.6', stl='libstdc++') 180# 181# 182# The compiler complains that the 2-argument constructor of std::pair is ambiguous, even after 183# adding explicit casts to the exact types of the expected overload. 184# 185# add_osx_tests('clang-default', stl='libc++') 186# 187# 188# This triggers an assert error in the compiler, with the message: 189# "expected to get called on an inlined function!" [...] function isMSExternInline, file Decl.cpp, line 2647. 190# 191# add_osx_tests('clang-3.5', stl='libc++', asan=False, ubsan=False) 192# 193# 194# This fails with this error: 195# /usr/include/c++/v1/string:1938:44: error: 'basic_string<_CharT, _Traits, _Allocator>' is missing 196# exception specification 'noexcept(is_nothrow_copy_constructible<allocator_type>::value)' 197# TODO: Try again every once in a while (to re-enable these once the bug in libc++ is fixed). 198# 199# add_ubuntu_tests(ubuntu_version='16.04', compiler='clang-3.8', stl='libc++', asan=False, ubsan=False) 200# 201 202 203yaml_file = { 204 'sudo': 'required', 205 'dist': 'trusty', 206 'services' : ['docker'], 207 'language': 'cpp', 208 'branches': { 209 'only': ['master'], 210 }, 211 'matrix': { 212 'fast_finish': True, 213 'include': build_matrix_smoke_test_rows + build_matrix_rows, 214 }, 215} 216 217class CustomDumper(yaml.SafeDumper): 218 def ignore_aliases(self, _data): 219 return True 220 221print('#') 222print('# This file was auto-generated from extras/scripts/travis_yml_generator.py, DO NOT EDIT') 223print('#') 224print(yaml.dump(yaml_file, default_flow_style=False, Dumper=CustomDumper)) 225