123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328 |
- #!/usr/bin/env python3
- from itertools import combinations, chain
- from enum import Enum, auto
- LINUX = 'linux'
- OSX = 'osx'
- WINDOWS = 'windows'
- FREEBSD = 'freebsd'
- AMD64 = 'amd64'
- ARM64 = 'arm64'
- PPC64LE = 'ppc64le'
- TRAVIS_TEMPLATE = """\
- # This config file is generated by ./scripts/gen_travis.py.
- # Do not edit by hand.
- # We use 'minimal', because 'generic' makes Windows VMs hang at startup. Also
- # the software provided by 'generic' is simply not needed for our tests.
- # Differences are explained here:
- # https://docs.travis-ci.com/user/languages/minimal-and-generic/
- language: minimal
- dist: focal
- jobs:
- include:
- {jobs}
- before_install:
- - |-
- if test -f "./scripts/$TRAVIS_OS_NAME/before_install.sh"; then
- source ./scripts/$TRAVIS_OS_NAME/before_install.sh
- fi
- before_script:
- - |-
- if test -f "./scripts/$TRAVIS_OS_NAME/before_script.sh"; then
- source ./scripts/$TRAVIS_OS_NAME/before_script.sh
- else
- scripts/gen_travis.py > travis_script && diff .travis.yml travis_script
- autoconf
- # If COMPILER_FLAGS are not empty, add them to CC and CXX
- ./configure ${{COMPILER_FLAGS:+ CC="$CC $COMPILER_FLAGS" \
- CXX="$CXX $COMPILER_FLAGS"}} $CONFIGURE_FLAGS
- make -j3
- make -j3 tests
- fi
- script:
- - |-
- if test -f "./scripts/$TRAVIS_OS_NAME/script.sh"; then
- source ./scripts/$TRAVIS_OS_NAME/script.sh
- else
- make check
- fi
- """
- class Option(object):
- class Type:
- COMPILER = auto()
- COMPILER_FLAG = auto()
- CONFIGURE_FLAG = auto()
- MALLOC_CONF = auto()
- FEATURE = auto()
- def __init__(self, type, value):
- self.type = type
- self.value = value
- @staticmethod
- def as_compiler(value):
- return Option(Option.Type.COMPILER, value)
- @staticmethod
- def as_compiler_flag(value):
- return Option(Option.Type.COMPILER_FLAG, value)
- @staticmethod
- def as_configure_flag(value):
- return Option(Option.Type.CONFIGURE_FLAG, value)
- @staticmethod
- def as_malloc_conf(value):
- return Option(Option.Type.MALLOC_CONF, value)
- @staticmethod
- def as_feature(value):
- return Option(Option.Type.FEATURE, value)
- def __eq__(self, obj):
- return (isinstance(obj, Option) and obj.type == self.type
- and obj.value == self.value)
- # The 'default' configuration is gcc, on linux, with no compiler or configure
- # flags. We also test with clang, -m32, --enable-debug, --enable-prof,
- # --disable-stats, and --with-malloc-conf=tcache:false. To avoid abusing
- # travis though, we don't test all 2**7 = 128 possible combinations of these;
- # instead, we only test combinations of up to 2 'unusual' settings, under the
- # hope that bugs involving interactions of such settings are rare.
- MAX_UNUSUAL_OPTIONS = 2
- GCC = Option.as_compiler('CC=gcc CXX=g++')
- CLANG = Option.as_compiler('CC=clang CXX=clang++')
- CL = Option.as_compiler('CC=cl.exe CXX=cl.exe')
- compilers_unusual = [CLANG,]
- CROSS_COMPILE_32BIT = Option.as_feature('CROSS_COMPILE_32BIT')
- feature_unusuals = [CROSS_COMPILE_32BIT]
- configure_flag_unusuals = [Option.as_configure_flag(opt) for opt in (
- '--enable-debug',
- '--enable-prof',
- '--disable-stats',
- '--disable-libdl',
- '--enable-opt-safety-checks',
- '--with-lg-page=16',
- )]
- malloc_conf_unusuals = [Option.as_malloc_conf(opt) for opt in (
- 'tcache:false',
- 'dss:primary',
- 'percpu_arena:percpu',
- 'background_thread:true',
- )]
- all_unusuals = (compilers_unusual + feature_unusuals
- + configure_flag_unusuals + malloc_conf_unusuals)
- def get_extra_cflags(os, compiler):
- if os == FREEBSD:
- return []
- if os == WINDOWS:
- # For non-CL compilers under Windows (for now it's only MinGW-GCC),
- # -fcommon needs to be specified to correctly handle multiple
- # 'malloc_conf' symbols and such, which are declared weak under Linux.
- # Weak symbols don't work with MinGW-GCC.
- if compiler != CL.value:
- return ['-fcommon']
- else:
- return []
- # We get some spurious errors when -Warray-bounds is enabled.
- extra_cflags = ['-Werror', '-Wno-array-bounds']
- if compiler == CLANG.value or os == OSX:
- extra_cflags += [
- '-Wno-unknown-warning-option',
- '-Wno-ignored-attributes'
- ]
- if os == OSX:
- extra_cflags += [
- '-Wno-deprecated-declarations',
- ]
- return extra_cflags
- # Formats a job from a combination of flags
- def format_job(os, arch, combination):
- compilers = [x.value for x in combination if x.type == Option.Type.COMPILER]
- assert(len(compilers) <= 1)
- compiler_flags = [x.value for x in combination if x.type == Option.Type.COMPILER_FLAG]
- configure_flags = [x.value for x in combination if x.type == Option.Type.CONFIGURE_FLAG]
- malloc_conf = [x.value for x in combination if x.type == Option.Type.MALLOC_CONF]
- features = [x.value for x in combination if x.type == Option.Type.FEATURE]
- if len(malloc_conf) > 0:
- configure_flags.append('--with-malloc-conf=' + ','.join(malloc_conf))
- if not compilers:
- compiler = GCC.value
- else:
- compiler = compilers[0]
- extra_environment_vars = ''
- cross_compile = CROSS_COMPILE_32BIT.value in features
- if os == LINUX and cross_compile:
- compiler_flags.append('-m32')
- features_str = ' '.join([' {}=yes'.format(feature) for feature in features])
- stringify = lambda arr, name: ' {}="{}"'.format(name, ' '.join(arr)) if arr else ''
- env_string = '{}{}{}{}{}{}'.format(
- compiler,
- features_str,
- stringify(compiler_flags, 'COMPILER_FLAGS'),
- stringify(configure_flags, 'CONFIGURE_FLAGS'),
- stringify(get_extra_cflags(os, compiler), 'EXTRA_CFLAGS'),
- extra_environment_vars)
- job = ' - os: {}\n'.format(os)
- job += ' arch: {}\n'.format(arch)
- job += ' env: {}'.format(env_string)
- return job
- def generate_unusual_combinations(unusuals, max_unusual_opts):
- """
- Generates different combinations of non-standard compilers, compiler flags,
- configure flags and malloc_conf settings.
- @param max_unusual_opts: Limit of unusual options per combination.
- """
- return chain.from_iterable(
- [combinations(unusuals, i) for i in range(max_unusual_opts + 1)])
- def included(combination, exclude):
- """
- Checks if the combination of options should be included in the Travis
- testing matrix.
- @param exclude: A list of options to be avoided.
- """
- return not any(excluded in combination for excluded in exclude)
- def generate_jobs(os, arch, exclude, max_unusual_opts, unusuals=all_unusuals):
- jobs = []
- for combination in generate_unusual_combinations(unusuals, max_unusual_opts):
- if included(combination, exclude):
- jobs.append(format_job(os, arch, combination))
- return '\n'.join(jobs)
- def generate_linux(arch):
- os = LINUX
- # Only generate 2 unusual options for AMD64 to reduce matrix size
- max_unusual_opts = MAX_UNUSUAL_OPTIONS if arch == AMD64 else 1
- exclude = []
- if arch == PPC64LE:
- # Avoid 32 bit builds and clang on PowerPC
- exclude = (CROSS_COMPILE_32BIT, CLANG,)
- return generate_jobs(os, arch, exclude, max_unusual_opts)
- def generate_macos(arch):
- os = OSX
- max_unusual_opts = 1
- exclude = ([Option.as_malloc_conf(opt) for opt in (
- 'dss:primary',
- 'percpu_arena:percpu',
- 'background_thread:true')] +
- [Option.as_configure_flag('--enable-prof')] +
- [CLANG,])
- return generate_jobs(os, arch, exclude, max_unusual_opts)
- def generate_windows(arch):
- os = WINDOWS
- max_unusual_opts = 3
- unusuals = (
- Option.as_configure_flag('--enable-debug'),
- CL,
- CROSS_COMPILE_32BIT,
- )
- return generate_jobs(os, arch, (), max_unusual_opts, unusuals)
- def generate_freebsd(arch):
- os = FREEBSD
- max_unusual_opts = 4
- unusuals = (
- Option.as_configure_flag('--enable-debug'),
- Option.as_configure_flag('--enable-prof --enable-prof-libunwind'),
- Option.as_configure_flag('--with-lg-page=16 --with-malloc-conf=tcache:false'),
- CROSS_COMPILE_32BIT,
- )
- return generate_jobs(os, arch, (), max_unusual_opts, unusuals)
- def get_manual_jobs():
- return """\
- # Development build
- - os: linux
- env: CC=gcc CXX=g++ CONFIGURE_FLAGS="--enable-debug \
- --disable-cache-oblivious --enable-stats --enable-log --enable-prof" \
- EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- # --enable-expermental-smallocx:
- - os: linux
- env: CC=gcc CXX=g++ CONFIGURE_FLAGS="--enable-debug \
- --enable-experimental-smallocx --enable-stats --enable-prof" \
- EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- """
- def main():
- jobs = '\n'.join((
- generate_windows(AMD64),
- generate_freebsd(AMD64),
- generate_linux(AMD64),
- generate_linux(PPC64LE),
- generate_macos(AMD64),
- get_manual_jobs(),
- ))
- print(TRAVIS_TEMPLATE.format(jobs=jobs))
- if __name__ == '__main__':
- main()
|