普通文本  |  225行  |  9.99 KB

#!/usr/bin/env python3
#  Copyright 2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS-IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import yaml

# "smoke tests" are run before other build matrix rows.
build_matrix_smoke_test_rows = []
build_matrix_rows = []

def determine_compiler_kind(compiler):
  if compiler.startswith('gcc'):
    return 'gcc'
  elif compiler.startswith('clang'):
    return 'clang'
  else:
    raise Exception('Unexpected compiler: %s' % compiler)

def determine_tests(asan, ubsan, smoke_tests, use_precompiled_headers_in_tests, exclude_tests,
                    include_only_tests):
  tests = []
  has_debug_build = False
  tests += ['ReleasePlain']
  if asan:
    has_debug_build = True
    if ubsan:
      tests += ['DebugAsanUbsan']
    else:
      tests += ['DebugAsan']
  if ubsan and not asan:
    raise Exception('Enabling UBSan but not ASan is not currently supported.')
  if not has_debug_build:
    tests += ['DebugPlain']
  for smoke_test in smoke_tests:
    if smoke_test not in tests:
      tests += [smoke_test]
  excessive_excluded_tests = set(exclude_tests) - set(tests)
  if excessive_excluded_tests:
    raise Exception(
      'Some tests were excluded but were not going to run anyway: %s. '
      'Tests to run (ignoring the possible NoPch prefix): %s'
      % (excessive_excluded_tests, tests))
  if include_only_tests is not None:
    if exclude_tests != []:
      raise Exception('Using exclude_tests and include_only_tests together is not supported.')
    tests = include_only_tests
  else:
    tests = [test for test in tests if test not in exclude_tests]
  if not use_precompiled_headers_in_tests:
    tests = [test + 'NoPch' for test in tests]
  return tests

def generate_export_statements_for_env(env):
  return ' '.join(['export %s=\'%s\';' % (var_name, value) for (var_name, value) in sorted(env.items())])

def generate_env_string_for_env(env):
  return ' '.join(['%s=%s' % (var_name, value) for (var_name, value) in sorted(env.items())])

def add_ubuntu_tests(ubuntu_version, compiler, os='linux', stl=None, asan=True, ubsan=True,
                     use_precompiled_headers_in_tests=True, smoke_tests=[], exclude_tests=[], include_only_tests=None):
  env = {
    'UBUNTU': ubuntu_version,
    'COMPILER': compiler
  }
  if stl is not None:
    env['STL'] = stl
  compiler_kind = determine_compiler_kind(compiler)
  export_statements = 'export OS=' + os + '; ' + generate_export_statements_for_env(env=env)
  test_environment_template = {'os': 'linux', 'compiler': compiler_kind,
                               'install': '%s extras/scripts/travis_ci_install_linux.sh' % export_statements}
  tests = determine_tests(asan, ubsan, smoke_tests,
                          use_precompiled_headers_in_tests=use_precompiled_headers_in_tests,
                          exclude_tests=exclude_tests,
                          include_only_tests=include_only_tests)
  for test in tests:
    test_environment = test_environment_template.copy()
    test_environment['script'] = '%s extras/scripts/postsubmit.sh %s' % (export_statements, test)
    # The TEST variable has no effect on the test run, but allows to see the test name in the Travis CI dashboard.
    test_environment['env'] = generate_env_string_for_env(env) + " TEST=%s" % test
    if test in smoke_tests:
      build_matrix_smoke_test_rows.append(test_environment)
    else:
      build_matrix_rows.append(test_environment)


def add_osx_tests(compiler, xcode_version=None, stl=None, asan=True, ubsan=True,
                  use_precompiled_headers_in_tests=True, smoke_tests=[], exclude_tests=[], include_only_tests=None):
  env = {'COMPILER': compiler}
  if stl is not None:
    env['STL'] = stl
  compiler_kind = determine_compiler_kind(compiler)
  export_statements = 'export OS=osx; ' + generate_export_statements_for_env(env=env)
  test_environment_template = {'os': 'osx', 'compiler': compiler_kind,
                               'install': '%s extras/scripts/travis_ci_install_osx.sh' % export_statements}
  if xcode_version is not None:
    test_environment_template['osx_image'] = 'xcode%s' % xcode_version

  tests = determine_tests(asan, ubsan, smoke_tests,
                          use_precompiled_headers_in_tests=use_precompiled_headers_in_tests,
                          exclude_tests=exclude_tests, include_only_tests=include_only_tests)
  for test in tests:
    test_environment = test_environment_template.copy()
    test_environment['script'] = '%s extras/scripts/postsubmit.sh %s' % (export_statements, test)
    # The TEST variable has no effect on the test run, but allows to see the test name in the Travis CI dashboard.
    test_environment['env'] = generate_env_string_for_env(env) + " TEST=%s" % test
    if test in smoke_tests:
      build_matrix_smoke_test_rows.append(test_environment)
    else:
      build_matrix_rows.append(test_environment)


def add_bazel_tests(ubuntu_version, smoke_tests=[]):
  env = {
    'UBUNTU': ubuntu_version,
    'COMPILER': 'bazel',
  }
  test = 'DebugPlain'
  export_statements = 'export OS=linux; ' + generate_export_statements_for_env(env=env)
  test_environment = {'os': 'linux',
                      'compiler': 'gcc',
                      'env': generate_env_string_for_env(env),
                      'install': '%s extras/scripts/travis_ci_install_linux.sh' % export_statements,
                      'script': '%s extras/scripts/postsubmit.sh %s' % (export_statements, test)}
  if test in smoke_tests:
    build_matrix_smoke_test_rows.append(test_environment)
  else:
    build_matrix_rows.append(test_environment)

# 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
add_ubuntu_tests(ubuntu_version='18.10', compiler='gcc-8', asan=False, ubsan=False, smoke_tests=['DebugPlain', 'ReleasePlain'])
add_ubuntu_tests(ubuntu_version='18.10', compiler='clang-4.0', stl='libstdc++')
add_ubuntu_tests(ubuntu_version='18.10', compiler='clang-7.0', stl='libstdc++', smoke_tests=['DebugPlain', 'DebugAsanUbsan', 'ReleasePlain'])

add_bazel_tests(ubuntu_version='16.04', smoke_tests=['DebugPlain'])

# ASan/UBSan are disabled for all these, the analysis on later versions is better anyway.
# Also, in some combinations they wouldn't work.
add_ubuntu_tests(ubuntu_version='14.04', compiler='gcc-5', asan=False, ubsan=False)
add_ubuntu_tests(ubuntu_version='14.04', compiler='clang-3.5', stl='libstdc++', asan=False, ubsan=False)
add_ubuntu_tests(ubuntu_version='14.04', compiler='clang-3.9', stl='libstdc++', asan=False, ubsan=False)
add_ubuntu_tests(ubuntu_version='14.04', compiler='clang-3.5', stl='libc++', asan=False, ubsan=False)
add_ubuntu_tests(ubuntu_version='14.04', compiler='clang-3.9', stl='libc++', asan=False, ubsan=False)

# Asan/Ubsan are disabled because it generates lots of warnings like:
#    warning: direct access in [...] to global weak symbol guard variable for [...] means the weak symbol cannot be
#    overridden at runtime. This was likely caused by different translation units being compiled with different
#    visibility settings.
# and the build eventually fails or times out.
add_osx_tests(compiler='gcc-5', xcode_version='8', asan=False, ubsan=False)
add_osx_tests(compiler='gcc-6', xcode_version='8', asan=False, ubsan=False, smoke_tests=['DebugPlain'])
add_osx_tests(compiler='clang-4.0', xcode_version='8', stl='libc++', smoke_tests=['DebugPlain'])

# UBSan is disabled because AppleClang does not support -fsanitize=undefined.
add_osx_tests(compiler='clang-default', xcode_version='7.3', stl='libc++', ubsan=False)
# UBSan is disabled because AppleClang does not support -fsanitize=undefined.
add_osx_tests(compiler='clang-default', xcode_version='8.2', stl='libc++', ubsan=False)

add_osx_tests(compiler='clang-default', xcode_version='9.4', stl='libc++')
add_osx_tests(compiler='clang-default', xcode_version='10', stl='libc++', smoke_tests=['DebugPlain'])

# ** Disabled combinations **
#
# These fail with "'type_traits' file not found" (the <type_traits> header is missing).
#
#   add_osx_tests('gcc-default', stl='libstdc++')
#   add_osx_tests('clang-default', stl='libstdc++')
#   add_osx_tests('clang-3.5', stl='libstdc++')
#   add_osx_tests('clang-3.6', stl='libstdc++')
#
#
# The compiler complains that the 2-argument constructor of std::pair is ambiguous, even after
# adding explicit casts to the exact types of the expected overload.
#
#   add_osx_tests('clang-default', stl='libc++')
#
#
# This triggers an assert error in the compiler, with the message:
# "expected to get called on an inlined function!" [...] function isMSExternInline, file Decl.cpp, line 2647.
#
#   add_osx_tests('clang-3.5', stl='libc++', asan=False, ubsan=False)
#
#
# This fails with this error:
# /usr/include/c++/v1/string:1938:44: error: 'basic_string<_CharT, _Traits, _Allocator>' is missing
# exception specification 'noexcept(is_nothrow_copy_constructible<allocator_type>::value)'
# TODO: Try again every once in a while (to re-enable these once the bug in libc++ is fixed).
#
#   add_ubuntu_tests(ubuntu_version='16.04', compiler='clang-3.8', stl='libc++', asan=False, ubsan=False)
#


yaml_file = {
  'sudo': 'required',
  'dist': 'trusty',
  'services' : ['docker'],
  'language': 'cpp',
  'branches': {
    'only': ['master'],
  },
  'matrix': {
    'fast_finish': True,
    'include': build_matrix_smoke_test_rows + build_matrix_rows,
  },
}

class CustomDumper(yaml.SafeDumper):
   def ignore_aliases(self, _data):
       return True

print('#')
print('# This file was auto-generated from extras/scripts/travis_yml_generator.py, DO NOT EDIT')
print('#')
print(yaml.dump(yaml_file, default_flow_style=False, Dumper=CustomDumper))