From 2c8c9fe3b4e2d3a0910d567e99f0b268a854c0fe Mon Sep 17 00:00:00 2001 From: Paul Eggleton Date: Tue, 19 Jan 2016 00:18:33 +1300 Subject: recipetool: create: add basic support for extracting dependencies from cmake Add support for extracting dependencies from CMakeLists.txt. There's still a bunch of things missing that are outside the scope of OE-Core and we still lack a proper extension mechanism, but this is a good start. This also adds an oe-selftest test to exercise the new code a bit. Implements [YOCTO #7635]. (From OE-Core rev: 77e73e6930381fdbd6e78d3913d6467572e16568) Signed-off-by: Paul Eggleton Signed-off-by: Richard Purdie --- scripts/lib/recipetool/create_buildsys.py | 177 +++++++++++++++++++++++++++++- 1 file changed, 171 insertions(+), 6 deletions(-) (limited to 'scripts/lib/recipetool/create_buildsys.py') diff --git a/scripts/lib/recipetool/create_buildsys.py b/scripts/lib/recipetool/create_buildsys.py index 40659d1ea8..6afb5de1c2 100644 --- a/scripts/lib/recipetool/create_buildsys.py +++ b/scripts/lib/recipetool/create_buildsys.py @@ -36,6 +36,7 @@ class CmakeRecipeHandler(RecipeHandler): if RecipeHandler.checkfiles(srctree, ['CMakeLists.txt']): classes.append('cmake') values = CmakeRecipeHandler.extract_cmake_deps(lines_before, srctree, extravalues) + classes.extend(values.pop('inherit', '').split()) for var, value in values.iteritems(): lines_before.append('%s = "%s"' % (var, value)) lines_after.append('# Specify any options you want to pass to cmake using EXTRA_OECMAKE:') @@ -48,18 +49,182 @@ class CmakeRecipeHandler(RecipeHandler): @staticmethod def extract_cmake_deps(outlines, srctree, extravalues, cmakelistsfile=None): values = {} + inherits = [] if cmakelistsfile: srcfiles = [cmakelistsfile] else: srcfiles = RecipeHandler.checkfiles(srctree, ['CMakeLists.txt']) - proj_re = re.compile('project\(([^)]*)\)', re.IGNORECASE) - with open(srcfiles[0], 'r') as f: - for line in f: - res = proj_re.match(line.strip()) - if res: - extravalues['PN'] = res.group(1).split()[0] + # Note that some of these are non-standard, but probably better to + # be able to map them anyway if we see them + cmake_pkgmap = {'alsa': 'alsa-lib', + 'aspell': 'aspell', + 'atk': 'atk', + 'bison': 'bison-native', + 'boost': 'boost', + 'bzip2': 'bzip2', + 'cairo': 'cairo', + 'cups': 'cups', + 'curl': 'curl', + 'curses': 'ncurses', + 'cvs': 'cvs', + 'drm': 'libdrm', + 'dbus': 'dbus', + 'dbusglib': 'dbus-glib', + 'egl': 'virtual/egl', + 'expat': 'expat', + 'flex': 'flex-native', + 'fontconfig': 'fontconfig', + 'freetype': 'freetype', + 'gettext': '', + 'git': '', + 'gio': 'glib-2.0', + 'giounix': 'glib-2.0', + 'glew': 'glew', + 'glib': 'glib-2.0', + 'glib2': 'glib-2.0', + 'glu': 'libglu', + 'glut': 'freeglut', + 'gobject': 'glib-2.0', + 'gperf': 'gperf-native', + 'gnutls': 'gnutls', + 'gtk2': 'gtk+', + 'gtk3': 'gtk+3', + 'gtk': 'gtk+3', + 'harfbuzz': 'harfbuzz', + 'icu': 'icu', + 'intl': 'virtual/libintl', + 'jpeg': 'jpeg', + 'libarchive': 'libarchive', + 'libiconv': 'virtual/libiconv', + 'liblzma': 'xz', + 'libxml2': 'libxml2', + 'libxslt': 'libxslt', + 'opengl': 'virtual/libgl', + 'openmp': '', + 'openssl': 'openssl', + 'pango': 'pango', + 'perl': '', + 'perllibs': '', + 'pkgconfig': '', + 'png': 'libpng', + 'pthread': '', + 'pythoninterp': '', + 'pythonlibs': '', + 'ruby': 'ruby-native', + 'sdl': 'libsdl', + 'sdl2': 'libsdl2', + 'subversion': 'subversion-native', + 'swig': 'swig-native', + 'tcl': 'tcl-native', + 'threads': '', + 'tiff': 'tiff', + 'wget': 'wget', + 'x11': 'libx11', + 'xcb': 'libxcb', + 'xext': 'libxext', + 'xfixes': 'libxfixes', + 'zlib': 'zlib', + } + + pcdeps = [] + libdeps = [] + deps = [] + unmappedpkgs = [] + + proj_re = re.compile('project\s*\(([^)]*)\)', re.IGNORECASE) + pkgcm_re = re.compile('pkg_check_modules\s*\(\s*[a-zA-Z0-9-_]+\s*(REQUIRED)?\s+([^)\s]+)\s*\)', re.IGNORECASE) + pkgsm_re = re.compile('pkg_search_module\s*\(\s*[a-zA-Z0-9-_]+\s*(REQUIRED)?((\s+[^)\s]+)+)\s*\)', re.IGNORECASE) + findpackage_re = re.compile('find_package\s*\(\s*([a-zA-Z0-9-_]+)\s*.*', re.IGNORECASE) + checklib_re = re.compile('check_library_exists\s*\(\s*([^\s)]+)\s*.*', re.IGNORECASE) + include_re = re.compile('include\s*\(\s*([^)\s]*)\s*\)', re.IGNORECASE) + subdir_re = re.compile('add_subdirectory\s*\(\s*([^)\s]*)\s*([^)\s]*)\s*\)', re.IGNORECASE) + dep_re = re.compile('([^ ><=]+)( *[<>=]+ *[^ ><=]+)?') + + def parse_cmake_file(fn, paths=None): + searchpaths = (paths or []) + [os.path.dirname(fn)] + logger.debug('Parsing file %s' % fn) + with open(fn, 'r') as f: + for line in f: + line = line.strip() + res = include_re.match(line) + if res: + includefn = bb.utils.which(':'.join(searchpaths), res.group(1)) + if includefn: + parse_cmake_file(includefn, searchpaths) + else: + logger.debug('Unable to recurse into include file %s' % res.group(1)) + continue + res = subdir_re.match(line) + if res: + subdirfn = os.path.join(os.path.dirname(fn), res.group(1), 'CMakeLists.txt') + if os.path.exists(subdirfn): + parse_cmake_file(subdirfn, searchpaths) + else: + logger.debug('Unable to recurse into subdirectory file %s' % subdirfn) + continue + res = proj_re.match(line) + if res: + extravalues['PN'] = res.group(1).split()[0] + continue + res = pkgcm_re.match(line) + if res: + res = dep_re.findall(res.group(2)) + if res: + pcdeps.extend([x[0] for x in res]) + inherits.append('pkgconfig') + continue + res = pkgsm_re.match(line) + if res: + res = dep_re.findall(res.group(2)) + if res: + # Note: appending a tuple here! + item = tuple((x[0] for x in res)) + if len(item) == 1: + item = item[0] + pcdeps.append(item) + inherits.append('pkgconfig') + continue + res = findpackage_re.match(line) + if res: + origpkg = res.group(1) + pkg = origpkg.lower() + if pkg == 'gettext': + inherits.append('gettext') + elif pkg == 'perl': + inherits.append('perlnative') + elif pkg == 'pkgconfig': + inherits.append('pkgconfig') + elif pkg == 'pythoninterp': + inherits.append('pythonnative') + elif pkg == 'pythonlibs': + inherits.append('python-dir') + else: + dep = cmake_pkgmap.get(pkg, None) + if dep: + deps.append(dep) + elif dep is None: + unmappedpkgs.append(origpkg) + continue + res = checklib_re.match(line) + if res: + lib = res.group(1) + if not lib.startswith('$'): + libdeps.append(lib) + if line.lower().startswith('useswig'): + deps.append('swig-native') + continue + + parse_cmake_file(srcfiles[0]) + + if unmappedpkgs: + outlines.append('# NOTE: unable to map the following CMake package dependencies: %s' % ' '.join(unmappedpkgs)) + + RecipeHandler.handle_depends(libdeps, pcdeps, deps, outlines, values, tinfoil.config_data) + + if inherits: + values['inherit'] = ' '.join(list(set(inherits))) return values -- cgit v1.2.3-54-g00ecf