summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggleton <paul.eggleton@linux.intel.com>2016-01-19 00:18:33 +1300
committerRichard Purdie <richard.purdie@linuxfoundation.org>2016-01-19 17:24:53 +0000
commit2c8c9fe3b4e2d3a0910d567e99f0b268a854c0fe (patch)
tree863a899e78f3213f75729db08efc6cfed1a4a51c
parent3eb397fab6a5c5a86ac4eb30c5159f19e8ebf796 (diff)
downloadpoky-2c8c9fe3b4e2d3a0910d567e99f0b268a854c0fe.tar.gz
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>
-rw-r--r--meta/lib/oeqa/selftest/recipetool.py17
-rw-r--r--scripts/lib/recipetool/create.py3
-rw-r--r--scripts/lib/recipetool/create_buildsys.py177
3 files changed, 191 insertions, 6 deletions
diff --git a/meta/lib/oeqa/selftest/recipetool.py b/meta/lib/oeqa/selftest/recipetool.py
index 927da73e6f..b4d33bc35d 100644
--- a/meta/lib/oeqa/selftest/recipetool.py
+++ b/meta/lib/oeqa/selftest/recipetool.py
@@ -422,6 +422,23 @@ class RecipetoolTests(RecipetoolBase):
422 inherits = ['autotools'] 422 inherits = ['autotools']
423 self._test_recipe_contents(os.path.join(temprecipe, dirlist[0]), checkvars, inherits) 423 self._test_recipe_contents(os.path.join(temprecipe, dirlist[0]), checkvars, inherits)
424 424
425 def test_recipetool_create_cmake(self):
426 # Try adding a recipe
427 temprecipe = os.path.join(self.tempdir, 'recipe')
428 os.makedirs(temprecipe)
429 recipefile = os.path.join(temprecipe, 'navit_0.5.0.bb')
430 srcuri = 'http://downloads.sourceforge.net/project/navit/v0.5.0/navit-0.5.0.tar.gz'
431 result = runCmd('recipetool create -o %s %s' % (temprecipe, srcuri))
432 self.assertTrue(os.path.isfile(recipefile))
433 checkvars = {}
434 checkvars['LICENSE'] = set(['Unknown', 'GPLv2', 'LGPLv2'])
435 checkvars['SRC_URI'] = 'http://downloads.sourceforge.net/project/navit/v${PV}/navit-${PV}.tar.gz'
436 checkvars['SRC_URI[md5sum]'] = '242f398e979a6b8c0f3c802b63435b68'
437 checkvars['SRC_URI[sha256sum]'] = '13353481d7fc01a4f64e385dda460b51496366bba0fd2cc85a89a0747910e94d'
438 checkvars['DEPENDS'] = set(['freetype', 'zlib', 'openssl', 'glib-2.0', 'virtual/libgl', 'virtual/egl', 'gtk+', 'libpng', 'libsdl', 'freeglut', 'dbus-glib'])
439 inherits = ['cmake', 'python-dir', 'gettext', 'pkgconfig']
440 self._test_recipe_contents(recipefile, checkvars, inherits)
441
425class RecipetoolAppendsrcBase(RecipetoolBase): 442class RecipetoolAppendsrcBase(RecipetoolBase):
426 def _try_recipetool_appendsrcfile(self, testrecipe, newfile, destfile, options, expectedlines, expectedfiles): 443 def _try_recipetool_appendsrcfile(self, testrecipe, newfile, destfile, options, expectedlines, expectedfiles):
427 cmd = 'recipetool appendsrcfile %s %s %s %s %s' % (options, self.templayerdir, testrecipe, newfile, destfile) 444 cmd = 'recipetool appendsrcfile %s %s %s %s %s' % (options, self.templayerdir, testrecipe, newfile, destfile)
diff --git a/scripts/lib/recipetool/create.py b/scripts/lib/recipetool/create.py
index 1601a7f8c4..ad6bf7ba4b 100644
--- a/scripts/lib/recipetool/create.py
+++ b/scripts/lib/recipetool/create.py
@@ -558,6 +558,8 @@ def create_recipe(args):
558 outlines = [] 558 outlines = []
559 outlines.extend(lines_before) 559 outlines.extend(lines_before)
560 if classes: 560 if classes:
561 if outlines[-1] and not outlines[-1].startswith('#'):
562 outlines.append('')
561 outlines.append('inherit %s' % ' '.join(classes)) 563 outlines.append('inherit %s' % ' '.join(classes))
562 outlines.append('') 564 outlines.append('')
563 outlines.extend(lines_after) 565 outlines.extend(lines_after)
@@ -627,6 +629,7 @@ def get_license_md5sums(d, static_only=False):
627 md5sums['5f30f0716dfdd0d91eb439ebec522ec2'] = 'LGPLv2' 629 md5sums['5f30f0716dfdd0d91eb439ebec522ec2'] = 'LGPLv2'
628 md5sums['55ca817ccb7d5b5b66355690e9abc605'] = 'LGPLv2' 630 md5sums['55ca817ccb7d5b5b66355690e9abc605'] = 'LGPLv2'
629 md5sums['252890d9eee26aab7b432e8b8a616475'] = 'LGPLv2' 631 md5sums['252890d9eee26aab7b432e8b8a616475'] = 'LGPLv2'
632 md5sums['3214f080875748938ba060314b4f727d'] = 'LGPLv2'
630 md5sums['d32239bcb673463ab874e80d47fae504'] = 'GPLv3' 633 md5sums['d32239bcb673463ab874e80d47fae504'] = 'GPLv3'
631 md5sums['f27defe1e96c2e1ecd4e0c9be8967949'] = 'GPLv3' 634 md5sums['f27defe1e96c2e1ecd4e0c9be8967949'] = 'GPLv3'
632 md5sums['6a6a8e020838b23406c81b19c1d46df6'] = 'LGPLv3' 635 md5sums['6a6a8e020838b23406c81b19c1d46df6'] = 'LGPLv3'
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):
36 if RecipeHandler.checkfiles(srctree, ['CMakeLists.txt']): 36 if RecipeHandler.checkfiles(srctree, ['CMakeLists.txt']):
37 classes.append('cmake') 37 classes.append('cmake')
38 values = CmakeRecipeHandler.extract_cmake_deps(lines_before, srctree, extravalues) 38 values = CmakeRecipeHandler.extract_cmake_deps(lines_before, srctree, extravalues)
39 classes.extend(values.pop('inherit', '').split())
39 for var, value in values.iteritems(): 40 for var, value in values.iteritems():
40 lines_before.append('%s = "%s"' % (var, value)) 41 lines_before.append('%s = "%s"' % (var, value))
41 lines_after.append('# Specify any options you want to pass to cmake using EXTRA_OECMAKE:') 42 lines_after.append('# Specify any options you want to pass to cmake using EXTRA_OECMAKE:')
@@ -48,18 +49,182 @@ class CmakeRecipeHandler(RecipeHandler):
48 @staticmethod 49 @staticmethod
49 def extract_cmake_deps(outlines, srctree, extravalues, cmakelistsfile=None): 50 def extract_cmake_deps(outlines, srctree, extravalues, cmakelistsfile=None):
50 values = {} 51 values = {}
52 inherits = []
51 53
52 if cmakelistsfile: 54 if cmakelistsfile:
53 srcfiles = [cmakelistsfile] 55 srcfiles = [cmakelistsfile]
54 else: 56 else:
55 srcfiles = RecipeHandler.checkfiles(srctree, ['CMakeLists.txt']) 57 srcfiles = RecipeHandler.checkfiles(srctree, ['CMakeLists.txt'])
56 58
57 proj_re = re.compile('project\(([^)]*)\)', re.IGNORECASE) 59 # Note that some of these are non-standard, but probably better to
58 with open(srcfiles[0], 'r') as f: 60 # be able to map them anyway if we see them
59 for line in f: 61 cmake_pkgmap = {'alsa': 'alsa-lib',
60 res = proj_re.match(line.strip()) 62 'aspell': 'aspell',
61 if res: 63 'atk': 'atk',
62 extravalues['PN'] = res.group(1).split()[0] 64 'bison': 'bison-native',
65 'boost': 'boost',
66 'bzip2': 'bzip2',
67 'cairo': 'cairo',
68 'cups': 'cups',
69 'curl': 'curl',
70 'curses': 'ncurses',
71 'cvs': 'cvs',
72 'drm': 'libdrm',
73 'dbus': 'dbus',
74 'dbusglib': 'dbus-glib',
75 'egl': 'virtual/egl',
76 'expat': 'expat',
77 'flex': 'flex-native',
78 'fontconfig': 'fontconfig',
79 'freetype': 'freetype',
80 'gettext': '',
81 'git': '',
82 'gio': 'glib-2.0',
83 'giounix': 'glib-2.0',
84 'glew': 'glew',
85 'glib': 'glib-2.0',
86 'glib2': 'glib-2.0',
87 'glu': 'libglu',
88 'glut': 'freeglut',
89 'gobject': 'glib-2.0',
90 'gperf': 'gperf-native',
91 'gnutls': 'gnutls',
92 'gtk2': 'gtk+',
93 'gtk3': 'gtk+3',
94 'gtk': 'gtk+3',
95 'harfbuzz': 'harfbuzz',
96 'icu': 'icu',
97 'intl': 'virtual/libintl',
98 'jpeg': 'jpeg',
99 'libarchive': 'libarchive',
100 'libiconv': 'virtual/libiconv',
101 'liblzma': 'xz',
102 'libxml2': 'libxml2',
103 'libxslt': 'libxslt',
104 'opengl': 'virtual/libgl',
105 'openmp': '',
106 'openssl': 'openssl',
107 'pango': 'pango',
108 'perl': '',
109 'perllibs': '',
110 'pkgconfig': '',
111 'png': 'libpng',
112 'pthread': '',
113 'pythoninterp': '',
114 'pythonlibs': '',
115 'ruby': 'ruby-native',
116 'sdl': 'libsdl',
117 'sdl2': 'libsdl2',
118 'subversion': 'subversion-native',
119 'swig': 'swig-native',
120 'tcl': 'tcl-native',
121 'threads': '',
122 'tiff': 'tiff',
123 'wget': 'wget',
124 'x11': 'libx11',
125 'xcb': 'libxcb',
126 'xext': 'libxext',
127 'xfixes': 'libxfixes',
128 'zlib': 'zlib',
129 }
130
131 pcdeps = []
132 libdeps = []
133 deps = []
134 unmappedpkgs = []
135
136 proj_re = re.compile('project\s*\(([^)]*)\)', re.IGNORECASE)
137 pkgcm_re = re.compile('pkg_check_modules\s*\(\s*[a-zA-Z0-9-_]+\s*(REQUIRED)?\s+([^)\s]+)\s*\)', re.IGNORECASE)
138 pkgsm_re = re.compile('pkg_search_module\s*\(\s*[a-zA-Z0-9-_]+\s*(REQUIRED)?((\s+[^)\s]+)+)\s*\)', re.IGNORECASE)
139 findpackage_re = re.compile('find_package\s*\(\s*([a-zA-Z0-9-_]+)\s*.*', re.IGNORECASE)
140 checklib_re = re.compile('check_library_exists\s*\(\s*([^\s)]+)\s*.*', re.IGNORECASE)
141 include_re = re.compile('include\s*\(\s*([^)\s]*)\s*\)', re.IGNORECASE)
142 subdir_re = re.compile('add_subdirectory\s*\(\s*([^)\s]*)\s*([^)\s]*)\s*\)', re.IGNORECASE)
143 dep_re = re.compile('([^ ><=]+)( *[<>=]+ *[^ ><=]+)?')
144
145 def parse_cmake_file(fn, paths=None):
146 searchpaths = (paths or []) + [os.path.dirname(fn)]
147 logger.debug('Parsing file %s' % fn)
148 with open(fn, 'r') as f:
149 for line in f:
150 line = line.strip()
151 res = include_re.match(line)
152 if res:
153 includefn = bb.utils.which(':'.join(searchpaths), res.group(1))
154 if includefn:
155 parse_cmake_file(includefn, searchpaths)
156 else:
157 logger.debug('Unable to recurse into include file %s' % res.group(1))
158 continue
159 res = subdir_re.match(line)
160 if res:
161 subdirfn = os.path.join(os.path.dirname(fn), res.group(1), 'CMakeLists.txt')
162 if os.path.exists(subdirfn):
163 parse_cmake_file(subdirfn, searchpaths)
164 else:
165 logger.debug('Unable to recurse into subdirectory file %s' % subdirfn)
166 continue
167 res = proj_re.match(line)
168 if res:
169 extravalues['PN'] = res.group(1).split()[0]
170 continue
171 res = pkgcm_re.match(line)
172 if res:
173 res = dep_re.findall(res.group(2))
174 if res:
175 pcdeps.extend([x[0] for x in res])
176 inherits.append('pkgconfig')
177 continue
178 res = pkgsm_re.match(line)
179 if res:
180 res = dep_re.findall(res.group(2))
181 if res:
182 # Note: appending a tuple here!
183 item = tuple((x[0] for x in res))
184 if len(item) == 1:
185 item = item[0]
186 pcdeps.append(item)
187 inherits.append('pkgconfig')
188 continue
189 res = findpackage_re.match(line)
190 if res:
191 origpkg = res.group(1)
192 pkg = origpkg.lower()
193 if pkg == 'gettext':
194 inherits.append('gettext')
195 elif pkg == 'perl':
196 inherits.append('perlnative')
197 elif pkg == 'pkgconfig':
198 inherits.append('pkgconfig')
199 elif pkg == 'pythoninterp':
200 inherits.append('pythonnative')
201 elif pkg == 'pythonlibs':
202 inherits.append('python-dir')
203 else:
204 dep = cmake_pkgmap.get(pkg, None)
205 if dep:
206 deps.append(dep)
207 elif dep is None:
208 unmappedpkgs.append(origpkg)
209 continue
210 res = checklib_re.match(line)
211 if res:
212 lib = res.group(1)
213 if not lib.startswith('$'):
214 libdeps.append(lib)
215 if line.lower().startswith('useswig'):
216 deps.append('swig-native')
217 continue
218
219 parse_cmake_file(srcfiles[0])
220
221 if unmappedpkgs:
222 outlines.append('# NOTE: unable to map the following CMake package dependencies: %s' % ' '.join(unmappedpkgs))
223
224 RecipeHandler.handle_depends(libdeps, pcdeps, deps, outlines, values, tinfoil.config_data)
225
226 if inherits:
227 values['inherit'] = ' '.join(list(set(inherits)))
63 228
64 return values 229 return values
65 230