示例#1
0
    def extract_autotools_deps(outlines,
                               srctree,
                               extravalues=None,
                               acfile=None):
        import shlex

        # Find all plugins that want to register handlers
        logger.debug('Loading autotools handlers')
        handlers = []
        for plugin in plugins:
            if hasattr(plugin, 'register_autotools_handlers'):
                plugin.register_autotools_handlers(handlers)

        values = {}
        inherits = []

        # Hardcoded map, we also use a dynamic one based on what's in the sysroot
        progmap = {
            'flex': 'flex-native',
            'bison': 'bison-native',
            'm4': 'm4-native',
            'tar': 'tar-native',
            'ar': 'binutils-native',
            'ranlib': 'binutils-native',
            'ld': 'binutils-native',
            'strip': 'binutils-native',
            'libtool': '',
            'autoconf': '',
            'autoheader': '',
            'automake': '',
            'uname': '',
            'rm': '',
            'cp': '',
            'mv': '',
            'find': '',
            'awk': '',
            'sed': '',
        }
        progclassmap = {
            'gconftool-2': 'gconf',
            'pkg-config': 'pkgconfig',
            'python': 'pythonnative',
            'python3': 'python3native',
            'perl': 'perlnative',
            'makeinfo': 'texinfo',
        }

        pkg_re = re.compile(
            'PKG_CHECK_MODULES\(\s*\[?[a-zA-Z0-9_]*\]?,\s*\[?([^,\]]*)\]?[),].*'
        )
        pkgce_re = re.compile('PKG_CHECK_EXISTS\(\s*\[?([^,\]]*)\]?[),].*')
        lib_re = re.compile('AC_CHECK_LIB\(\s*\[?([^,\]]*)\]?,.*')
        libx_re = re.compile(
            'AX_CHECK_LIBRARY\(\s*\[?[^,\]]*\]?,\s*\[?([^,\]]*)\]?,\s*\[?([a-zA-Z0-9-]*)\]?,.*'
        )
        progs_re = re.compile(
            '_PROGS?\(\s*\[?[a-zA-Z0-9_]*\]?,\s*\[?([^,\]]*)\]?[),].*')
        dep_re = re.compile('([^ ><=]+)( [<>=]+ [^ ><=]+)?')
        ac_init_re = re.compile('AC_INIT\(\s*([^,]+),\s*([^,]+)[,)].*')
        am_init_re = re.compile(
            'AM_INIT_AUTOMAKE\(\s*([^,]+),\s*([^,]+)[,)].*')
        define_re = re.compile('\s*(m4_)?define\(\s*([^,]+),\s*([^,]+)\)')
        version_re = re.compile('([0-9.]+)')

        defines = {}

        def subst_defines(value):
            newvalue = value
            for define, defval in defines.items():
                newvalue = newvalue.replace(define, defval)
            if newvalue != value:
                return subst_defines(newvalue)
            return value

        def process_value(value):
            value = value.replace('[', '').replace(']', '')
            if value.startswith('m4_esyscmd(') or value.startswith(
                    'm4_esyscmd_s('):
                cmd = subst_defines(value[value.index('(') + 1:-1])
                try:
                    if '|' in cmd:
                        cmd = 'set -o pipefail; ' + cmd
                    stdout, _ = bb.process.run(cmd, cwd=srctree, shell=True)
                    ret = stdout.rstrip()
                except bb.process.ExecutionError as e:
                    ret = ''
            elif value.startswith('m4_'):
                return None
            ret = subst_defines(value)
            if ret:
                ret = ret.strip('"\'')
            return ret

        # Since a configure.ac file is essentially a program, this is only ever going to be
        # a hack unfortunately; but it ought to be enough of an approximation
        if acfile:
            srcfiles = [acfile]
        else:
            srcfiles = RecipeHandler.checkfiles(
                srctree, ['acinclude.m4', 'configure.ac', 'configure.in'])

        pcdeps = []
        libdeps = []
        deps = []
        unmapped = []

        RecipeHandler.load_binmap(tinfoil.config_data)

        def process_macro(keyword, value):
            for handler in handlers:
                if handler.process_macro(srctree, keyword, value,
                                         process_value, libdeps, pcdeps, deps,
                                         outlines, inherits, values):
                    return
            logger.debug('Found keyword %s with value "%s"' % (keyword, value))
            if keyword == 'PKG_CHECK_MODULES':
                res = pkg_re.search(value)
                if res:
                    res = dep_re.findall(res.group(1))
                    if res:
                        pcdeps.extend([x[0] for x in res])
                inherits.append('pkgconfig')
            elif keyword == 'PKG_CHECK_EXISTS':
                res = pkgce_re.search(value)
                if res:
                    res = dep_re.findall(res.group(1))
                    if res:
                        pcdeps.extend([x[0] for x in res])
                inherits.append('pkgconfig')
            elif keyword in ('AM_GNU_GETTEXT', 'AM_GLIB_GNU_GETTEXT',
                             'GETTEXT_PACKAGE'):
                inherits.append('gettext')
            elif keyword in ('AC_PROG_INTLTOOL', 'IT_PROG_INTLTOOL'):
                deps.append('intltool-native')
            elif keyword == 'AM_PATH_GLIB_2_0':
                deps.append('glib-2.0')
            elif keyword in ('AC_CHECK_PROG', 'AC_PATH_PROG', 'AX_WITH_PROG'):
                res = progs_re.search(value)
                if res:
                    for prog in shlex.split(res.group(1)):
                        prog = prog.split()[0]
                        for handler in handlers:
                            if handler.process_prog(srctree, keyword, value,
                                                    prog, deps, outlines,
                                                    inherits, values):
                                return
                        progclass = progclassmap.get(prog, None)
                        if progclass:
                            inherits.append(progclass)
                        else:
                            progdep = RecipeHandler.recipebinmap.get(
                                prog, None)
                            if not progdep:
                                progdep = progmap.get(prog, None)
                            if progdep:
                                deps.append(progdep)
                            elif progdep is None:
                                if not prog.startswith('$'):
                                    unmapped.append(prog)
            elif keyword == 'AC_CHECK_LIB':
                res = lib_re.search(value)
                if res:
                    lib = res.group(1)
                    if not lib.startswith('$'):
                        libdeps.append(lib)
            elif keyword == 'AX_CHECK_LIBRARY':
                res = libx_re.search(value)
                if res:
                    lib = res.group(2)
                    if not lib.startswith('$'):
                        header = res.group(1)
                        libdeps.append((lib, header))
            elif keyword == 'AC_PATH_X':
                deps.append('libx11')
            elif keyword in ('AX_BOOST', 'BOOST_REQUIRE'):
                deps.append('boost')
            elif keyword in ('AC_PROG_LEX', 'AM_PROG_LEX', 'AX_PROG_FLEX'):
                deps.append('flex-native')
            elif keyword in ('AC_PROG_YACC', 'AX_PROG_BISON'):
                deps.append('bison-native')
            elif keyword == 'AX_CHECK_ZLIB':
                deps.append('zlib')
            elif keyword in ('AX_CHECK_OPENSSL', 'AX_LIB_CRYPTO'):
                deps.append('openssl')
            elif keyword == 'AX_LIB_CURL':
                deps.append('curl')
            elif keyword == 'AX_LIB_BEECRYPT':
                deps.append('beecrypt')
            elif keyword == 'AX_LIB_EXPAT':
                deps.append('expat')
            elif keyword == 'AX_LIB_GCRYPT':
                deps.append('libgcrypt')
            elif keyword == 'AX_LIB_NETTLE':
                deps.append('nettle')
            elif keyword == 'AX_LIB_READLINE':
                deps.append('readline')
            elif keyword == 'AX_LIB_SQLITE3':
                deps.append('sqlite3')
            elif keyword == 'AX_LIB_TAGLIB':
                deps.append('taglib')
            elif keyword in ['AX_PKG_SWIG', 'AC_PROG_SWIG']:
                deps.append('swig-native')
            elif keyword == 'AX_PROG_XSLTPROC':
                deps.append('libxslt-native')
            elif keyword in [
                    'AC_PYTHON_DEVEL', 'AX_PYTHON_DEVEL', 'AM_PATH_PYTHON'
            ]:
                pythonclass = 'pythonnative'
                res = version_re.search(value)
                if res:
                    if res.group(1).startswith('3'):
                        pythonclass = 'python3native'
                # Avoid replacing python3native with pythonnative
                if not pythonclass in inherits and not 'python3native' in inherits:
                    if 'pythonnative' in inherits:
                        inherits.remove('pythonnative')
                    inherits.append(pythonclass)
            elif keyword == 'AX_WITH_CURSES':
                deps.append('ncurses')
            elif keyword == 'AX_PATH_BDB':
                deps.append('db')
            elif keyword == 'AX_PATH_LIB_PCRE':
                deps.append('libpcre')
            elif keyword == 'AC_INIT':
                if extravalues is not None:
                    res = ac_init_re.match(value)
                    if res:
                        extravalues['PN'] = process_value(res.group(1))
                        pv = process_value(res.group(2))
                        if validate_pv(pv):
                            extravalues['PV'] = pv
            elif keyword == 'AM_INIT_AUTOMAKE':
                if extravalues is not None:
                    if 'PN' not in extravalues:
                        res = am_init_re.match(value)
                        if res:
                            if res.group(1) != 'AC_PACKAGE_NAME':
                                extravalues['PN'] = process_value(res.group(1))
                            pv = process_value(res.group(2))
                            if validate_pv(pv):
                                extravalues['PV'] = pv
            elif keyword == 'define(':
                res = define_re.match(value)
                if res:
                    key = res.group(2).strip('[]')
                    value = process_value(res.group(3))
                    if value is not None:
                        defines[key] = value

        keywords = [
            'PKG_CHECK_MODULES',
            'PKG_CHECK_EXISTS',
            'AM_GNU_GETTEXT',
            'AM_GLIB_GNU_GETTEXT',
            'GETTEXT_PACKAGE',
            'AC_PROG_INTLTOOL',
            'IT_PROG_INTLTOOL',
            'AM_PATH_GLIB_2_0',
            'AC_CHECK_PROG',
            'AC_PATH_PROG',
            'AX_WITH_PROG',
            'AC_CHECK_LIB',
            'AX_CHECK_LIBRARY',
            'AC_PATH_X',
            'AX_BOOST',
            'BOOST_REQUIRE',
            'AC_PROG_LEX',
            'AM_PROG_LEX',
            'AX_PROG_FLEX',
            'AC_PROG_YACC',
            'AX_PROG_BISON',
            'AX_CHECK_ZLIB',
            'AX_CHECK_OPENSSL',
            'AX_LIB_CRYPTO',
            'AX_LIB_CURL',
            'AX_LIB_BEECRYPT',
            'AX_LIB_EXPAT',
            'AX_LIB_GCRYPT',
            'AX_LIB_NETTLE',
            'AX_LIB_READLINE'
            'AX_LIB_SQLITE3',
            'AX_LIB_TAGLIB',
            'AX_PKG_SWIG',
            'AC_PROG_SWIG',
            'AX_PROG_XSLTPROC',
            'AC_PYTHON_DEVEL',
            'AX_PYTHON_DEVEL',
            'AM_PATH_PYTHON',
            'AX_WITH_CURSES',
            'AX_PATH_BDB',
            'AX_PATH_LIB_PCRE',
            'AC_INIT',
            'AM_INIT_AUTOMAKE',
            'define(',
        ]

        for handler in handlers:
            handler.extend_keywords(keywords)

        for srcfile in srcfiles:
            nesting = 0
            in_keyword = ''
            partial = ''
            with open(srcfile, 'r', errors='surrogateescape') as f:
                for line in f:
                    if in_keyword:
                        partial += ' ' + line.strip()
                        if partial.endswith('\\'):
                            partial = partial[:-1]
                        nesting = nesting + line.count('(') - line.count(')')
                        if nesting == 0:
                            process_macro(in_keyword, partial)
                            partial = ''
                            in_keyword = ''
                    else:
                        for keyword in keywords:
                            if keyword in line:
                                nesting = line.count('(') - line.count(')')
                                if nesting > 0:
                                    partial = line.strip()
                                    if partial.endswith('\\'):
                                        partial = partial[:-1]
                                    in_keyword = keyword
                                else:
                                    process_macro(keyword, line.strip())
                                break

            if in_keyword:
                process_macro(in_keyword, partial)

        if extravalues:
            for k, v in list(extravalues.items()):
                if v:
                    if v.startswith('$') or v.startswith('@') or v.startswith(
                            '%'):
                        del extravalues[k]
                    else:
                        extravalues[k] = v.strip('"\'').rstrip('()')

        if unmapped:
            outlines.append(
                '# NOTE: the following prog dependencies are unknown, ignoring: %s'
                % ' '.join(list(set(unmapped))))

        RecipeHandler.handle_depends(libdeps, pcdeps, deps, outlines, values,
                                     tinfoil.config_data)

        for handler in handlers:
            handler.post_process(srctree, libdeps, pcdeps, deps, outlines,
                                 inherits, values)

        if inherits:
            values['inherit'] = ' '.join(list(set(inherits)))

        return values
示例#2
0
    def extract_autotools_deps(outlines, srctree, extravalues=None, acfile=None):
        import shlex

        # Find all plugins that want to register handlers
        logger.debug('Loading autotools handlers')
        handlers = []
        for plugin in plugins:
            if hasattr(plugin, 'register_autotools_handlers'):
                plugin.register_autotools_handlers(handlers)

        values = {}
        inherits = []

        # Hardcoded map, we also use a dynamic one based on what's in the sysroot
        progmap = {'flex': 'flex-native',
                'bison': 'bison-native',
                'm4': 'm4-native',
                'tar': 'tar-native',
                'ar': 'binutils-native',
                'ranlib': 'binutils-native',
                'ld': 'binutils-native',
                'strip': 'binutils-native',
                'libtool': '',
                'autoconf': '',
                'autoheader': '',
                'automake': '',
                'uname': '',
                'rm': '',
                'cp': '',
                'mv': '',
                'find': '',
                'awk': '',
                'sed': '',
                }
        progclassmap = {'gconftool-2': 'gconf',
                'pkg-config': 'pkgconfig',
                'python': 'pythonnative',
                'python3': 'python3native',
                'perl': 'perlnative',
                'makeinfo': 'texinfo',
                }

        pkg_re = re.compile('PKG_CHECK_MODULES\(\s*\[?[a-zA-Z0-9_]*\]?,\s*\[?([^,\]]*)\]?[),].*')
        pkgce_re = re.compile('PKG_CHECK_EXISTS\(\s*\[?([^,\]]*)\]?[),].*')
        lib_re = re.compile('AC_CHECK_LIB\(\s*\[?([^,\]]*)\]?,.*')
        libx_re = re.compile('AX_CHECK_LIBRARY\(\s*\[?[^,\]]*\]?,\s*\[?([^,\]]*)\]?,\s*\[?([a-zA-Z0-9-]*)\]?,.*')
        progs_re = re.compile('_PROGS?\(\s*\[?[a-zA-Z0-9_]*\]?,\s*\[?([^,\]]*)\]?[),].*')
        dep_re = re.compile('([^ ><=]+)( [<>=]+ [^ ><=]+)?')
        ac_init_re = re.compile('AC_INIT\(\s*([^,]+),\s*([^,]+)[,)].*')
        am_init_re = re.compile('AM_INIT_AUTOMAKE\(\s*([^,]+),\s*([^,]+)[,)].*')
        define_re = re.compile('\s*(m4_)?define\(\s*([^,]+),\s*([^,]+)\)')

        defines = {}
        def subst_defines(value):
            newvalue = value
            for define, defval in defines.items():
                newvalue = newvalue.replace(define, defval)
            if newvalue != value:
                return subst_defines(newvalue)
            return value

        def process_value(value):
            value = value.replace('[', '').replace(']', '')
            if value.startswith('m4_esyscmd(') or value.startswith('m4_esyscmd_s('):
                cmd = subst_defines(value[value.index('(')+1:-1])
                try:
                    if '|' in cmd:
                        cmd = 'set -o pipefail; ' + cmd
                    stdout, _ = bb.process.run(cmd, cwd=srctree, shell=True)
                    ret = stdout.rstrip()
                except bb.process.ExecutionError as e:
                    ret = ''
            elif value.startswith('m4_'):
                return None
            ret = subst_defines(value)
            if ret:
                ret = ret.strip('"\'')
            return ret

        # Since a configure.ac file is essentially a program, this is only ever going to be
        # a hack unfortunately; but it ought to be enough of an approximation
        if acfile:
            srcfiles = [acfile]
        else:
            srcfiles = RecipeHandler.checkfiles(srctree, ['acinclude.m4', 'configure.ac', 'configure.in'])

        pcdeps = []
        libdeps = []
        deps = []
        unmapped = []

        RecipeHandler.load_binmap(tinfoil.config_data)

        def process_macro(keyword, value):
            for handler in handlers:
                if handler.process_macro(srctree, keyword, value, process_value, libdeps, pcdeps, deps, outlines, inherits, values):
                    return
            if keyword == 'PKG_CHECK_MODULES':
                res = pkg_re.search(value)
                if res:
                    res = dep_re.findall(res.group(1))
                    if res:
                        pcdeps.extend([x[0] for x in res])
                inherits.append('pkgconfig')
            elif keyword == 'PKG_CHECK_EXISTS':
                res = pkgce_re.search(value)
                if res:
                    res = dep_re.findall(res.group(1))
                    if res:
                        pcdeps.extend([x[0] for x in res])
                inherits.append('pkgconfig')
            elif keyword in ('AM_GNU_GETTEXT', 'AM_GLIB_GNU_GETTEXT', 'GETTEXT_PACKAGE'):
                inherits.append('gettext')
            elif keyword in ('AC_PROG_INTLTOOL', 'IT_PROG_INTLTOOL'):
                deps.append('intltool-native')
            elif keyword == 'AM_PATH_GLIB_2_0':
                deps.append('glib-2.0')
            elif keyword in ('AC_CHECK_PROG', 'AC_PATH_PROG', 'AX_WITH_PROG'):
                res = progs_re.search(value)
                if res:
                    for prog in shlex.split(res.group(1)):
                        prog = prog.split()[0]
                        for handler in handlers:
                            if handler.process_prog(srctree, keyword, value, prog, deps, outlines, inherits, values):
                                return
                        progclass = progclassmap.get(prog, None)
                        if progclass:
                            inherits.append(progclass)
                        else:
                            progdep = RecipeHandler.recipebinmap.get(prog, None)
                            if not progdep:
                                progdep = progmap.get(prog, None)
                            if progdep:
                                deps.append(progdep)
                            elif progdep is None:
                                if not prog.startswith('$'):
                                    unmapped.append(prog)
            elif keyword == 'AC_CHECK_LIB':
                res = lib_re.search(value)
                if res:
                    lib = res.group(1)
                    if not lib.startswith('$'):
                        libdeps.append(lib)
            elif keyword == 'AX_CHECK_LIBRARY':
                res = libx_re.search(value)
                if res:
                    lib = res.group(2)
                    if not lib.startswith('$'):
                        header = res.group(1)
                        libdeps.append((lib, header))
            elif keyword == 'AC_PATH_X':
                deps.append('libx11')
            elif keyword in ('AX_BOOST', 'BOOST_REQUIRE'):
                deps.append('boost')
            elif keyword in ('AC_PROG_LEX', 'AM_PROG_LEX', 'AX_PROG_FLEX'):
                deps.append('flex-native')
            elif keyword in ('AC_PROG_YACC', 'AX_PROG_BISON'):
                deps.append('bison-native')
            elif keyword == 'AX_CHECK_ZLIB':
                deps.append('zlib')
            elif keyword in ('AX_CHECK_OPENSSL', 'AX_LIB_CRYPTO'):
                deps.append('openssl')
            elif keyword == 'AX_LIB_CURL':
                deps.append('curl')
            elif keyword == 'AX_LIB_BEECRYPT':
                deps.append('beecrypt')
            elif keyword == 'AX_LIB_EXPAT':
                deps.append('expat')
            elif keyword == 'AX_LIB_GCRYPT':
                deps.append('libgcrypt')
            elif keyword == 'AX_LIB_NETTLE':
                deps.append('nettle')
            elif keyword == 'AX_LIB_READLINE':
                deps.append('readline')
            elif keyword == 'AX_LIB_SQLITE3':
                deps.append('sqlite3')
            elif keyword == 'AX_LIB_TAGLIB':
                deps.append('taglib')
            elif keyword == 'AX_PKG_SWIG':
                deps.append('swig-native')
            elif keyword == 'AX_PROG_XSLTPROC':
                deps.append('libxslt-native')
            elif keyword == 'AX_WITH_CURSES':
                deps.append('ncurses')
            elif keyword == 'AX_PATH_BDB':
                deps.append('db')
            elif keyword == 'AX_PATH_LIB_PCRE':
                deps.append('libpcre')
            elif keyword == 'AC_INIT':
                if extravalues is not None:
                    res = ac_init_re.match(value)
                    if res:
                        extravalues['PN'] = process_value(res.group(1))
                        pv = process_value(res.group(2))
                        if validate_pv(pv):
                            extravalues['PV'] = pv
            elif keyword == 'AM_INIT_AUTOMAKE':
                if extravalues is not None:
                    if 'PN' not in extravalues:
                        res = am_init_re.match(value)
                        if res:
                            if res.group(1) != 'AC_PACKAGE_NAME':
                                extravalues['PN'] = process_value(res.group(1))
                            pv = process_value(res.group(2))
                            if validate_pv(pv):
                                extravalues['PV'] = pv
            elif keyword == 'define(':
                res = define_re.match(value)
                if res:
                    key = res.group(2).strip('[]')
                    value = process_value(res.group(3))
                    if value is not None:
                        defines[key] = value

        keywords = ['PKG_CHECK_MODULES',
                    'PKG_CHECK_EXISTS',
                    'AM_GNU_GETTEXT',
                    'AM_GLIB_GNU_GETTEXT',
                    'GETTEXT_PACKAGE',
                    'AC_PROG_INTLTOOL',
                    'IT_PROG_INTLTOOL',
                    'AM_PATH_GLIB_2_0',
                    'AC_CHECK_PROG',
                    'AC_PATH_PROG',
                    'AX_WITH_PROG',
                    'AC_CHECK_LIB',
                    'AX_CHECK_LIBRARY',
                    'AC_PATH_X',
                    'AX_BOOST',
                    'BOOST_REQUIRE',
                    'AC_PROG_LEX',
                    'AM_PROG_LEX',
                    'AX_PROG_FLEX',
                    'AC_PROG_YACC',
                    'AX_PROG_BISON',
                    'AX_CHECK_ZLIB',
                    'AX_CHECK_OPENSSL',
                    'AX_LIB_CRYPTO',
                    'AX_LIB_CURL',
                    'AX_LIB_BEECRYPT',
                    'AX_LIB_EXPAT',
                    'AX_LIB_GCRYPT',
                    'AX_LIB_NETTLE',
                    'AX_LIB_READLINE'
                    'AX_LIB_SQLITE3',
                    'AX_LIB_TAGLIB',
                    'AX_PKG_SWIG',
                    'AX_PROG_XSLTPROC',
                    'AX_WITH_CURSES',
                    'AX_PATH_BDB',
                    'AX_PATH_LIB_PCRE',
                    'AC_INIT',
                    'AM_INIT_AUTOMAKE',
                    'define(',
                    ]

        for handler in handlers:
            handler.extend_keywords(keywords)

        for srcfile in srcfiles:
            nesting = 0
            in_keyword = ''
            partial = ''
            with open(srcfile, 'r', errors='surrogateescape') as f:
                for line in f:
                    if in_keyword:
                        partial += ' ' + line.strip()
                        if partial.endswith('\\'):
                            partial = partial[:-1]
                        nesting = nesting + line.count('(') - line.count(')')
                        if nesting == 0:
                            process_macro(in_keyword, partial)
                            partial = ''
                            in_keyword = ''
                    else:
                        for keyword in keywords:
                            if keyword in line:
                                nesting = line.count('(') - line.count(')')
                                if nesting > 0:
                                    partial = line.strip()
                                    if partial.endswith('\\'):
                                        partial = partial[:-1]
                                    in_keyword = keyword
                                else:
                                    process_macro(keyword, line.strip())
                                break

            if in_keyword:
                process_macro(in_keyword, partial)

        if extravalues:
            for k,v in list(extravalues.items()):
                if v:
                    if v.startswith('$') or v.startswith('@') or v.startswith('%'):
                        del extravalues[k]
                    else:
                        extravalues[k] = v.strip('"\'').rstrip('()')

        if unmapped:
            outlines.append('# NOTE: the following prog dependencies are unknown, ignoring: %s' % ' '.join(list(set(unmapped))))

        RecipeHandler.handle_depends(libdeps, pcdeps, deps, outlines, values, tinfoil.config_data)

        for handler in handlers:
            handler.post_process(srctree, libdeps, pcdeps, deps, outlines, inherits, values)

        if inherits:
            values['inherit'] = ' '.join(list(set(inherits)))

        return values
示例#3
0
    def extract_autotools_deps(outlines, srctree, extravalues=None, acfile=None):
        import shlex

        # Find all plugins that want to register handlers
        logger.debug("Loading autotools handlers")
        handlers = []
        for plugin in plugins:
            if hasattr(plugin, "register_autotools_handlers"):
                plugin.register_autotools_handlers(handlers)

        values = {}
        inherits = []

        # Hardcoded map, we also use a dynamic one based on what's in the sysroot
        progmap = {
            "flex": "flex-native",
            "bison": "bison-native",
            "m4": "m4-native",
            "tar": "tar-native",
            "ar": "binutils-native",
            "ranlib": "binutils-native",
            "ld": "binutils-native",
            "strip": "binutils-native",
            "libtool": "",
            "autoconf": "",
            "autoheader": "",
            "automake": "",
            "uname": "",
            "rm": "",
            "cp": "",
            "mv": "",
            "find": "",
            "awk": "",
            "sed": "",
        }
        progclassmap = {
            "gconftool-2": "gconf",
            "pkg-config": "pkgconfig",
            "python": "pythonnative",
            "python3": "python3native",
            "perl": "perlnative",
            "makeinfo": "texinfo",
        }

        pkg_re = re.compile("PKG_CHECK_MODULES\(\s*\[?[a-zA-Z0-9_]*\]?,\s*\[?([^,\]]*)\]?[),].*")
        pkgce_re = re.compile("PKG_CHECK_EXISTS\(\s*\[?([^,\]]*)\]?[),].*")
        lib_re = re.compile("AC_CHECK_LIB\(\s*\[?([^,\]]*)\]?,.*")
        libx_re = re.compile("AX_CHECK_LIBRARY\(\s*\[?[^,\]]*\]?,\s*\[?([^,\]]*)\]?,\s*\[?([a-zA-Z0-9-]*)\]?,.*")
        progs_re = re.compile("_PROGS?\(\s*\[?[a-zA-Z0-9_]*\]?,\s*\[?([^,\]]*)\]?[),].*")
        dep_re = re.compile("([^ ><=]+)( [<>=]+ [^ ><=]+)?")
        ac_init_re = re.compile("AC_INIT\(\s*([^,]+),\s*([^,]+)[,)].*")
        am_init_re = re.compile("AM_INIT_AUTOMAKE\(\s*([^,]+),\s*([^,]+)[,)].*")
        define_re = re.compile("\s*(m4_)?define\(\s*([^,]+),\s*([^,]+)\)")

        defines = {}

        def subst_defines(value):
            newvalue = value
            for define, defval in defines.iteritems():
                newvalue = newvalue.replace(define, defval)
            if newvalue != value:
                return subst_defines(newvalue)
            return value

        def process_value(value):
            value = value.replace("[", "").replace("]", "")
            if value.startswith("m4_esyscmd(") or value.startswith("m4_esyscmd_s("):
                cmd = subst_defines(value[value.index("(") + 1 : -1])
                try:
                    if "|" in cmd:
                        cmd = "set -o pipefail; " + cmd
                    stdout, _ = bb.process.run(cmd, cwd=srctree, shell=True)
                    ret = stdout.rstrip()
                except bb.process.ExecutionError as e:
                    ret = ""
            elif value.startswith("m4_"):
                return None
            ret = subst_defines(value)
            if ret:
                ret = ret.strip("\"'")
            return ret

        # Since a configure.ac file is essentially a program, this is only ever going to be
        # a hack unfortunately; but it ought to be enough of an approximation
        if acfile:
            srcfiles = [acfile]
        else:
            srcfiles = RecipeHandler.checkfiles(srctree, ["acinclude.m4", "configure.ac", "configure.in"])

        pcdeps = []
        libdeps = []
        deps = []
        unmapped = []

        RecipeHandler.load_binmap(tinfoil.config_data)

        def process_macro(keyword, value):
            for handler in handlers:
                if handler.process_macro(
                    srctree, keyword, value, process_value, libdeps, pcdeps, deps, outlines, inherits, values
                ):
                    return
            if keyword == "PKG_CHECK_MODULES":
                res = pkg_re.search(value)
                if res:
                    res = dep_re.findall(res.group(1))
                    if res:
                        pcdeps.extend([x[0] for x in res])
                inherits.append("pkgconfig")
            elif keyword == "PKG_CHECK_EXISTS":
                res = pkgce_re.search(value)
                if res:
                    res = dep_re.findall(res.group(1))
                    if res:
                        pcdeps.extend([x[0] for x in res])
                inherits.append("pkgconfig")
            elif keyword in ("AM_GNU_GETTEXT", "AM_GLIB_GNU_GETTEXT", "GETTEXT_PACKAGE"):
                inherits.append("gettext")
            elif keyword in ("AC_PROG_INTLTOOL", "IT_PROG_INTLTOOL"):
                deps.append("intltool-native")
            elif keyword == "AM_PATH_GLIB_2_0":
                deps.append("glib-2.0")
            elif keyword in ("AC_CHECK_PROG", "AC_PATH_PROG", "AX_WITH_PROG"):
                res = progs_re.search(value)
                if res:
                    for prog in shlex.split(res.group(1)):
                        prog = prog.split()[0]
                        for handler in handlers:
                            if handler.process_prog(srctree, keyword, value, prog, deps, outlines, inherits, values):
                                return
                        progclass = progclassmap.get(prog, None)
                        if progclass:
                            inherits.append(progclass)
                        else:
                            progdep = RecipeHandler.recipebinmap.get(prog, None)
                            if not progdep:
                                progdep = progmap.get(prog, None)
                            if progdep:
                                deps.append(progdep)
                            elif progdep is None:
                                if not prog.startswith("$"):
                                    unmapped.append(prog)
            elif keyword == "AC_CHECK_LIB":
                res = lib_re.search(value)
                if res:
                    lib = res.group(1)
                    if not lib.startswith("$"):
                        libdeps.append(lib)
            elif keyword == "AX_CHECK_LIBRARY":
                res = libx_re.search(value)
                if res:
                    lib = res.group(2)
                    if not lib.startswith("$"):
                        header = res.group(1)
                        libdeps.append((lib, header))
            elif keyword == "AC_PATH_X":
                deps.append("libx11")
            elif keyword in ("AX_BOOST", "BOOST_REQUIRE"):
                deps.append("boost")
            elif keyword in ("AC_PROG_LEX", "AM_PROG_LEX", "AX_PROG_FLEX"):
                deps.append("flex-native")
            elif keyword in ("AC_PROG_YACC", "AX_PROG_BISON"):
                deps.append("bison-native")
            elif keyword == "AX_CHECK_ZLIB":
                deps.append("zlib")
            elif keyword in ("AX_CHECK_OPENSSL", "AX_LIB_CRYPTO"):
                deps.append("openssl")
            elif keyword == "AX_LIB_CURL":
                deps.append("curl")
            elif keyword == "AX_LIB_BEECRYPT":
                deps.append("beecrypt")
            elif keyword == "AX_LIB_EXPAT":
                deps.append("expat")
            elif keyword == "AX_LIB_GCRYPT":
                deps.append("libgcrypt")
            elif keyword == "AX_LIB_NETTLE":
                deps.append("nettle")
            elif keyword == "AX_LIB_READLINE":
                deps.append("readline")
            elif keyword == "AX_LIB_SQLITE3":
                deps.append("sqlite3")
            elif keyword == "AX_LIB_TAGLIB":
                deps.append("taglib")
            elif keyword == "AX_PKG_SWIG":
                deps.append("swig")
            elif keyword == "AX_PROG_XSLTPROC":
                deps.append("libxslt-native")
            elif keyword == "AX_WITH_CURSES":
                deps.append("ncurses")
            elif keyword == "AX_PATH_BDB":
                deps.append("db")
            elif keyword == "AX_PATH_LIB_PCRE":
                deps.append("libpcre")
            elif keyword == "AC_INIT":
                if extravalues is not None:
                    res = ac_init_re.match(value)
                    if res:
                        extravalues["PN"] = process_value(res.group(1))
                        pv = process_value(res.group(2))
                        if validate_pv(pv):
                            extravalues["PV"] = pv
            elif keyword == "AM_INIT_AUTOMAKE":
                if extravalues is not None:
                    if "PN" not in extravalues:
                        res = am_init_re.match(value)
                        if res:
                            if res.group(1) != "AC_PACKAGE_NAME":
                                extravalues["PN"] = process_value(res.group(1))
                            pv = process_value(res.group(2))
                            if validate_pv(pv):
                                extravalues["PV"] = pv
            elif keyword == "define(":
                res = define_re.match(value)
                if res:
                    key = res.group(2).strip("[]")
                    value = process_value(res.group(3))
                    if value is not None:
                        defines[key] = value

        keywords = [
            "PKG_CHECK_MODULES",
            "PKG_CHECK_EXISTS",
            "AM_GNU_GETTEXT",
            "AM_GLIB_GNU_GETTEXT",
            "GETTEXT_PACKAGE",
            "AC_PROG_INTLTOOL",
            "IT_PROG_INTLTOOL",
            "AM_PATH_GLIB_2_0",
            "AC_CHECK_PROG",
            "AC_PATH_PROG",
            "AX_WITH_PROG",
            "AC_CHECK_LIB",
            "AX_CHECK_LIBRARY",
            "AC_PATH_X",
            "AX_BOOST",
            "BOOST_REQUIRE",
            "AC_PROG_LEX",
            "AM_PROG_LEX",
            "AX_PROG_FLEX",
            "AC_PROG_YACC",
            "AX_PROG_BISON",
            "AX_CHECK_ZLIB",
            "AX_CHECK_OPENSSL",
            "AX_LIB_CRYPTO",
            "AX_LIB_CURL",
            "AX_LIB_BEECRYPT",
            "AX_LIB_EXPAT",
            "AX_LIB_GCRYPT",
            "AX_LIB_NETTLE",
            "AX_LIB_READLINE" "AX_LIB_SQLITE3",
            "AX_LIB_TAGLIB",
            "AX_PKG_SWIG",
            "AX_PROG_XSLTPROC",
            "AX_WITH_CURSES",
            "AX_PATH_BDB",
            "AX_PATH_LIB_PCRE",
            "AC_INIT",
            "AM_INIT_AUTOMAKE",
            "define(",
        ]

        for handler in handlers:
            handler.extend_keywords(keywords)

        for srcfile in srcfiles:
            nesting = 0
            in_keyword = ""
            partial = ""
            with open(srcfile, "r") as f:
                for line in f:
                    if in_keyword:
                        partial += " " + line.strip()
                        if partial.endswith("\\"):
                            partial = partial[:-1]
                        nesting = nesting + line.count("(") - line.count(")")
                        if nesting == 0:
                            process_macro(in_keyword, partial)
                            partial = ""
                            in_keyword = ""
                    else:
                        for keyword in keywords:
                            if keyword in line:
                                nesting = line.count("(") - line.count(")")
                                if nesting > 0:
                                    partial = line.strip()
                                    if partial.endswith("\\"):
                                        partial = partial[:-1]
                                    in_keyword = keyword
                                else:
                                    process_macro(keyword, line.strip())
                                break

            if in_keyword:
                process_macro(in_keyword, partial)

        if extravalues:
            for k, v in extravalues.items():
                if v:
                    if v.startswith("$") or v.startswith("@") or v.startswith("%"):
                        del extravalues[k]
                    else:
                        extravalues[k] = v.strip("\"'").rstrip("()")

        if unmapped:
            outlines.append(
                "# NOTE: the following prog dependencies are unknown, ignoring: %s" % " ".join(list(set(unmapped)))
            )

        RecipeHandler.handle_depends(libdeps, pcdeps, deps, outlines, values, tinfoil.config_data)

        for handler in handlers:
            handler.post_process(srctree, libdeps, pcdeps, deps, outlines, inherits, values)

        if inherits:
            values["inherit"] = " ".join(list(set(inherits)))

        return values