Beispiel #1
0
    def __init__(self, ctx, exe='cl', *,
            pre_flags=[],
            flags=[],
            includes=[],
            macros=[],
            warnings=[],
            debug=None,
            optimize=None,
            debug_flags=['/Zi'],
            optimize_flags=['/Ox']):
        super().__init__(ctx)

        self.exe = fbuild.builders.find_program(ctx, [exe])
        self.pre_flags = pre_flags
        self.flags = flags
        self.includes = includes
        self.macros = macros
        self.warnings = warnings
        self.debug = debug
        self.optimize = optimize
        self.debug_flags = debug_flags
        self.optimize_flags = optimize_flags

        if not self.check_flags(flags):
            raise fbuild.ConfigFailed('%s failed to compile an exe' % self)

        if debug_flags and not self.check_flags(debug_flags):
            raise fbuild.ConfigFailed('%s failed to compile an exe' % self)

        if optimize_flags and not self.check_flags(optimize_flags):
            raise fbuild.ConfigFailed('%s failed to compile an exe' % self)
Beispiel #2
0
    def __init__(self,
                 ctx,
                 exe,
                 src_suffix,
                 *,
                 classpaths=[],
                 sourcepaths=[],
                 debug=False,
                 debug_flags=['-g'],
                 target=None,
                 flags=[]):
        super().__init__(ctx)

        self.exe = fbuild.builders.find_program(ctx, [exe])
        self.src_suffix = src_suffix
        self.classpaths = classpaths
        self.sourcepaths = sourcepaths
        self.debug = debug
        self.debug_flags = debug_flags
        self.target = target
        self.flags = flags

        if not self.check_flags([]):
            raise fbuild.ConfigFailed('%s failed to compile an exe' % self)

        if debug_flags and not self.check_flags(debug_flags):
            raise fbuild.ConfigFailed('%s failed to compile an exe' % self)
Beispiel #3
0
    def __init__(self, ctx, exe, *,
            pre_flags=(),
            flags=(),
            includes=(),
            macros=(),
            warnings=(),
            libpaths=(),
            libs=(),
            external_libs=(),
            debug=None,
            profile=None,
            optimize=None,
            debug_flags=('-g',),
            profile_flags=('-pg',),
            optimize_flags=('-O2',),
            arch=None,
            machine_flags=(),
            requires_version=None,
            requires_at_least_version=None,
            requires_at_most_version=None):
        super().__init__(ctx)

        self.exe = exe
        self.pre_flags = tuple(pre_flags)
        self.flags = tuple(flags)
        self.includes = tuple(includes)
        self.macros = tuple(macros)
        self.warnings = tuple(warnings)
        self.libpaths = tuple(libpaths)
        self.libs = tuple(libs)
        self.external_libs = tuple(external_libs)
        self.debug = debug
        self.profile = profile
        self.optimize = optimize
        self.debug_flags = tuple(debug_flags)
        self.profile_flags = tuple(profile_flags)
        self.optimize_flags = tuple(optimize_flags)
        self.arch = arch
        self.machine_flags = tuple(machine_flags)

        if not self.check_flags(flags):
            raise fbuild.ConfigFailed('%s failed to compile an exe' % self)

        if debug and debug_flags and not self.check_flags(debug_flags):
            raise fbuild.ConfigFailed('%s failed to compile an exe' % self)

        if profile and profile_flags and not self.check_flags(profile_flags):
            raise fbuild.ConfigFailed('%s failed to compile an exe' % self)

        if optimize and optimize_flags and not self.check_flags(optimize_flags):
            raise fbuild.ConfigFailed('%s failed to compile an exe' % self)

        # Make sure we've got a valid version.
        fbuild.builders.check_version(ctx, self, self.version,
            requires_version=requires_version,
            requires_at_least_version=requires_at_least_version,
            requires_at_most_version=requires_at_most_version)
Beispiel #4
0
def check_version(ctx, builder, version_function, *,
        requires_version=None,
        requires_at_least_version=None,
        requires_at_most_version=None):
    """Helper function to simplify checking the version of a builder."""
    if any(v is not None for v in (
            requires_version,
            requires_at_least_version,
            requires_at_most_version)):
        ctx.logger.check('checking %s version' % builder)

        version_str = version_function()

        # Convert the version into a tuple
        version = []
        for i in version_str.split('.'):
            try:
                version.append(int(i))
            except ValueError:
                # The subversion isn't a number, so just convert it to a
                # string.
                version.append(i)
        version = tuple(version)

        if requires_version is not None and requires_version != version:
            msg = 'version %s required; found %s' % (
                '.'.join(str(i) for i in requires_version), version_str)

            ctx.logger.failed(msg)
            raise fbuild.ConfigFailed(msg)

        if requires_at_least_version is not None and \
                requires_at_least_version > version:
            msg = 'at least version %s required; found %s' % (
                '.'.join(str(i) for i in requires_at_least_version),
                version_str)

            ctx.logger.failed(msg)
            raise fbuild.ConfigFailed(msg)

        if requires_at_most_version is not None and \
                requires_at_most_version < version:
            msg = 'at most version %s required; found %s' % (
                '.'.join(str(i) for i in requires_at_most_version),
                version_str)

            ctx.logger.failed(msg)
            raise fbuild.ConfigFailed(msg)

        ctx.logger.passed(version_str)
Beispiel #5
0
def copy_dll(ctx, fluid):
    dll = fluid.replaceext('.dll')
    if not dll.exists():
        url = 'https://github.com/midifi/midifi/blob/master/README.md#windows-1'
        raise fbuild.ConfigFailed('cannot find %s\nsee %s for more info' % (dll,
                                                                            url))
    return copy_dll2(ctx, dll)
Beispiel #6
0
def _guess_builder(name,
                   functions,
                   ctx,
                   *args,
                   platform=None,
                   platform_options=[],
                   **kwargs):
    if platform is None:
        platform = fbuild.builders.platform.guess_platform(ctx, platform)

    for subplatform, function in functions:
        if subplatform <= platform:
            new_kwargs = kwargs.copy()

            for p, kw in platform_options:
                if p <= subplatform:
                    new_kwargs.update(kw)

            # Try to use this compiler. If it doesn't work, skip this compiler
            # and try another one.
            try:
                return fbuild.functools.call(function, ctx, *args,
                                             **new_kwargs)
            except fbuild.ConfigFailed:
                pass

    raise fbuild.ConfigFailed('cannot find a %s builder for %s' %
                              (name, platform))
Beispiel #7
0
    def __init__(self, ctx, exe, *, flags=[]):
        super().__init__(ctx)

        self.exe = fbuild.builders.find_program(ctx, [exe if exe else 'ghc'])
        self.flags = flags

        if not self.check_flags(flags):
            raise fbuild.ConfigFailed('%s failed to compile an exe' % self)
Beispiel #8
0
    def __init__(self, ctx, cc, flags, *, suffix):
        super().__init__(ctx)

        self.cc = cc
        self.flags = tuple(flags)
        self.suffix = suffix

        if flags and not cc.check_flags(flags):
            raise fbuild.ConfigFailed('%s does not support %s flags' %
                                      (cc, flags))
Beispiel #9
0
    def __init__(self, ctx, cl, flags, *, suffix):
        super().__init__(ctx)

        self.cl = cl
        self.flags = flags
        self.suffix = suffix

        if flags and not cl.check_flags(flags):
            raise fbuild.ConfigFailed('%s does not support %s flags' %
                (cl, flags))
Beispiel #10
0
    def __init__(self, ctx, exe, *, includes=[], debug=False, flags=[]):
        super().__init__(ctx)

        # we split exe in case extra arguments were specified in the name
        self.exe = fbuild.builders.find_program(ctx, [exe])
        self.includes = includes
        self.debug = debug
        self.flags = flags

        if not self.check_flags([]):
            raise fbuild.ConfigFailed('%s failed to compile an exe' % self)
Beispiel #11
0
    def __init__(self, ctx, exe, *args,
            debug_flags=['-g:vars'],
            optimize=False,
            optimize_flags=['-optimise'],
            **kwargs):
        self.optimize = optimize
        self.optimize_flags = optimize_flags

        super().__init__(ctx, exe, '.scala', debug_flags=debug_flags, *args, **kwargs)

        if optimize_flags and not self.check_flags(optimize_flags):
            raise fbuild.ConfigFailed('%s failed to compile an exe' % self)
Beispiel #12
0
def check_fluid(linker):
    fluidsynth = Path(linker.prefix + 'fluidsynth' + linker.suffix)
    fluidsynth = fluidsynth.addroot(Path('fluidsynth') / 'fluidsynth' / 'src')

    message = textwrap.dedent('''
    You need to build Fluidsynth separately first!
    Try runnung 'cd fluidsynth/fluidsynth; cmake'.
    (See http://sourceforge.net/p/fluidsynth/wiki/BuildingWithCMake/ for info.)
    '''.rstrip().lstrip('\n')).replace('\n', ' ', 1)

    if not fluidsynth.exists():
        raise fbuild.ConfigFailed(message)

    return fluidsynth
Beispiel #13
0
    def __init__(self, *args, flags=(), cross_compiler=False, **kwargs):
        self.flags = tuple(flags)

        # If we're a cross compiler, don't try to execute tests as they'll
        # probably fail.
        self.cross_compiler = cross_compiler

        super().__init__(*args, **kwargs)

        # ----------------------------------------------------------------------
        # Check the builder to make sure it works.

        self.ctx.logger.check('checking if %s can make objects' % self)
        try:
            with self.tempfile_compile('int main() { return 0; }'):
                self.ctx.logger.passed()
        except fbuild.ExecutionError as e:
            raise fbuild.ConfigFailed('compiler failed: %s' % e)

        self.ctx.logger.check('checking if %s can make libraries' % self)
        try:
            with self.tempfile_link_lib('int foo() { return 5; }'):
                self.ctx.logger.passed()
        except fbuild.ExecutionError as e:
            raise fbuild.ConfigFailed('lib linker failed: %s' % e)

        self.ctx.logger.check('checking if %s can make exes' % self)
        try:
            if not self.cross_compiler:
                self.tempfile_run('int main() { return 0; }')
            else:
                with self.tempfile_link_exe('int main() { return 0; }'):
                    pass
        except fbuild.ExecutionError as e:
            raise fbuild.ConfigFailed('exe linker failed: %s' % e)
        else:
            self.ctx.logger.passed()
Beispiel #14
0
    def platform_extra(self):
        get_toolchain = '''
        include 'std/felix/toolchain_clang_config';
        include 'std/felix/toolchain_interface';
        include 'std/felix/flx_pkgconfig';

        config_dirs := #Config::std_config.FLX_CONFIG_DIRS;
        pkgconfig := FlxPkgConfig::FlxPkgConfigQuery config_dirs;
        toolchain := pkgconfig.getpkgfield1 ('toolchain', 'toolchain');

        for arg in #System::args perform
            if arg.startswith('--toolchain=') perform
                toolchain = arg.[12 to];

        println toolchain;
        '''

        with self.tempfile(get_toolchain) as f:
            self.ctx.logger.check('detecting toolchain used by flx '\
                                  '(this may take a while!)')
            try:
                toolchain = self.uncached_run(f, quieter=1)[0]
            except:
                self.ctx.logger.failed()
                raise fbuild.ConfigFailed('could not detect flx toolchain')
            else:
                toolchain = toolchain.decode('utf-8').strip().split('\n')[-1]
                self.ctx.logger.passed('ok %s' % toolchain)

        if 'msvc' in toolchain:
            return {'windows'}
        elif 'gcc' in toolchain:
            return {'gcc'}
        elif 'clang' in toolchain:
            return {'clang'}
        else:
            raise fbuild.ConfigFailed('unknown toolchain %s' % toolchain)
Beispiel #15
0
def find_font(ctx) -> fbuild.db.DST:
    ctx.logger.check('locating arial font')
    font = None

    if sys.platform == 'win32':
        font = Path(os.environ['SYSTEMROOT']) / 'Fonts' / 'Arial.ttf'
        if not font.exists():
            font = None
    elif sys.platform.startswith('linux'):
        # Check /etc/fonts/fonts.conf.
        font_dirs = []
        fonts = Path('/etc/fonts/fonts.conf')
        if not fonts.exists():
            ctx.logger.failed()
            raise fbuild.ConfigFailed('cannot locate fonts.conf')

        tree = etree.parse(str(fonts))
        for element in tree.findall('dir'):
            path = Path(element.text)
            if element.attrib.get('prefix') == 'xdg' and \
                'XDG_DATA_HOME' in os.environ:
                path = path.addroot(os.environ['XDG_DATA_HOME'])

            try:
                font = Path(next(path.find('Arial.ttf', include_dirs=False)))
            except StopIteration:
                pass
            else:
                break

    if font is None:
        ctx.logger.failed()
        raise fbuild.ConfigFailed('cannot locate arial font')
    else:
        ctx.logger.passed('ok %s' % font)
        return font
Beispiel #16
0
 def _test(self):
     self.ctx.logger.check('checking flx')
     failed = False
     with self.tempfile("println 'Hello, world!';") as f:
         try:
             output = self.uncached_run(f, quieter=1)
         except:
             self.ctx.logger.failed()
             raise
         else:
             if output[1] or not output[0].rstrip().endswith(b'Hello, world!'):
                 self.ctx.logger.failed()
                 raise fbuild.ConfigFailed(
                     'flx test program did not give correct output')
             else:
                 self.ctx.logger.passed()
Beispiel #17
0
    def __init__(self, ctx, cc, flags, *, suffix):
        super().__init__(ctx)

        self.cc = cc
        self.suffix = suffix
        flags = tuple(flags)
        noaggro = ("-fno-aggressive-loop-optimizations", )
        if cc.check_flags(noaggro):
            print(
                "FLAG -fno-aggressive-loop-optimizations supported and applied"
            )
            flags = flags + noaggro
        else:
            print("FLAG -fno-aggressive-loop-optimizations NOT supported")
        if flags and not cc.check_flags(flags):
            raise fbuild.ConfigFailed('%s does not support %s flags' %
                                      (cc, flags))
        self.flags = tuple(flags)
Beispiel #18
0
    def conversion_map(self, *args, **kwargs):
        type_pairs = [(name1, name2) for name1, type1 in self.int_types()
                      if type1 is not None
                      for name2, type2 in self.int_types()
                      if type2 is not None]

        lines = []
        for t1, t2 in type_pairs:
            lines.append('printf("%%d %%d\\n", '
                         '(int)sizeof((%(t1)s)0 + (%(t2)s)0), '
                         '(%(t1)s)~3 + (%(t2)s)1 < (%(t1)s)0 + (%(t2)s)0);' % {
                             't1': t1,
                             't2': t2
                         })

        code = '''
        #include <stdio.h>
        int main(int argc, char** argv) {
            %s
            return 0;
        }
        ''' % '\n'.join(lines)

        try:
            stdout, stderr = self.builder.tempfile_run(code, *args, **kwargs)
        except fbuild.ExecutionError:
            raise fbuild.ConfigFailed('failed to detect type conversions')

        lookup = {(t.size, t.signed): self.structural_alias(t)
                  for n, t in self.int_types() if t is not None}

        d = {}
        for line, (t1,
                   t2) in zip(stdout.decode('utf-8').split('\n'), type_pairs):
            size, sign = line.split()
            d[(t1, t2)] = lookup[(int(size), int(sign) == 1)]

        return d
Beispiel #19
0
    def __call__(self, ctx, static={}, shared={}, platform=None, platform_options={},
                 exe=None, **kwargs):
        """Try to find a set of builders. A static builder will be located using the
        arguments in *static* combined with *kwargs*, and the shared builder will be
        located using *shared* arguments combined with *kwargs*. Each
        """
        if platform is None:
            platform = fbuild.builders.platform.guess_platform(ctx, platform)

        if exe is not None:
            tp = identify_compiler(ctx, exe)
            if tp is None:
                raise fbuild.ConfigFailed('cannot identify exe given for %s' % name)
            # Grab only the compiler type pertaining to this guess call.
            platform |= tp & self.compilers
        else:
            # We're open to using all compilers.
            platform |= self.compilers

        builders = {'static': static, 'shared': shared}

        for subplatform, static_function, shared_function in self.functions:
            if subplatform <= platform:
                # We need to go through each requested builder and check the compiler.
                result = fbuild.record.Record()
                for builder, builder_args in builders.items():
                    if builder_args is None:
                        result[builder] = None
                        continue

                    if builder == 'static':
                        function = static_function
                    else:
                        function = shared_function

                    # Create a new arg dict, merging both kwargs and the builder-specific args.
                    new_kwargs = copy.deepcopy(kwargs)
                    new_kwargs.update(copy.deepcopy(builder_args))

                    # Make sure that only the current compiler used for parsing
                    # platform_options.
                    simplified_platform = (platform - self.compilers) | subplatform
                    # Now parse the options.
                    fbuild.builders.platform.parse_platform_options(ctx,
                        simplified_platform, platform_options, new_kwargs)

                    # Try to use this compiler. If it doesn't work, then give up on this
                    # subplatform and move on.
                    try:
                        result[builder] = fbuild.functools.call(function, ctx, exe,
                                                                platform=platform,
                                                                **new_kwargs)
                    except fbuild.ConfigFailed:
                        break

                # If both builders are present in some form, then that means this
                # function has succeeded. Time to return the result record.
                if len(result) == 2:
                    return result

        # If we made it all the way here, then everything failed.
        raise fbuild.ConfigFailed('cannot find a builder for %s' % platform)
Beispiel #20
0
    def __init__(self, *args, flags=(), cross_compiler=False, **kwargs):
        self.flags = tuple(flags)

        # If we're a cross compiler, don't try to execute tests as they'll
        # probably fail.
        self.cross_compiler = cross_compiler

        super().__init__(*args, **kwargs)

        # ----------------------------------------------------------------------
        # Check the builder to make sure it works.

        self.ctx.logger.check('checking if %s can make objects' % self)
        try:
            with self.tempfile_compile('int main() { return 0; }'):
                self.ctx.logger.passed()
        except fbuild.ExecutionError as e:
            raise fbuild.ConfigFailed('compiler failed: %s' % e)

        self.ctx.logger.check('checking if %s can make libraries' % self)
        try:
            with self.tempfile_link_lib('int foo() { return 5; }'):
                self.ctx.logger.passed()
        except fbuild.ExecutionError as e:
            raise fbuild.ConfigFailed('lib linker failed: %s' % e)

        self.ctx.logger.check('checking if %s can make exes' % self)
        try:
            if not self.cross_compiler:
                self.tempfile_run('int main() { return 0; }')
            else:
                with self.tempfile_link_exe('int main() { return 0; }'):
                    pass
        except fbuild.ExecutionError as e:
            raise fbuild.ConfigFailed('exe linker failed: %s' % e)
        else:
            self.ctx.logger.passed()

        self.ctx.logger.check('checking if %s can link lib to exe' % self)
        with fbuild.temp.tempdir() as dirname:
            src_lib = dirname / 'templib' + self.src_suffix
            with open(src_lib, 'w') as f:
                print('''
                    #ifdef __cplusplus
                    extern "C" {
                    #endif
                    #if defined _WIN32 || defined __CYGWIN__
                    __declspec(dllexport)
                    #elif defined __GNUC__
                    __attribute__ ((visibility ("default")))
                    #endif
                    int foo() { return 5; }
                    #ifdef __cplusplus
                    }
                    #endif
                ''', file=f)

            src_exe = dirname / 'tempexe' + self.src_suffix
            with open(src_exe, 'w') as f:
                print('''
                    #include <stdio.h>
                    #ifdef __cplusplus
                    extern "C" {
                    #endif
                    extern int foo();
                    #ifdef __cplusplus
                    }
                    #endif
                    int main(int argc, char** argv) {
                        printf("%d", foo());
                        return 0;
                    }''', file=f)

            obj = self.uncached_compile(src_lib, quieter=1)
            lib = self.uncached_link_lib(dirname / 'templib', [obj],
                    quieter=1)
            obj = self.uncached_compile(src_exe, quieter=1)
            exe = self.uncached_link_exe(dirname / 'tempexe', [obj],
                    libs=[lib],
                    quieter=1)

            if self.cross_compiler:
                self.ctx.logger.passed()
            else:
                try:
                    stdout, stderr = self.run([exe], quieter=1)
                except fbuild.ExecutionError:
                    raise fbuild.ConfigFailed('failed to link lib to exe')
                else:
                    if stdout != b'5':
                        raise fbuild.ConfigFailed('failed to link lib to exe')
                    self.ctx.logger.passed()
Beispiel #21
0
    def __init__(self, ctx, exe, *,
            platform=None,
            obj_suffix,
            lib_suffix,
            includes=(),
            libs=(),
            cc=None,
            c_libs=(),
            pre_flags=(),
            flags=(),
            debug=False,
            optimize=False,
            debug_flags=('-g',),
            optimize_flags=(),
            ocamldep=None,
            make_ocamldep=Ocamldep,
            requires_version=None,
            requires_at_least_version=None,
            requires_at_most_version=None):
        super().__init__(ctx, src_suffix='.ml')

        self.ocamldep = ocamldep or make_ocamldep(ctx)
        self.exe = exe
        self.obj_suffix = obj_suffix
        self.lib_suffix = lib_suffix
        self.exe_suffix = fbuild.builders.platform.exe_suffix(ctx, platform)
        self.includes = tuple(includes)
        self.libs = tuple(libs)
        self.cc = cc
        self.c_libs = tuple(c_libs)
        self.pre_flags = tuple(pre_flags)
        self.flags = tuple(flags)
        self.debug = debug
        self.optimize = optimize
        self.debug_flags = tuple(debug_flags)
        self.optimize_flags = tuple(optimize_flags)

        # Make sure we've got a valid version.
        fbuild.builders.check_version(ctx, self, self.version,
            requires_version=requires_version,
            requires_at_least_version=requires_at_least_version,
            requires_at_most_version=requires_at_most_version)

        # ----------------------------------------------------------------------
        # Check the builder to make sure it works.

        self.ctx.logger.check('checking if %s can make objects' % str(self))
        if self.try_compile():
            self.ctx.logger.passed()
        else:
            raise fbuild.ConfigFailed('%s compiler failed' % str(self))

        self.ctx.logger.check('checking if %s can make libraries' % str(self))
        if self.try_link_lib():
            self.ctx.logger.passed()
        else:
            raise fbuild.ConfigFailed('%s lib linker failed' % str(self))

        self.ctx.logger.check('checking if %s can make exes' % str(self))
        if self.try_link_exe():
            self.ctx.logger.passed()
        else:
            raise fbuild.ConfigFailed('%s exe linker failed' % str(self))

        self.ctx.logger.check('checking if %s can link lib to exe' % str(self))
        with fbuild.temp.tempdir() as parent:
            src_lib = parent / 'lib.ml'
            with open(src_lib, 'w') as f:
                print('let x = 5;;', file=f)

            src_exe = parent / 'exe.ml'
            with open(src_exe, 'w') as f:
                print('print_int Lib.x;;', file=f)

            obj = self.uncached_compile(src_lib, quieter=1)
            lib = self.uncached_link_lib(parent / 'lib', [obj], quieter=1)

            obj = self.uncached_compile(src_exe, quieter=1)
            exe = self.uncached_link_exe(parent / 'exe', [obj], libs=[lib],
                quieter=1)

            try:
                stdout, stderr = self.ctx.execute([exe], quieter=1)
            except fbuild.ExecutionError:
                raise fbuild.ConfigFailed('failed to link %s lib to exe' %
                    str(self))
            else:
                if stdout != b'5':
                   raise fbuild.ConfigFailed('failed to link %s lib to exe' %
                        str(self))
                self.ctx.logger.passed()
Beispiel #22
0
def _guess_builder(name,
                   compilers,
                   functions,
                   ctx,
                   *args,
                   platform=None,
                   platform_extra=set(),
                   platform_options=[],
                   exe=None,
                   **kwargs):
    if platform is None:
        platform = fbuild.builders.platform.guess_platform(ctx, platform)
    if not platform_extra & compilers:
        if exe is not None:
            tp = identify_compiler(ctx, exe)
            if tp is None:
                raise fbuild.ConfigFailed('cannot identify exe given for ' +\
                                          name)
            platform_extra |= tp
        else:
            platform_extra |= compilers
    platform |= platform_extra

    for subplatform, function in functions:
        # XXX: this is slightly a hack to make sure:
        # a) Clang can actually be detected
        # b) Any compilers explicitly listed in platform_extra will have #1
        #  priority
        if subplatform - (compilers & platform_extra) <= platform:
            new_kwargs = copy.deepcopy(kwargs)

            for p, kw in platform_options:
                if p <= subplatform:
                    for k, v in kw.items():
                        if k[-1] in '+-':
                            func = k[-1]
                            k = k[:-1]
                            try:
                                curval = new_kwargs[k]
                            except:
                                if isinstance(v, str):
                                    curval = ''
                                elif isinstance(v, list):
                                    curval = []
                                elif isinstance(v, tuple):
                                    curval = ()
                            if func == '+':
                                curval += v
                            elif func == '-':
                                lst = list(curval)
                                for x in v:
                                    lst.pop(lst.index(x))
                                if isinstance(curval, str):
                                    curval = ''.join(lst)
                                else:
                                    curval = type(curval)(lst)
                            new_kwargs[k] = curval
                        else:
                            new_kwargs[k] = v

            # Try to use this compiler. If it doesn't work, skip this compiler
            # and try another one.
            try:
                return fbuild.functools.call(function, ctx, exe, *args,
                                             **new_kwargs)
            except fbuild.ConfigFailed:
                pass

    raise fbuild.ConfigFailed('cannot find a %s builder for %s' %
                              (name, platform))