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 <paul.eggleton@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
Paul Eggleton 2016-01-19 00:18:33 +13:00 committed by Richard Purdie
parent 3eb397fab6
commit 2c8c9fe3b4
3 changed files with 191 additions and 6 deletions

View File

@ -422,6 +422,23 @@ class RecipetoolTests(RecipetoolBase):
inherits = ['autotools']
self._test_recipe_contents(os.path.join(temprecipe, dirlist[0]), checkvars, inherits)
def test_recipetool_create_cmake(self):
# Try adding a recipe
temprecipe = os.path.join(self.tempdir, 'recipe')
os.makedirs(temprecipe)
recipefile = os.path.join(temprecipe, 'navit_0.5.0.bb')
srcuri = 'http://downloads.sourceforge.net/project/navit/v0.5.0/navit-0.5.0.tar.gz'
result = runCmd('recipetool create -o %s %s' % (temprecipe, srcuri))
self.assertTrue(os.path.isfile(recipefile))
checkvars = {}
checkvars['LICENSE'] = set(['Unknown', 'GPLv2', 'LGPLv2'])
checkvars['SRC_URI'] = 'http://downloads.sourceforge.net/project/navit/v${PV}/navit-${PV}.tar.gz'
checkvars['SRC_URI[md5sum]'] = '242f398e979a6b8c0f3c802b63435b68'
checkvars['SRC_URI[sha256sum]'] = '13353481d7fc01a4f64e385dda460b51496366bba0fd2cc85a89a0747910e94d'
checkvars['DEPENDS'] = set(['freetype', 'zlib', 'openssl', 'glib-2.0', 'virtual/libgl', 'virtual/egl', 'gtk+', 'libpng', 'libsdl', 'freeglut', 'dbus-glib'])
inherits = ['cmake', 'python-dir', 'gettext', 'pkgconfig']
self._test_recipe_contents(recipefile, checkvars, inherits)
class RecipetoolAppendsrcBase(RecipetoolBase):
def _try_recipetool_appendsrcfile(self, testrecipe, newfile, destfile, options, expectedlines, expectedfiles):
cmd = 'recipetool appendsrcfile %s %s %s %s %s' % (options, self.templayerdir, testrecipe, newfile, destfile)

View File

@ -558,6 +558,8 @@ def create_recipe(args):
outlines = []
outlines.extend(lines_before)
if classes:
if outlines[-1] and not outlines[-1].startswith('#'):
outlines.append('')
outlines.append('inherit %s' % ' '.join(classes))
outlines.append('')
outlines.extend(lines_after)
@ -627,6 +629,7 @@ def get_license_md5sums(d, static_only=False):
md5sums['5f30f0716dfdd0d91eb439ebec522ec2'] = 'LGPLv2'
md5sums['55ca817ccb7d5b5b66355690e9abc605'] = 'LGPLv2'
md5sums['252890d9eee26aab7b432e8b8a616475'] = 'LGPLv2'
md5sums['3214f080875748938ba060314b4f727d'] = 'LGPLv2'
md5sums['d32239bcb673463ab874e80d47fae504'] = 'GPLv3'
md5sums['f27defe1e96c2e1ecd4e0c9be8967949'] = 'GPLv3'
md5sums['6a6a8e020838b23406c81b19c1d46df6'] = 'LGPLv3'

View File

@ -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