Skip to contentSkip to conversation

Add list of virtual packages to manual (branch yem/manual)

PATCH New Yann E. MORIN 2 participants 13 messages Jun 8, 2014

lore
Share & tools
lore
#0 lore raw

v3 cover Add list of virtual packages to manual (branch yem/manual)

From: "Yann E. MORIN" <[email protected]>

Hello All!

This series intends to add the list of virtual packages to the manual, for three reasons:

- for users that are told (in a comment in the menuconfig) that a package they need depends on a virtual package, to know what provider to select,

- for people writing a new provider for an existing virtual package to have a reference of which symbol to select and which package to provide in their Config.in and .mk files,

- for people writing a new package that depends on features provided by a virtual package to know what symbol to depend on.

The series starts with some preparatory changes and cleanups, then introduces a way to generate different forms of tables, then goes on by removing virtual packages from the current lists, and finally adds a new list with the virtual packages.

Pre-rendered manual available here:
http://ymorin.is-a-geek.org/download/tmp/buildroot/virtual-packages/manual/manual.html

Special thanks to Samuel and Maxime for their pythonistic help! :-)

Changes v2 -> v3:
- drop remaining 'both' instances (Samuel)

Changes RFC -> v2:
- saner API to formatter-functions (Samuel)
- more classical Python constructs for dicts and lambdas (Samuel)
- more accurate python-doc (Samuel)
- lota typoes (Samuel)

Regards,
Yann E. MORIN.

The following changes since commit ed1182641812986f529b2150635f1e93c799a419:

xserver_xorg-server: add support for xtensa architecture (2014-06-08 15:51:00 +0200)

are available in the git repository at:

git://gitorious.org/buildroot/buildroot.git yem/manual

for you to fetch changes up to e5d675da25e21b9b647172b947977d45da55c3eb:

docs/manual: add the virtual packages list (2014-06-08 16:07:30 +0200)

----------------------------------------------------------------
Yann E. MORIN (11):
package/cryptodev: make it behave more like other virtual packages package/jpeg: make it behave more like other virtual packages package/mesa3d: rename the prompt
support/scripts: prepare expanding the packages lists support/scripts: document args to _is_package() in gen-manual-lists support/scripts: prepare handling virtual packages in generated lists support/scripts: do not display virtual packages in generated lists support/scripts: who's responsible to decide what is a package support/scripts: introduce a symbol formatter to generate package lists support/scripts: generate a list of virtual packages docs/manual: add the virtual packages list

 docs/manual/adding-packages-directory.txt |  10 ++
 docs/manual/adding-packages-virtual.txt   |   6 +
 docs/manual/appendix.txt                  |   8 ++
 package/cryptodev/Config.in               |   4 +-
 package/jpeg/Config.in                    |   4 +-
 package/mesa3d/Config.in                  |   2 +-
 support/scripts/gen-manual-lists.py       | 217 ++++++++++++++++++++++++------
 7 files changed, 209 insertions(+), 42 deletions(-)
Signature · 6 lines
.-----------------.--------------------.------------------.--------------------.
|  Yann E. MORIN  | Real-Time Embedded | /"\ ASCII RIBBON | Erics' conspiracy: |
| +33 662 376 056 | Software  Designer | \ / CAMPAIGN     |  ___               |
| +33 223 225 172 `------------.-------:  X  AGAINST      |  \e/  There is no  |
| http://ymorin.is-a-geek.org/ | _/*\_ | / \ HTML MAIL    |   v   conspiracy.  |
'------------------------------^-------^------------------^--------------------'
#1 lore raw

PATCH v3 1/11 package/cryptodev: make it behave more like other virtual packages

From: "Yann E. MORIN" <[email protected]>

Currently, the virtual package cryptodev is a special virtual package, as it offers a choice for its implementation, rather than letting the user enable them manually.

In so doing, it defines its _HAS option as a 'def_bool y' rather than letting each implementation 'select' it.

Since we are going to generate a list of virtual packages and their providers, this defeats the heuristic used to find providers.

Coming with an alternate heuristic that also matches the cryptodev package is quite complex, so better and easier to make it look more like any other virtual package.

---
 package/cryptodev/Config.in | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
package/cryptodev/Config.in +3 -1
index 2407e04..9f9df02 100644
@@ -18,6 +18,7 @@ choice
 config BR2_PACKAGE_CRYPTODEV_LINUX
 	bool "cryptodev-linux"
 	depends on !BR2_microblaze
+	select BR2_PACKAGE_HAS_CRYPTODEV
 	help
 	  Cryptodev-linux is a device that allows access to Linux kernel
 	  cryptographic drivers; thus allowing userspace applications
@@ -27,6 +28,7 @@ config BR2_PACKAGE_CRYPTODEV_LINUX
 
 config BR2_PACKAGE_OCF_LINUX
 	bool "ocf-linux"
+	select BR2_PACKAGE_HAS_CRYPTODEV
 	help
 	  OCF-Linux is a Linux port of the OpenBSD/FreeBSD Cryptographic
 	  Framework (OCF). This port aims to bring full asynchronous HW/SW
@@ -38,7 +40,7 @@ config BR2_PACKAGE_OCF_LINUX
 endchoice
 
 config BR2_PACKAGE_HAS_CRYPTODEV
-	def_bool y
+	bool
 
 config BR2_PACKAGE_PROVIDES_CRYPTODEV
 	string
Signature · 1 line
1.8.3.2
#2 lore raw

PATCH v3 2/11 package/jpeg: make it behave more like other virtual packages

In reply to Yann E. MORIN

From: "Yann E. MORIN" <[email protected]>

Currently, the virtual package jpeg is a special virtual package, as it offers a choice for its implementation, rather than letting the user enable them manually.

In so doing, it defines its _HAS option as a 'def_bool y' rather than letting each implementation 'select' it.

Since we are going to generate a list of virtual packages and their providers, this defeats the heuristic used to find providers.

Coming with an alternate heuristic that also matches the jpeg package is quite complex, so better and easier to make it look more like any other virtual package.

---
 package/jpeg/Config.in | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
package/jpeg/Config.in +3 -1
index 3042d24..f337aeb 100644
@@ -13,6 +13,7 @@ choice
 
 config BR2_PACKAGE_LIBJPEG
 	bool "jpeg"
+	select BR2_PACKAGE_HAS_JPEG
 	help
 	  The ubiquitous C library for manipulating JPEG images.
 
@@ -20,6 +21,7 @@ config BR2_PACKAGE_LIBJPEG
 
 config BR2_PACKAGE_JPEG_TURBO
 	bool "jpeg-turbo"
+	select BR2_PACKAGE_HAS_JPEG
 	help
 	  Libjpeg-turbo is a derivative of libjpeg that uses SIMD
 	  instructions (MMX, SSE2, NEON) to accelerate baseline JPEG
@@ -31,7 +33,7 @@ config BR2_PACKAGE_JPEG_TURBO
 endchoice
 
 config BR2_PACKAGE_HAS_JPEG
-	def_bool y
+	bool
 
 config BR2_PACKAGE_PROVIDES_JPEG
 	string
Signature · 1 line
1.8.3.2
#3 lore raw

PATCH v3 3/11 package/mesa3d: rename the prompt

In reply to Yann E. MORIN

From: "Yann E. MORIN" <[email protected]>

Rename the prompt for mesa3d so that it matches what we usually do for prompts of packages: just name the package in lower case.

This will help generate nicer tables in the generated packages list, both in existing tables, and in the upcoming table of virtual packages.

---
 package/mesa3d/Config.in | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
package/mesa3d/Config.in +1 -1
index 06f2bc3..6621154 100644
@@ -1,5 +1,5 @@
 menuconfig BR2_PACKAGE_MESA3D
-	bool "Mesa 3D Graphics Library"
+	bool "mesa3d"
 	select BR2_PACKAGE_LIBDRM
 	select BR2_PACKAGE_EXPAT
 	select BR2_PACKAGE_HOST_LIBXML2_PYTHON
Signature · 1 line
1.8.3.2
#4 lore raw

PATCH v3 4/11 support/scripts: prepare expanding the packages lists

In reply to Yann E. MORIN

From: "Yann E. MORIN" <[email protected]>

Move to a function the code generating the package name from a symbol's name, to avoid code duplication.

This is not used currently, but will be in a subsequent patch.

---
 support/scripts/gen-manual-lists.py | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)
support/scripts/gen-manual-lists.py +10 -1
index 94f403e..aee2299 100644
@@ -245,7 +245,7 @@ class Buildroot:
         """
         if not self.re_pkg_prefix.match(symbol.get_name()):
             return False
-        pkg_name = re.sub("BR2_PACKAGE_(HOST_)?(.*)", r"\2", symbol.get_name())
+        pkg_name = self._get_pkg_name(symbol)
 
         pattern = "^(HOST_)?" + pkg_name + "$"
         pattern = re.sub("_", ".", pattern)
@@ -278,6 +278,15 @@ class Buildroot:
                 return True
         return False
 
+    def _get_pkg_name(self, symbol):
+        """ Return the package name of the specified symbol.
+
+        :param symbol:      The symbol to get the package name of
+
+        """
+
+        return re.sub("BR2_PACKAGE_(HOST_)?(.*)", r"\2", symbol.get_name())
+
     def _get_symbol_label(self, symbol, mark_deprecated=True):
         """ Return the label (a.k.a. prompt text) of the symbol.
 
Signature · 1 line
1.8.3.2
#5 lore raw

PATCH v3 5/11 support/scripts: document args to _is_package() in gen-manual-lists

In reply to Yann E. MORIN

From: "Yann E. MORIN" <[email protected]>

---
 support/scripts/gen-manual-lists.py | 2 ++
 1 file changed, 2 insertions(+)
support/scripts/gen-manual-lists.py +2 -0
index aee2299..b33fcf0 100644
@@ -242,6 +242,8 @@ class Buildroot:
         """ Return True if the symbol is a package or a host package, otherwise
         False.
 
+        :param symbol:  The symbol to check
+
         """
         if not self.re_pkg_prefix.match(symbol.get_name()):
             return False
Signature · 1 line
1.8.3.2
#6 lore raw

PATCH v3 6/11 support/scripts: prepare handling virtual packages in generated lists

In reply to Yann E. MORIN

From: "Yann E. MORIN" <[email protected]>

Prepare to tell apart real packages from virtual packages.

Currently, the code implicitly recognises only real packages, and discards virtual packages, because of the heuristic used to recognise whether a symbol is a package:

- for real package:
- symbols : BR2_PACKAGE_FOO
- .mk files: foo.mk
- for virtual packages:
- symbols : BR2_PACKAGE_HAS_FOO
- .mk files: foo.mk

The current heuristic is to check for each symbol if a corresponding .mk file exists, by stripping 'BR2_PACKAGE_' from the beginning of the symbol, converting the result to lowercase, and checking if a .mk file exists.

So, as a side effect, it completely misses the virtual packages [*], which is pretty nice since we get a list with only real packages that the user can indeed select and see in the menuconfig.

[*] Except for 'cryptodev' and 'jpeg' which are both virtual packages and normal packages. Except they are not normal packages, they are used to display a choice of the implementation to use. This case will be fixed in follow-up patches.

Since we'll soon need to also output the table of virtual packages, we need to teach the _is_package() function to recognise them as well.

This patch is the first step into that direction: it introduces a new function _is_real_package() that is just a wrapper to _is_package(), which gains a new parameter, being the type of packages to filter on.

No behavioural change is made in this patch, it is just a preparatory patch.

---
Changes RFC -> v2
- remove useless 'both' semantic (Samuel)
- document default value (Samuel)
- fix typoes (Samuel)

---
 support/scripts/gen-manual-lists.py | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)
support/scripts/gen-manual-lists.py +9 -3
index b33fcf0..e234ef1 100644
@@ -183,14 +183,14 @@ class Buildroot:
         'target-packages': {
             'filename': "package-list",
             'root_menu': "Target packages",
-            'filter': "_is_package",
+            'filter': "_is_real_package",
             'sorted': True,
             'sub_menu': True,
         },
         'host-packages': {
             'filename': "host-package-list",
             'root_menu': "Host utilities",
-            'filter': "_is_package",
+            'filter': "_is_real_package",
             'sorted': True,
             'sub_menu': False,
         },
@@ -238,11 +238,14 @@ class Buildroot:
         return bool([ symbol for x in symbol.get_referenced_symbols()
             if x.get_name().startswith(self._deprecated.get_name()) ])
 
-    def _is_package(self, symbol):
+    def _is_package(self, symbol, type='real'):
         """ Return True if the symbol is a package or a host package, otherwise
         False.
 
         :param symbol:  The symbol to check
+        :param type:    Limit to 'real' or 'virtual' types of packages,
+                        with 'real' being the default.
+                        Note: only 'real' is (implictly) handled for now
 
         """
         if not self.re_pkg_prefix.match(symbol.get_name()):
@@ -280,6 +283,9 @@ class Buildroot:
                 return True
         return False
 
+    def _is_real_package(self, symbol):
+        return self._is_package(symbol, 'real')
+
     def _get_pkg_name(self, symbol):
         """ Return the package name of the specified symbol.
 
Signature · 1 line
1.8.3.2
#7 lore raw

PATCH v3 7/11 support/scripts: do not display virtual packages in generated lists

In reply to Yann E. MORIN

From: "Yann E. MORIN" <[email protected]>

If a package has both a 'real' and a 'virtual' definition, consider it is a virtual package and do not display it in the generated package list.

This is the case for jpeg and cryptodev, that are virtual packages, but also real (but empty) packages used to provide a prompt to enable/disable a choice to select an implementation. In this case, we do not want to list the virtual packages, but only their implementations.

So, consider packages that are both real and virtual as virtual packages.

---
Changes v2 -> v3:
- drop remaining 'both' reference (Samuel)

Changes RFC -> v2:
- fix typoes (Samuel)

---
 support/scripts/gen-manual-lists.py | 21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)
support/scripts/gen-manual-lists.py +19 -2
index e234ef1..a3b5aea 100644
@@ -279,13 +279,30 @@ class Buildroot:
                     pkg_list.append(re.sub(r"(.*?)\.mk", r"\1", file_))
             setattr(self, "_package_list", pkg_list)
         for pkg in getattr(self, "_package_list"):
-            if pattern.match(pkg):
-                return True
+            if type == 'real':
+                if pattern.match(pkg) and not self._exists_virt_symbol(pkg):
+                    return True
         return False
 
     def _is_real_package(self, symbol):
         return self._is_package(symbol, 'real')
 
+    def _exists_virt_symbol(self, pkg_name):
+        """ Return True if a symbol exists that defines the package as
+        a virtual package, False otherwise
+
+        :param pkg_name:    The name of the package, for which to check if
+                            a symbol exists defining it as a virtual package
+
+        """
+        virt_pattern = "BR2_PACKAGE_HAS_" + pkg_name + "$"
+        virt_pattern = re.sub("_", ".", virt_pattern)
+        virt_pattern = re.compile(virt_pattern, re.IGNORECASE)
+        for sym in self.config:
+            if virt_pattern.match(sym.get_name()):
+                return True
+        return False
+
     def _get_pkg_name(self, symbol):
         """ Return the package name of the specified symbol.
 
Signature · 1 line
1.8.3.2
#8 lore raw

PATCH v3 8/11 support/scripts: who's responsible to decide what is a package

In reply to Yann E. MORIN

From: "Yann E. MORIN" <[email protected]>

When generating the package lists, the responsibility to decide what is actually a package symbol is currently split between the _is_package(), the get_symbol_subset() and the format_asciidoc_table() functions.

The two latter functions check that an item is really a symbol, and that is has a prompt.

While this is currently correct for real packages, this will no longer be the case when we also generate a list of virtual packages, since they do not have a prompt.

Move the responsibility to verify that a symbol is indeed a package symbol to _is_package(), so it's all in one place, and makes it easier to change for virtual packages.

---
Changes RFC -> v2:
- fix typoes (samuel)

---
 support/scripts/gen-manual-lists.py | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
support/scripts/gen-manual-lists.py +4 -4
index a3b5aea..352c08f 100644
@@ -75,8 +75,6 @@ def get_symbol_subset(root, filter_func):
         raise Exception(message)
     for item in get_items():
         if item.is_symbol():
-            if not item.prompts:
-                continue
             if not filter_func(item):
                 continue
             yield item
@@ -134,8 +132,6 @@ def format_asciidoc_table(root, get_label_func, filter_func=lambda x: True,
             return "| {0:<40}\n".format(item)
     lines = []
     for item in get_symbol_subset(root, filter_func):
-        if not item.is_symbol() or not item.prompts:
-            continue
         loc = get_symbol_parents(item, root, enable_choice=enable_choice)
         lines.append(_format_entry(get_label_func(item), loc, sub_menu))
     if sorted:
@@ -248,6 +244,10 @@ class Buildroot:
                         Note: only 'real' is (implictly) handled for now
 
         """
+        if not symbol.is_symbol():
+            return False
+        if type == 'real' and not symbol.prompts:
+            return False
         if not self.re_pkg_prefix.match(symbol.get_name()):
             return False
         pkg_name = self._get_pkg_name(symbol)
Signature · 1 line
1.8.3.2
#9 lore raw

PATCH v3 9/11 support/scripts: introduce a symbol formatter to generate package lists

In reply to Yann E. MORIN

From: "Yann E. MORIN" <[email protected]>

Currently, we can generate two different tables of packages:
- a single-column table with the symbols' prompts,
- a two-column table with the symbols' prompts and locations in the menuconfig.

For virtual packages, this is not enough, since we will have to display more columns, with different content:
- the virtual package name (but such symbols do not have a prompt)
- the symbol name
- the providers for the virtual package

So, instead of having a single function that knows how to generate any table, introduce a formatter function that is passed as argument to, and called by format_asciidoc_table(). Such formatter functions are responsible for providing:
- the layout of the table (number of columns, column arrangement),
- the formatted header line,
- a formatted line for a symbol.

What the formatter should ouput depends on its arguments:
- if none are passed, the layout is returned,
- if the header label is passed, it returns the formatted header line,
- otherwise, it returns the formatted line for a symbol.

Two formatter functions are introduced in this changeset, to replace the current 'sub_menu' feature:
- _format_symbol_prompt() to display a one-column table with only the symbols' prompts,
- _format_symbol_prompt_location() to display a two-column table with the symbols' prompts and locations.

This will help us to later introduce a new formatter to generate a table for virtual packages.

[Thanks to Samuel for his pythonistic help!]

---
Changes v2 -> v3:
- drop redundant 'is None' test, enhance exception message (Samuel)

Changes RFC -> v2:
- add explicit parameter to formatters to decide what to do, instead of relying on argument being None or not (Samuel)
- use traditional 'lambda x: x' instead of custom ones (Samuel)
- fix typoes (samuel)

---
 support/scripts/gen-manual-lists.py | 81 ++++++++++++++++++++++++-------------
 1 file changed, 52 insertions(+), 29 deletions(-)
support/scripts/gen-manual-lists.py +52 -29
index 352c08f..74d115d 100644
@@ -109,50 +109,33 @@ def get_symbol_parents(item, root=None, enable_choice=False):
 
 
 def format_asciidoc_table(root, get_label_func, filter_func=lambda x: True,
-                          enable_choice=False, sorted=True, sub_menu=True,
+                          format_func=lambda x: x,
+                          enable_choice=False, sorted=True,
                           item_label=None):
     """ Return the asciidoc formatted table of the items and their location.
 
     :param root:           Root item of the item subset
     :param get_label_func: Item's label getter function
     :param filter_func:    Filter function to apply on the item subset
+    :param format_func:    Function to format a symbol and the table header
     :param enable_choice:  Enable choices to appear as part of the item's
                            location
     :param sorted:         Flag to alphabetically sort the table
-    :param sub_menu:       Output the column with the sub-menu path
 
     """
-    def _format_entry(item, parents, sub_menu):
-        """ Format an asciidoc table entry.
 
-        """
-        if sub_menu:
-            return "| {0:<40} <| {1}\n".format(item, " -> ".join(parents))
-        else:
-            return "| {0:<40}\n".format(item)
     lines = []
     for item in get_symbol_subset(root, filter_func):
-        loc = get_symbol_parents(item, root, enable_choice=enable_choice)
-        lines.append(_format_entry(get_label_func(item), loc, sub_menu))
+        lines.append(format_func(what="symbol", symbol=item, root=root,
+                                 get_label_func=get_label_func,
+                                 enable_choice=enable_choice))
     if sorted:
         lines.sort(key=lambda x: x.lower())
-    if hasattr(root, "get_title"):
-        loc_label = get_symbol_parents(root, None, enable_choice=enable_choice)
-        loc_label += [root.get_title(), "..."]
-    else:
-        loc_label = ["Location"]
-    if not item_label:
-        item_label = "Items"
     table = ":halign: center\n\n"
-    if sub_menu:
-        width = "100%"
-        columns = "^1,4"
-    else:
-        width = "30%"
-        columns = "^1"
+    width, columns = format_func(what="layout")
     table = "[width=\"{0}\",cols=\"{1}\",options=\"header\"]\n".format(width, columns)
     table += "|===================================================\n"
-    table += _format_entry(item_label, loc_label, sub_menu)
+    table += format_func(what="header", header=item_label, root=root)
     table += "\n" + "".join(lines) + "\n"
     table += "|===================================================\n"
     return table
@@ -180,22 +163,22 @@ class Buildroot:
             'filename': "package-list",
             'root_menu': "Target packages",
             'filter': "_is_real_package",
+            'format': "_format_symbol_prompt_location",
             'sorted': True,
-            'sub_menu': True,
         },
         'host-packages': {
             'filename': "host-package-list",
             'root_menu': "Host utilities",
             'filter': "_is_real_package",
+            'format': "_format_symbol_prompt",
             'sorted': True,
-            'sub_menu': False,
         },
         'deprecated': {
             'filename': "deprecated-list",
             'root_menu': None,
             'filter': "_is_deprecated",
+            'format': "_format_symbol_prompt_location",
             'sorted': False,
-            'sub_menu': True,
         },
     }
 
@@ -324,6 +307,45 @@ class Buildroot:
             label += " *(deprecated)*"
         return label
 
+    def _format_symbol_prompt(self, what=None, symbol=None, root=None,
+                                    enable_choice=False, header=None,
+                                    get_label_func=lambda x: x):
+        if what == "layout":
+            return ( "30%", "^1" )
+
+        if what == "header":
+            return "| {0:<40}\n".format(header)
+
+        if what == "symbol":
+            return "| {0:<40}\n".format(get_label_func(symbol))
+
+        message = "Invalid argument 'what': '%s'\n" % str(what)
+        message += "Allowed values are: 'layout', 'header' and 'symbol'"
+        raise Exception(message)
+
+    def _format_symbol_prompt_location(self, what=None, symbol=None, root=None,
+                                             enable_choice=False, header=None,
+                                             get_label_func=lambda x: x):
+        if what == "layout":
+            return ( "100%", "^1,4" )
+
+        if what == "header":
+            if hasattr(root, "get_title"):
+                loc_label = get_symbol_parents(root, None, enable_choice=enable_choice)
+                loc_label += [root.get_title(), "..."]
+            else:
+                loc_label = ["Location"]
+            return "| {0:<40} <| {1}\n".format(header, " -> ".join(loc_label))
+
+        if what == "symbol":
+            parents = get_symbol_parents(symbol, root, enable_choice)
+            return "| {0:<40} <| {1}\n".format(get_label_func(symbol),
+                                               " -> ".join(parents))
+
+        message = "Invalid argument 'what': '%s'\n" % str(what)
+        message += "Allowed values are: 'layout', 'header' and 'symbol'"
+        raise Exception(message)
+
     def print_list(self, list_type, enable_choice=True, enable_deprecated=True,
                    dry_run=False, output=None):
         """ Print the requested list. If not dry run, then the list is
@@ -356,6 +378,7 @@ class Buildroot:
             root_item = self.config
         filter_ = getattr(self, list_config.get('filter'))
         filter_func = lambda x: filter_(x)
+        format_func = getattr(self, list_config.get('format'))
         if not enable_deprecated and list_type != "deprecated":
             filter_func = lambda x: filter_(x) and not self._is_deprecated(x)
         mark_depr = list_type != "deprecated"
@@ -364,9 +387,9 @@ class Buildroot:
 
         table = format_asciidoc_table(root_item, get_label,
                                       filter_func=filter_func,
+                                      format_func=format_func,
                                       enable_choice=enable_choice,
                                       sorted=list_config.get('sorted'),
-                                      sub_menu=list_config.get('sub_menu'),
                                       item_label=item_label)
 
         content = self.list_in.format(table=table)
Signature · 1 line
1.8.3.2
#10 lore raw

PATCH v3 10/11 support/scripts: generate a list of virtual packages

In reply to Yann E. MORIN

From: "Yann E. MORIN" <[email protected]>

Generate an asciidoc table that can be included in the manual, that lists the existing virtual packages, the corresponding symbols, and their providers (and sub-options thereof).

The core of this change is the addition of a new formatter for virtual packages. This formatter is a bit tricky, as it has to catter for a bunch of corner cases:
- provider is not a package, but is sub-options of a package
- such a sub-option may be itself 'select'-ed by one or more other sub-options
- legacy packages should not be considered as a provider

Those cases are real:
- sub-options of mesa3d provide EGL or GLES
- selected sub-options of mesa3d provide GL
- udev is a legacy package, but it provides udev

---
Changes v2 -> v3:
- drop redundant 'is None' test, enhance exception message (Samuel)

Changes RFC -> v2:
- fix disctionnaries to use usual quoteation marks (Samuel)
- rewrite _is_legacy_symbol() in a more pythonic way (samuel)
- avoid passing the 'br' object since we're only ever calling the functions as class members anyway (Samuel)
- fix typoes (Samuel)

---
 support/scripts/gen-manual-lists.py | 84 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 83 insertions(+), 1 deletion(-)
support/scripts/gen-manual-lists.py +83 -1
index 74d115d..69f4c7e 100644
@@ -173,6 +173,13 @@ class Buildroot:
             'format': "_format_symbol_prompt",
             'sorted': True,
         },
+        'virtual-packages': {
+            'filename': "virtual-package-list",
+            'root_menu': "Target packages",
+            'filter': "_is_virtual_package",
+            'format': "_format_symbol_virtual",
+            'sorted': True,
+        },
         'deprecated': {
             'filename': "deprecated-list",
             'root_menu': None,
@@ -231,6 +238,8 @@ class Buildroot:
             return False
         if type == 'real' and not symbol.prompts:
             return False
+        if type == 'virtual' and symbol.prompts:
+            return False
         if not self.re_pkg_prefix.match(symbol.get_name()):
             return False
         pkg_name = self._get_pkg_name(symbol)
@@ -265,11 +274,17 @@ class Buildroot:
             if type == 'real':
                 if pattern.match(pkg) and not self._exists_virt_symbol(pkg):
                     return True
+            if type == 'virtual':
+                if pattern.match('has_' + pkg):
+                    return True
         return False
 
     def _is_real_package(self, symbol):
         return self._is_package(symbol, 'real')
 
+    def _is_virtual_package(self, symbol):
+        return self._is_package(symbol, 'virtual')
+
     def _exists_virt_symbol(self, pkg_name):
         """ Return True if a symbol exists that defines the package as
         a virtual package, False otherwise
@@ -346,6 +361,71 @@ class Buildroot:
         message += "Allowed values are: 'layout', 'header' and 'symbol'"
         raise Exception(message)
 
+    def _format_symbol_virtual(self, what=None, symbol=None, root=None,
+                                     enable_choice=False, header=None,
+                                     get_label_func=lambda x: "?"):
+        def _symbol_is_legacy(symbol):
+            selects = [ s.get_name() for s in symbol.get_selected_symbols() ]
+            return ("BR2_LEGACY" in selects)
+
+        def _get_parent_package(sym):
+            if self._is_real_package(sym):
+                return None
+            # Trim the symbol name from its last component (separated with
+            # underscores), until we either find a symbol which is a real
+            # package, or until we have no component (i.e. just 'BR2')
+            name = sym.get_name()
+            while name != "BR2":
+                name = name.rsplit("_", 1)[0]
+                s = self.config.get_symbol(name)
+                if s is None:
+                    continue
+                if self._is_real_package(s):
+                    return s
+            return None
+
+        def _get_providers(config, symbol):
+            providers = list()
+            for sym in self.config:
+                if not sym.is_symbol():
+                    continue
+                selects = sym.get_selected_symbols()
+                if not selects:
+                    continue
+                for s in selects:
+                    if s == symbol:
+                        if _symbol_is_legacy(sym):
+                            continue
+                        if sym.prompts:
+                            l = self._get_symbol_label(sym,False)
+                            parent_pkg = _get_parent_package(sym)
+                            if parent_pkg is not None:
+                                l = self._get_symbol_label(parent_pkg, False) \
+                                  + " (w/ " + l + ")"
+                            providers.append(l)
+                        else:
+                            providers.extend(_get_providers(config,sym))
+            return providers
+
+        if what == "layout":
+            return ( "100%", "^1,4,4" )
+
+        if what == "header":
+            return "| {0:<20} <| {1:<32} <| Providers\n".format("Virtual packages", "Symbols")
+
+        if what == "symbol":
+            pkg = re.sub(r"^BR2_PACKAGE_HAS_(.+)$", r"\1", symbol.get_name())
+            providers = _get_providers(self.config, symbol)
+
+            return "| {0:<20} <| {1:<32} <| {2}\n".format(pkg.lower(),
+                                                          '+' + symbol.get_name() + '+',
+                                                          ", ".join(providers))
+
+        message = "Invalid argument 'what': '%s'\n" % str(what)
+        message += "Allowed values are: 'layout', 'header' and 'symbol'"
+        raise Exception(message)
+
+
     def print_list(self, list_type, enable_choice=True, enable_deprecated=True,
                    dry_run=False, output=None):
         """ Print the requested list. If not dry run, then the list is
@@ -414,7 +494,7 @@ class Buildroot:
 
 
 if __name__ == '__main__':
-    list_types = ['target-packages', 'host-packages', 'deprecated']
+    list_types = ['target-packages', 'host-packages', 'virtual-packages', 'deprecated']
     parser = ArgumentParser()
     parser.add_argument("list_type", nargs="?", choices=list_types,
                         help="""\
@@ -425,6 +505,8 @@ Generate the given list (generate all lists if unspecified)""")
                         help="Output target package file")
     parser.add_argument("--output-host", dest="output_host",
                         help="Output host package file")
+    parser.add_argument("--output-virtual", dest="output_virtual",
+                        help="Output virtual package file")
     parser.add_argument("--output-deprecated", dest="output_deprecated",
                         help="Output deprecated file")
     args = parser.parse_args()
Signature · 1 line
1.8.3.2
#11 lore raw

PATCH v3 11/11 docs/manual: add the virtual packages list

In reply to Yann E. MORIN

From: "Yann E. MORIN" <[email protected]>

Add the list of virtual packages as an appendix to the manual.

Also reference this list from appropriate locations elsewhere in the manual:

- in section 7.2.2. "Config.in file", after the existing explanations on dependencies on target and toolchain options, on a linux kernel, and on udev /dev management,

- in section 7.2.10. "Infrastructure for virtual packages", in the provider Config.in and .mk explanations, to have the list of existing symbols to select (in Config.in) and packages to provide (in .mk).

---
Note: a pre-rendered version of the manual with these modifications is available at:
http://ymorin.is-a-geek.org/download/tmp/buildroot/virtual-pacakges/manual/manual.html

---
 docs/manual/adding-packages-directory.txt | 10 ++++++++++
 docs/manual/adding-packages-virtual.txt   |  6 ++++++
 docs/manual/appendix.txt                  |  8 ++++++++
 3 files changed, 24 insertions(+)
docs/manual/adding-packages-directory.txt +10 -0
index 070718e..69b012c 100644
@@ -298,6 +298,16 @@ management, use this format:
 foo needs udev /dev management and a toolchain w/ featA, featB, featC
 --------------------------
 
+==== Dependencies on features provided by virtual packages
+
+Some features can be provided by more than one package, such as the
+openGL libraries.
+
+See xref:virtual-package-tutorial[] for more on the virtual packages.
+
+See xref:virtual-package-list[] for the symbols to depend on if your package
+depends on a feature provided by a virtual package.
+
 === The +.mk+ file
 
 [[adding-packages-mk]]
docs/manual/adding-packages-virtual.txt +6 -0
index 6326bb5..a5f17a2 100644
@@ -83,6 +83,9 @@ On line 3, we select +BR2_PACKAGE_HAS_SOMETHING_VIRTUAL+, and on line 11, we
 set the value of +BR2_PACKAGE_PROVIDES_SOMETHING_VIRTUAL+ to the name of the
 provider, but only if it is selected.
 
+See xref:virtual-package-list[] for the symbols to select if you implement
+a new provider for an existing virtual package.
+
 ==== Provider's +.mk+ file
 
 The +.mk+ file should also declare an additional variable
@@ -96,6 +99,9 @@ packages it is an implementation of:
 Of course, do not forget to add the proper build and runtime dependencies for
 this package!
 
+See xref:virtual-package-list[] for the names of virtual packages to provide
+if you implement a new provider for an existing virtual package.
+
 ==== Notes on depending on a virtual package
 
 When adding a package that requires a certain +FEATURE+ provided by a virtual
docs/manual/appendix.txt +8 -0
index 35328c6..3f95551 100644
@@ -14,6 +14,14 @@ include::makeusers-syntax.txt[]
 
 include::package-list.txt[]
 
+[[virtual-package-list]]
+== List of virtual packages
+
+These are the virtual packages known to +Buildroot+, with the
+corresponding symbols and providers.
+
+include::virtual-package-list.txt[]
+
 [[host-package-list]]
 == List of host utilities available in Buildroot
 
Signature · 1 line
1.8.3.2
#12 lore raw

v3 cover Add list of virtual packages to manual (branch yem/manual)

In reply to Yann E. MORIN

Dear Yann E. MORIN,

Quoted 11 lines · Yann E. MORIN

This series intends to add the list of virtual packages to the manual, for three reasons:

- for users that are told (in a comment in the menuconfig) that a package they need depends on a virtual package, to know what provider to select,

- for people writing a new provider for an existing virtual package to have a reference of which symbol to select and which package to provide in their Config.in and .mk files,

Quoted 7 lines

- for people writing a new package that depends on features provided by a virtual package to know what symbol to depend on.

The series starts with some preparatory changes and cleanups, then introduces a way to generate different forms of tables, then goes on by removing virtual packages from the current lists, and finally adds a new list with the virtual packages.

Thanks, series applied!

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com