diff options
author | Chris Larson <chris_larson@mentor.com> | 2010-03-19 17:22:19 -0700 |
---|---|---|
committer | Richard Purdie <rpurdie@linux.intel.com> | 2010-03-25 17:25:45 +0000 |
commit | c24424327409544807a781bba4e6f9a8e178dcce (patch) | |
tree | 5df97b6f8665f6cdf9a9698c05e2a98f58bd5975 | |
parent | cefeeb1aa30a9d8744a6ff9c51811ebc8d18c735 (diff) | |
download | poky-c24424327409544807a781bba4e6f9a8e178dcce.tar.gz |
Implement BBVERSIONS
This implements a feature similar to BBCLASSEXTEND, but for generating
multiple versions of a given recipe. For example: BBVERSIONS = "1.0 2.0 git".
In addition to the above, one can utilize [a-b] style patterns, and can have a
:<basever> postfix, which allows you to essentially name the range of
versions. Both the current version and the basever end up in OVERRIDES, and
the basever gets placed into the BPV variable. The default BPV, if none is
specified, is the original PV of the recipe, before bbversions processing.
In this way, you can do things like:
BBVERSIONS = "1.0.[0-6]:1.0.0+
1.0.[7-9]:1.0.7+"
SRC_URI_append_1.0.7+ = "file://some_extra_patch.patch;patch=1"
Or you can create a recipe per range, and name the recipe file as such: nano_1.0.7+.bb.
(Bitbake rev: 4ee9a56e16f1eb3c1649eaa3127b09ab0e93d1ec)
Signed-off-by: Chris Larson <chris_larson@mentor.com>
Signed-off-by: Richard Purdie <rpurdie@linux.intel.com>
-rw-r--r-- | bitbake/doc/manual/usermanual.xml | 14 | ||||
-rw-r--r-- | bitbake/lib/bb/cache.py | 10 | ||||
-rw-r--r-- | bitbake/lib/bb/parse/ast.py | 114 | ||||
-rw-r--r-- | bitbake/lib/bb/parse/parse_py/BBHandler.py | 26 |
4 files changed, 134 insertions, 30 deletions
diff --git a/bitbake/doc/manual/usermanual.xml b/bitbake/doc/manual/usermanual.xml index 29cdf97a0a..6424a7ebd9 100644 --- a/bitbake/doc/manual/usermanual.xml +++ b/bitbake/doc/manual/usermanual.xml | |||
@@ -228,6 +228,18 @@ This event handler gets called every time an event is triggered. A global variab | |||
228 | method one can get the name of the triggered event.</para><para>The above event handler prints the name | 228 | method one can get the name of the triggered event.</para><para>The above event handler prints the name |
229 | of the event and the content of the <varname>FILE</varname> variable.</para> | 229 | of the event and the content of the <varname>FILE</varname> variable.</para> |
230 | </section> | 230 | </section> |
231 | <section> | ||
232 | <title>Variants</title> | ||
233 | <para>Two Bitbake features exist to facilitate the creation of multiple buildable incarnations from a single recipe file.</para> | ||
234 | <para>The first is <varname>BBCLASSEXTEND</varname>. This variable is a space separated list of classes to utilize to "extend" the recipe for each variant. As an example, setting <screen>BBCLASSEXTEND = "native"</screen> results in a second incarnation of the current recipe being available. This second incarantion will have the "native" class inherited.</para> | ||
235 | <para>The second feature is <varname>BBVERSIONS</varname>. This variable allows a single recipe to be able to build multiple versions of a project from a single recipe file, and allows you to specify conditional metadata (using the <varname>OVERRIDES</varname> mechanism) for a single version, or an optionally named range of versions:</para> | ||
236 | <para><screen>BBVERSIONS = "1.0 2.0 git" | ||
237 | SRC_URI_git = "git://someurl/somepath.git"</screen></para> | ||
238 | <para><screen>BBVERSIONS = "1.0.[0-6]:1.0.0+ \ | ||
239 | 1.0.[7-9]:1.0.7+" | ||
240 | SRC_URI_append_1.0.7+ = "file://some_patch_which_the_new_versions_need.patch;patch=1"</screen></para> | ||
241 | <para>Note that the name of the range will default to the original version of the recipe, so given OE, a recipe file of foo_1.0.0+.bb will default the name of its versions to 1.0.0+. This is useful, as the range name is not only placed into overrides, it's also made available for the metadata to use in the form of the <varname>BPV</varname> variable, for use in file:// search paths (<varname>FILESPATH</varname>).</para> | ||
242 | </section> | ||
231 | </section> | 243 | </section> |
232 | <section> | 244 | <section> |
233 | <title>Dependency Handling</title> | 245 | <title>Dependency Handling</title> |
@@ -270,7 +282,7 @@ of the event and the content of the <varname>FILE</varname> variable.</para> | |||
270 | <section> | 282 | <section> |
271 | <title>Configuration Files</title> | 283 | <title>Configuration Files</title> |
272 | <para>The first of the classifications of metadata in BitBake is configuration metadata. This metadata is global, and therefore affects <emphasis>all</emphasis> packages and tasks which are executed.</para> | 284 | <para>The first of the classifications of metadata in BitBake is configuration metadata. This metadata is global, and therefore affects <emphasis>all</emphasis> packages and tasks which are executed.</para> |
273 | <papa>Bitbake will first search the current working directory for an optional "conf/bblayers.conf" configuration file. This file is expected to contain a BBLAYERS variable which is a space delimited list of 'layer' directories. For each directory in this list a "conf/layer.conf" file will be searched for and parsed with the LAYERDIR variable being set to the directory where the layer was found. The idea is these files will setup BBPATH and other variables correctly for a given build directory automatically for the user.</para> | 285 | <para>Bitbake will first search the current working directory for an optional "conf/bblayers.conf" configuration file. This file is expected to contain a BBLAYERS variable which is a space delimited list of 'layer' directories. For each directory in this list a "conf/layer.conf" file will be searched for and parsed with the LAYERDIR variable being set to the directory where the layer was found. The idea is these files will setup BBPATH and other variables correctly for a given build directory automatically for the user.</para> |
274 | <para>Bitbake will then expect to find 'conf/bitbake.conf' somewhere in the user specified <envar>BBPATH</envar>. That configuration file generally has include directives to pull in any other metadata (generally files specific to architecture, machine, <emphasis>local</emphasis> and so on.</para> | 286 | <para>Bitbake will then expect to find 'conf/bitbake.conf' somewhere in the user specified <envar>BBPATH</envar>. That configuration file generally has include directives to pull in any other metadata (generally files specific to architecture, machine, <emphasis>local</emphasis> and so on.</para> |
275 | <para>Only variable definitions and include directives are allowed in .conf files.</para> | 287 | <para>Only variable definitions and include directives are allowed in .conf files.</para> |
276 | </section> | 288 | </section> |
diff --git a/bitbake/lib/bb/cache.py b/bitbake/lib/bb/cache.py index 43091daa26..9a962ecc74 100644 --- a/bitbake/lib/bb/cache.py +++ b/bitbake/lib/bb/cache.py | |||
@@ -143,8 +143,8 @@ class Cache: | |||
143 | if dep not in self.depends_cache[fn]["__depends"]: | 143 | if dep not in self.depends_cache[fn]["__depends"]: |
144 | self.depends_cache[fn]["__depends"].append(dep) | 144 | self.depends_cache[fn]["__depends"].append(dep) |
145 | 145 | ||
146 | # Make sure BBCLASSEXTEND always makes the cache too | 146 | # Make sure the variants always make it into the cache too |
147 | self.getVar('BBCLASSEXTEND', virtualfn, True) | 147 | self.getVar('__VARIANTS', virtualfn, True) |
148 | 148 | ||
149 | self.depends_cache[virtualfn]["CACHETIMESTAMP"] = bb.parse.cached_mtime(fn) | 149 | self.depends_cache[virtualfn]["CACHETIMESTAMP"] = bb.parse.cached_mtime(fn) |
150 | 150 | ||
@@ -199,7 +199,7 @@ class Cache: | |||
199 | self.cacheValidUpdate(fn) | 199 | self.cacheValidUpdate(fn) |
200 | 200 | ||
201 | if self.cacheValid(fn): | 201 | if self.cacheValid(fn): |
202 | multi = self.getVar('BBCLASSEXTEND', fn, True) | 202 | multi = self.getVar('__VARIANTS', fn, True) |
203 | for cls in (multi or "").split() + [""]: | 203 | for cls in (multi or "").split() + [""]: |
204 | virtualfn = self.realfn2virtual(fn, cls) | 204 | virtualfn = self.realfn2virtual(fn, cls) |
205 | if self.depends_cache[virtualfn]["__SKIPPED"]: | 205 | if self.depends_cache[virtualfn]["__SKIPPED"]: |
@@ -292,7 +292,7 @@ class Cache: | |||
292 | self.clean[fn] = "" | 292 | self.clean[fn] = "" |
293 | 293 | ||
294 | # Mark extended class data as clean too | 294 | # Mark extended class data as clean too |
295 | multi = self.getVar('BBCLASSEXTEND', fn, True) | 295 | multi = self.getVar('__VARIANTS', fn, True) |
296 | for cls in (multi or "").split(): | 296 | for cls in (multi or "").split(): |
297 | virtualfn = self.realfn2virtual(fn, cls) | 297 | virtualfn = self.realfn2virtual(fn, cls) |
298 | self.clean[virtualfn] = "" | 298 | self.clean[virtualfn] = "" |
@@ -443,7 +443,7 @@ class Cache: | |||
443 | 443 | ||
444 | # Touch this to make sure its in the cache | 444 | # Touch this to make sure its in the cache |
445 | self.getVar('__BB_DONT_CACHE', file_name, True) | 445 | self.getVar('__BB_DONT_CACHE', file_name, True) |
446 | self.getVar('BBCLASSEXTEND', file_name, True) | 446 | self.getVar('__VARIANTS', file_name, True) |
447 | 447 | ||
448 | def load_bbfile( self, bbfile , config): | 448 | def load_bbfile( self, bbfile , config): |
449 | """ | 449 | """ |
diff --git a/bitbake/lib/bb/parse/ast.py b/bitbake/lib/bb/parse/ast.py index 70a69b8d14..59aa44bee0 100644 --- a/bitbake/lib/bb/parse/ast.py +++ b/bitbake/lib/bb/parse/ast.py | |||
@@ -22,9 +22,11 @@ | |||
22 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 22 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
23 | 23 | ||
24 | import bb, re, string | 24 | import bb, re, string |
25 | from itertools import chain | ||
25 | 26 | ||
26 | __word__ = re.compile(r"\S+") | 27 | __word__ = re.compile(r"\S+") |
27 | __parsed_methods__ = bb.methodpool.get_parsed_dict() | 28 | __parsed_methods__ = bb.methodpool.get_parsed_dict() |
29 | _bbversions_re = re.compile(r"\[(?P<from>[0-9]+)-(?P<to>[0-9]+)\]") | ||
28 | 30 | ||
29 | class StatementGroup(list): | 31 | class StatementGroup(list): |
30 | def eval(self, data): | 32 | def eval(self, data): |
@@ -335,3 +337,115 @@ def finalise(fn, d): | |||
335 | 337 | ||
336 | bb.event.fire(bb.event.RecipeParsed(fn), d) | 338 | bb.event.fire(bb.event.RecipeParsed(fn), d) |
337 | 339 | ||
340 | def _create_variants(datastores, names, function): | ||
341 | def create_variant(name, orig_d, arg = None): | ||
342 | new_d = bb.data.createCopy(orig_d) | ||
343 | function(arg or name, new_d) | ||
344 | datastores[name] = new_d | ||
345 | |||
346 | for variant, variant_d in datastores.items(): | ||
347 | for name in names: | ||
348 | if not variant: | ||
349 | # Based on main recipe | ||
350 | create_variant(name, variant_d) | ||
351 | else: | ||
352 | create_variant("%s-%s" % (variant, name), variant_d, name) | ||
353 | |||
354 | def _expand_versions(versions): | ||
355 | def expand_one(version, start, end): | ||
356 | for i in xrange(start, end + 1): | ||
357 | ver = _bbversions_re.sub(str(i), version, 1) | ||
358 | yield ver | ||
359 | |||
360 | versions = iter(versions) | ||
361 | while True: | ||
362 | try: | ||
363 | version = versions.next() | ||
364 | except StopIteration: | ||
365 | break | ||
366 | |||
367 | range_ver = _bbversions_re.search(version) | ||
368 | if not range_ver: | ||
369 | yield version | ||
370 | else: | ||
371 | newversions = expand_one(version, int(range_ver.group("from")), | ||
372 | int(range_ver.group("to"))) | ||
373 | versions = chain(newversions, versions) | ||
374 | |||
375 | def multi_finalize(fn, d): | ||
376 | safe_d = d | ||
377 | |||
378 | d = bb.data.createCopy(safe_d) | ||
379 | try: | ||
380 | finalise(fn, d) | ||
381 | except bb.parse.SkipPackage: | ||
382 | bb.data.setVar("__SKIPPED", True, d) | ||
383 | datastores = {"": safe_d} | ||
384 | |||
385 | versions = (d.getVar("BBVERSIONS", True) or "").split() | ||
386 | if versions: | ||
387 | pv = orig_pv = d.getVar("PV", True) | ||
388 | baseversions = {} | ||
389 | |||
390 | def verfunc(ver, d, pv_d = None): | ||
391 | if pv_d is None: | ||
392 | pv_d = d | ||
393 | |||
394 | overrides = d.getVar("OVERRIDES", True).split(":") | ||
395 | pv_d.setVar("PV", ver) | ||
396 | overrides.append(ver) | ||
397 | bpv = baseversions.get(ver) or orig_pv | ||
398 | pv_d.setVar("BPV", bpv) | ||
399 | overrides.append(bpv) | ||
400 | d.setVar("OVERRIDES", ":".join(overrides)) | ||
401 | |||
402 | versions = list(_expand_versions(versions)) | ||
403 | for pos, version in enumerate(list(versions)): | ||
404 | try: | ||
405 | pv, bpv = version.split(":", 2) | ||
406 | except ValueError: | ||
407 | pass | ||
408 | else: | ||
409 | versions[pos] = pv | ||
410 | baseversions[pv] = bpv | ||
411 | |||
412 | if pv in versions and not baseversions.get(pv): | ||
413 | versions.remove(pv) | ||
414 | else: | ||
415 | pv = versions.pop() | ||
416 | |||
417 | # This is necessary because our existing main datastore | ||
418 | # has already been finalized with the old PV, we need one | ||
419 | # that's been finalized with the new PV. | ||
420 | d = bb.data.createCopy(safe_d) | ||
421 | verfunc(pv, d, safe_d) | ||
422 | try: | ||
423 | finalise(fn, d) | ||
424 | except bb.parse.SkipPackage: | ||
425 | bb.data.setVar("__SKIPPED", True, d) | ||
426 | |||
427 | _create_variants(datastores, versions, verfunc) | ||
428 | |||
429 | extended = d.getVar("BBCLASSEXTEND", True) or "" | ||
430 | if extended: | ||
431 | pn = d.getVar("PN", True) | ||
432 | def extendfunc(name, d): | ||
433 | d.setVar("PN", "%s-%s" % (pn, name)) | ||
434 | bb.parse.BBHandler.inherit([name], d) | ||
435 | |||
436 | safe_d.setVar("BBCLASSEXTEND", extended) | ||
437 | _create_variants(datastores, extended.split(), extendfunc) | ||
438 | |||
439 | for variant, variant_d in datastores.items(): | ||
440 | if variant: | ||
441 | try: | ||
442 | finalise(fn, variant_d) | ||
443 | except bb.parse.SkipPackage: | ||
444 | bb.data.setVar("__SKIPPED", True, variant_d) | ||
445 | |||
446 | if len(datastores) > 1: | ||
447 | variants = filter(None, datastores.keys()) | ||
448 | safe_d.setVar("__VARIANTS", " ".join(variants)) | ||
449 | |||
450 | datastores[""] = d | ||
451 | return datastores | ||
diff --git a/bitbake/lib/bb/parse/parse_py/BBHandler.py b/bitbake/lib/bb/parse/parse_py/BBHandler.py index 4641c13d9c..262c883c95 100644 --- a/bitbake/lib/bb/parse/parse_py/BBHandler.py +++ b/bitbake/lib/bb/parse/parse_py/BBHandler.py | |||
@@ -152,30 +152,8 @@ def handle(fn, d, include): | |||
152 | classes.remove(__classname__) | 152 | classes.remove(__classname__) |
153 | else: | 153 | else: |
154 | if include == 0: | 154 | if include == 0: |
155 | safe_d = d | 155 | return ast.multi_finalize(fn, d) |
156 | d = bb.data.createCopy(safe_d) | 156 | |
157 | try: | ||
158 | ast.finalise(fn, d) | ||
159 | except bb.parse.SkipPackage: | ||
160 | bb.data.setVar("__SKIPPED", True, d) | ||
161 | darray = {"": d} | ||
162 | |||
163 | extended = bb.data.getVar("BBCLASSEXTEND", d, True) | ||
164 | if extended: | ||
165 | bb.data.setVar("BBCLASSEXTEND", extended, safe_d) | ||
166 | |||
167 | for cls in (extended or "").split(): | ||
168 | pn = data.getVar('PN', d, True) | ||
169 | variant_d = bb.data.createCopy(safe_d) | ||
170 | data.setVar('PN', pn + '-' + cls, variant_d) | ||
171 | inherit([cls], variant_d) | ||
172 | try: | ||
173 | ast.finalise(fn, variant_d) | ||
174 | except bb.parse.SkipPackage: | ||
175 | bb.data.setVar("__SKIPPED", True, variant_d) | ||
176 | darray[cls] = variant_d | ||
177 | return darray | ||
178 | |||
179 | if oldfile: | 157 | if oldfile: |
180 | bb.data.setVar("FILE", oldfile, d) | 158 | bb.data.setVar("FILE", oldfile, d) |
181 | 159 | ||