diff mbox series

bitbake: bblayers/query: Add --show-variants option to display BBCLASSEXTEND variants

Message ID 20251024164008.4753-1-osama.abdelkader@gmail.com
State New
Headers show
Series bitbake: bblayers/query: Add --show-variants option to display BBCLASSEXTEND variants | expand

Commit Message

Osama Abdelkader Oct. 24, 2025, 4:40 p.m. UTC
The bitbake-layers show-recipes command was hiding BBCLASSEXTEND recipe
variants (e.g., devupstream, nativesdk, cross-canadian) by design, to
avoid clutter in the output. However, this made it impossible to see
recipes like linux-firmware's devupstream variant which uses git snapshots
instead of release tarballs.

This patch adds a new --show-variants (-v) option to show-recipes that
allows users to view all BBCLASSEXTEND variants when needed, while
maintaining the default behavior of hiding them for a cleaner output.

Example usage:
  bitbake-layers show-recipes -v linux-firmware

This will now show both:
  - Base version: 1:20251011
  - Devupstream version: 1:20251011+git

Signed-off-by: Osama Abdelkader <osama.abdelkader@gmail.com>
---
 bitbake/lib/bblayers/query.py | 23 ++++++++++++++++-------
 1 file changed, 16 insertions(+), 7 deletions(-)

Comments

Peter Kjellerstedt Oct. 25, 2025, 12:48 a.m. UTC | #1
> -----Original Message-----
> From: openembedded-core@lists.openembedded.org <openembedded-core@lists.openembedded.org> On Behalf Of Osama Abdelkader via lists.openembedded.org
> Sent: den 24 oktober 2025 18:40
> To: openembedded-core@lists.openembedded.org; ross.burton@arm.com
> Cc: Osama Abdelkader <osama.abdelkader@gmail.com>
> Subject: [OE-core] [PATCH] bitbake: bblayers/query: Add --show-variants option to display BBCLASSEXTEND variants

This should go to the bitbake-devel@lists.openembedded.org list instead.
And drop the "bitbake:" prefix from the subject. It is added by 
combo-layer when updating the poky repository.

> 
> The bitbake-layers show-recipes command was hiding BBCLASSEXTEND recipe
> variants (e.g., devupstream, nativesdk, cross-canadian) by design, to
> avoid clutter in the output. However, this made it impossible to see
> recipes like linux-firmware's devupstream variant which uses git snapshots
> instead of release tarballs.
> 
> This patch adds a new --show-variants (-v) option to show-recipes that
> allows users to view all BBCLASSEXTEND variants when needed, while
> maintaining the default behavior of hiding them for a cleaner output.
> 
> Example usage:
>   bitbake-layers show-recipes -v linux-firmware
> 
> This will now show both:
>   - Base version: 1:20251011
>   - Devupstream version: 1:20251011+git
> 
> Signed-off-by: Osama Abdelkader <osama.abdelkader@gmail.com>
> ---
>  bitbake/lib/bblayers/query.py | 23 ++++++++++++++++-------
>  1 file changed, 16 insertions(+), 7 deletions(-)
> 
> diff --git a/bitbake/lib/bblayers/query.py b/bitbake/lib/bblayers/query.py
> index eb7cb465b4..11341d5d53 100644
> --- a/bitbake/lib/bblayers/query.py
> +++ b/bitbake/lib/bblayers/query.py
> @@ -52,7 +52,7 @@ layer, with the preferred version first. Note that skipped recipes that
>  are overlayed will also be listed, with a " (skipped)" suffix.
>  """
> 
> -        items_listed = self.list_recipes('Overlayed recipes', None, True, args.same_version, args.filenames, False, True, None, False, None, args.mc)
> +        items_listed = self.list_recipes('Overlayed recipes', None, True, args.same_version, args.filenames, False, True, None, False, None, args.mc, False)

Since False is the default for show_variants, there is no add it 
here explicitly.

> 
>          # Check for overlayed .bbclass files
>          classes = collections.defaultdict(list)
> @@ -119,9 +119,9 @@ skipped recipes will also be listed, with a " (skipped)" suffix.
>              title = 'Matching recipes:'
>          else:
>              title = 'Available recipes:'
> -        self.list_recipes(title, args.pnspec, False, False, args.filenames, args.recipes_only, args.multiple, args.layer, args.bare, inheritlist, args.mc)
> +        self.list_recipes(title, args.pnspec, False, False, args.filenames, args.recipes_only, args.multiple, args.layer, args.bare, inheritlist, args.mc, args.show_variants)
> 
> -    def list_recipes(self, title, pnspec, show_overlayed_only, show_same_ver_only, show_filenames, show_recipes_only, show_multi_provider_only, selected_layer, bare, inherits, mc):
> +    def list_recipes(self, title, pnspec, show_overlayed_only, show_same_ver_only, show_filenames, show_recipes_only, show_multi_provider_only, selected_layer, bare, inherits, mc, show_variants=False):
>          if inherits:
>              bbpath = str(self.tinfoil.config_data.getVar('BBPATH'))
>              for classname in inherits:
> @@ -203,8 +203,10 @@ skipped recipes will also be listed, with a " (skipped)" suffix.
>                  # We only display once per recipe, we should prefer non extended versions of the
>                  # recipe if present (so e.g. in OpenEmbedded, openssl rather than nativesdk-openssl
>                  # which would otherwise sort first).
> +                # However, if show_variants is True, we show all BBCLASSEXTEND variants.
>                  if realfn[1] and realfn[0] in self.tinfoil.cooker.recipecaches[mc].pkg_fn:
> -                    continue
> +                    if not show_variants:
> +                        continue
> 
>                  if inherits:
>                      matchcount = 0
> @@ -229,7 +231,11 @@ skipped recipes will also be listed, with a " (skipped)" suffix.
>                      for prov in allproviders[p]:
>                          provfile = bb.cache.virtualfn2realfn(prov[1])[0]
>                          provlayer = self.get_file_layer(provfile)
> -                        provs.append((provfile, provlayer, prov[0]))
> +                        # When show_variants is True, use the virtual filename to distinguish BBCLASSEXTEND variants
> +                        if show_variants:
> +                            provs.append((prov[1], provlayer, prov[0]))
> +                        else:
> +                            provs.append((provfile, provlayer, prov[0]))
>                          if provlayer != preflayer:
>                              multilayer = True
>                          if prov[0] != pref[0]:
> @@ -238,10 +244,12 @@ skipped recipes will also be listed, with a " (skipped)" suffix.
>                          if not items_listed:
>                              logger.plain('=== %s ===' % title)
>                              items_listed = True
> +                        # When show_variants is True, use the virtual filename for preference check
> +                        pref_cmp_file = pref[1] if show_variants else preffile
>                          print_item(preffile, p, self.version_str(pref[0][0], pref[0][1]), preflayer, True)
>                          for (provfile, provlayer, provver) in provs:
> -                            if provfile != preffile:
> -                                print_item(provfile, p, self.version_str(provver[0], provver[1]), provlayer, False)
> +                            if provfile != pref_cmp_file:
> +                                print_item(bb.cache.virtualfn2realfn(provfile)[0] if show_variants else provfile, p, self.version_str(provver[0], provver[1]), provlayer, False)
>                          # Ensure we don't show two entries for BBCLASSEXTENDed recipes
>                          preffiles.append(preffile)
> 
> @@ -530,6 +538,7 @@ NOTE: .bbappend files can impact the dependencies.
>          parser_show_recipes.add_argument('-i', '--inherits', help='only list recipes that inherit the named class(es) - separate multiple classes using , (without spaces)', metavar='CLASS', default='')
>          parser_show_recipes.add_argument('-l', '--layer', help='only list recipes from the selected layer', default='')
>          parser_show_recipes.add_argument('-b', '--bare', help='output just names without the "(skipped)" marker', action='store_true')
> +        parser_show_recipes.add_argument('-v', '--show-variants', help='show all BBCLASSEXTEND recipe variants (e.g., devupstream, nativesdk)', action='store_true')
>          parser_show_recipes.add_argument('--mc', help='use specified multiconfig', default='')
>          parser_show_recipes.add_argument('pnspec', nargs='*', help='optional recipe name specification (wildcards allowed, enclose in quotes to avoid shell expansion)')
> 
> --
> 2.43.0

//Peter
Adrian Freihofer Dec. 8, 2025, 5:28 p.m. UTC | #2
On Fri, 2025-10-24 at 19:40 +0300, Osama Abdelkader via
lists.openembedded.org wrote:
> The bitbake-layers show-recipes command was hiding BBCLASSEXTEND
> recipe
> variants (e.g., devupstream, nativesdk, cross-canadian) by design, to
> avoid clutter in the output. However, this made it impossible to see
> recipes like linux-firmware's devupstream variant which uses git
> snapshots
> instead of release tarballs.
> 
> This patch adds a new --show-variants (-v) option to show-recipes
> that
> allows users to view all BBCLASSEXTEND variants when needed, while
> maintaining the default behavior of hiding them for a cleaner output.
> 
> Example usage:
>   bitbake-layers show-recipes -v linux-firmware
> 
> This will now show both:
>   - Base version: 1:20251011
>   - Devupstream version: 1:20251011+git
> 
> Signed-off-by: Osama Abdelkader <osama.abdelkader@gmail.com>
> ---
>  bitbake/lib/bblayers/query.py | 23 ++++++++++++++++-------
>  1 file changed, 16 insertions(+), 7 deletions(-)
> 
> diff --git a/bitbake/lib/bblayers/query.py
> b/bitbake/lib/bblayers/query.py
> index eb7cb465b4..11341d5d53 100644
> --- a/bitbake/lib/bblayers/query.py
> +++ b/bitbake/lib/bblayers/query.py
> @@ -52,7 +52,7 @@ layer, with the preferred version first. Note that
> skipped recipes that
>  are overlayed will also be listed, with a " (skipped)" suffix.
>  """
>  
> -        items_listed = self.list_recipes('Overlayed recipes', None,
> True, args.same_version, args.filenames, False, True, None, False,
> None, args.mc)
> +        items_listed = self.list_recipes('Overlayed recipes', None,
> True, args.same_version, args.filenames, False, True, None, False,
> None, args.mc, False)
>  
>          # Check for overlayed .bbclass files
>          classes = collections.defaultdict(list)
> @@ -119,9 +119,9 @@ skipped recipes will also be listed, with a "
> (skipped)" suffix.
>              title = 'Matching recipes:'
>          else:
>              title = 'Available recipes:'
> -        self.list_recipes(title, args.pnspec, False, False,
> args.filenames, args.recipes_only, args.multiple, args.layer,
> args.bare, inheritlist, args.mc)
> +        self.list_recipes(title, args.pnspec, False, False,
> args.filenames, args.recipes_only, args.multiple, args.layer,
> args.bare, inheritlist, args.mc, args.show_variants)
>  
> -    def list_recipes(self, title, pnspec, show_overlayed_only,
> show_same_ver_only, show_filenames, show_recipes_only,
> show_multi_provider_only, selected_layer, bare, inherits, mc):
> +    def list_recipes(self, title, pnspec, show_overlayed_only,
> show_same_ver_only, show_filenames, show_recipes_only,
> show_multi_provider_only, selected_layer, bare, inherits, mc,
> show_variants=False):
>          if inherits:
>              bbpath = str(self.tinfoil.config_data.getVar('BBPATH'))
>              for classname in inherits:
> @@ -203,8 +203,10 @@ skipped recipes will also be listed, with a "
> (skipped)" suffix.
>                  # We only display once per recipe, we should prefer
> non extended versions of the
>                  # recipe if present (so e.g. in OpenEmbedded,
> openssl rather than nativesdk-openssl
>                  # which would otherwise sort first).
> +                # However, if show_variants is True, we show all
> BBCLASSEXTEND variants.
>                  if realfn[1] and realfn[0] in
> self.tinfoil.cooker.recipecaches[mc].pkg_fn:
> -                    continue
> +                    if not show_variants:
> +                        continue
>  
>                  if inherits:
>                      matchcount = 0
> @@ -229,7 +231,11 @@ skipped recipes will also be listed, with a "
> (skipped)" suffix.
>                      for prov in allproviders[p]:
>                          provfile =
> bb.cache.virtualfn2realfn(prov[1])[0]
>                          provlayer = self.get_file_layer(provfile)
> -                        provs.append((provfile, provlayer, prov[0]))
> +                        # When show_variants is True, use the
> virtual filename to distinguish BBCLASSEXTEND variants
> +                        if show_variants:
> +                            provs.append((prov[1], provlayer,
> prov[0]))
> +                        else:
> +                            provs.append((provfile, provlayer,
> prov[0]))
>                          if provlayer != preflayer:
>                              multilayer = True
>                          if prov[0] != pref[0]:
> @@ -238,10 +244,12 @@ skipped recipes will also be listed, with a "
> (skipped)" suffix.
>                          if not items_listed:
>                              logger.plain('=== %s ===' % title)
>                              items_listed = True
> +                        # When show_variants is True, use the
> virtual filename for preference check
> +                        pref_cmp_file = pref[1] if show_variants
> else preffile
>                          print_item(preffile, p,
> self.version_str(pref[0][0], pref[0][1]), preflayer, True)
>                          for (provfile, provlayer, provver) in provs:
> -                            if provfile != preffile:
> -                                print_item(provfile, p,
> self.version_str(provver[0], provver[1]), provlayer, False)
> +                            if provfile != pref_cmp_file:
> +                               
> print_item(bb.cache.virtualfn2realfn(provfile)[0] if show_variants
> else provfile, p, self.version_str(provver[0], provver[1]),
> provlayer, False)
>                          # Ensure we don't show two entries for
> BBCLASSEXTENDed recipes
>                          preffiles.append(preffile)
>  
> @@ -530,6 +538,7 @@ NOTE: .bbappend files can impact the
> dependencies.
>          parser_show_recipes.add_argument('-i', '--inherits',
> help='only list recipes that inherit the named class(es) - separate
> multiple classes using , (without spaces)', metavar='CLASS',
> default='')
>          parser_show_recipes.add_argument('-l', '--layer', help='only
> list recipes from the selected layer', default='')
>          parser_show_recipes.add_argument('-b', '--bare',
> help='output just names without the "(skipped)" marker',
> action='store_true')
> +        parser_show_recipes.add_argument('-v', '--show-variants',
> help='show all BBCLASSEXTEND recipe variants (e.g., devupstream,
> nativesdk)', action='store_true')


During the patch review session, we concluded that -v usually stands
for “verbose” or often for “version.” Would it be possible to remove -v
for this somewhat more specific feature and only keep the long option?

Thank you.
Adrian

>          parser_show_recipes.add_argument('--mc', help='use specified
> multiconfig', default='')
>          parser_show_recipes.add_argument('pnspec', nargs='*',
> help='optional recipe name specification (wildcards allowed, enclose
> in quotes to avoid shell expansion)')
>  
> 
> -=-=-=-=-=-=-=-=-=-=-=-
> Links: You receive all messages sent to this group.
> View/Reply Online (#225300):
> https://lists.openembedded.org/g/openembedded-core/message/225300
> Mute This Topic: https://lists.openembedded.org/mt/115931358/4454582
> Group Owner: openembedded-core+owner@lists.openembedded.org
> Unsubscribe:
> https://lists.openembedded.org/g/openembedded-core/unsub [
> adrian.freihofer@gmail.com]
> -=-=-=-=-=-=-=-=-=-=-=-
Osama Abdelkader Dec. 8, 2025, 7:46 p.m. UTC | #3
On Mon, Dec 08, 2025 at 06:28:12PM +0100, adrian.freihofer@gmail.com wrote:
> On Fri, 2025-10-24 at 19:40 +0300, Osama Abdelkader via
> lists.openembedded.org wrote:
> > The bitbake-layers show-recipes command was hiding BBCLASSEXTEND
> > recipe
> > variants (e.g., devupstream, nativesdk, cross-canadian) by design, to
> > avoid clutter in the output. However, this made it impossible to see
> > recipes like linux-firmware's devupstream variant which uses git
> > snapshots
> > instead of release tarballs.
> > 
> > This patch adds a new --show-variants (-v) option to show-recipes
> > that
> > allows users to view all BBCLASSEXTEND variants when needed, while
> > maintaining the default behavior of hiding them for a cleaner output.
> > 
> > Example usage:
> >   bitbake-layers show-recipes -v linux-firmware
> > 
> > This will now show both:
> >   - Base version: 1:20251011
> >   - Devupstream version: 1:20251011+git
> > 
> > Signed-off-by: Osama Abdelkader <osama.abdelkader@gmail.com>
> > ---
> >  bitbake/lib/bblayers/query.py | 23 ++++++++++++++++-------
> >  1 file changed, 16 insertions(+), 7 deletions(-)
> > 
> > diff --git a/bitbake/lib/bblayers/query.py
> > b/bitbake/lib/bblayers/query.py
> > index eb7cb465b4..11341d5d53 100644
> > --- a/bitbake/lib/bblayers/query.py
> > +++ b/bitbake/lib/bblayers/query.py
> > @@ -52,7 +52,7 @@ layer, with the preferred version first. Note that
> > skipped recipes that
> >  are overlayed will also be listed, with a " (skipped)" suffix.
> >  """
> >  
> > -        items_listed = self.list_recipes('Overlayed recipes', None,
> > True, args.same_version, args.filenames, False, True, None, False,
> > None, args.mc)
> > +        items_listed = self.list_recipes('Overlayed recipes', None,
> > True, args.same_version, args.filenames, False, True, None, False,
> > None, args.mc, False)
> >  
> >          # Check for overlayed .bbclass files
> >          classes = collections.defaultdict(list)
> > @@ -119,9 +119,9 @@ skipped recipes will also be listed, with a "
> > (skipped)" suffix.
> >              title = 'Matching recipes:'
> >          else:
> >              title = 'Available recipes:'
> > -        self.list_recipes(title, args.pnspec, False, False,
> > args.filenames, args.recipes_only, args.multiple, args.layer,
> > args.bare, inheritlist, args.mc)
> > +        self.list_recipes(title, args.pnspec, False, False,
> > args.filenames, args.recipes_only, args.multiple, args.layer,
> > args.bare, inheritlist, args.mc, args.show_variants)
> >  
> > -    def list_recipes(self, title, pnspec, show_overlayed_only,
> > show_same_ver_only, show_filenames, show_recipes_only,
> > show_multi_provider_only, selected_layer, bare, inherits, mc):
> > +    def list_recipes(self, title, pnspec, show_overlayed_only,
> > show_same_ver_only, show_filenames, show_recipes_only,
> > show_multi_provider_only, selected_layer, bare, inherits, mc,
> > show_variants=False):
> >          if inherits:
> >              bbpath = str(self.tinfoil.config_data.getVar('BBPATH'))
> >              for classname in inherits:
> > @@ -203,8 +203,10 @@ skipped recipes will also be listed, with a "
> > (skipped)" suffix.
> >                  # We only display once per recipe, we should prefer
> > non extended versions of the
> >                  # recipe if present (so e.g. in OpenEmbedded,
> > openssl rather than nativesdk-openssl
> >                  # which would otherwise sort first).
> > +                # However, if show_variants is True, we show all
> > BBCLASSEXTEND variants.
> >                  if realfn[1] and realfn[0] in
> > self.tinfoil.cooker.recipecaches[mc].pkg_fn:
> > -                    continue
> > +                    if not show_variants:
> > +                        continue
> >  
> >                  if inherits:
> >                      matchcount = 0
> > @@ -229,7 +231,11 @@ skipped recipes will also be listed, with a "
> > (skipped)" suffix.
> >                      for prov in allproviders[p]:
> >                          provfile =
> > bb.cache.virtualfn2realfn(prov[1])[0]
> >                          provlayer = self.get_file_layer(provfile)
> > -                        provs.append((provfile, provlayer, prov[0]))
> > +                        # When show_variants is True, use the
> > virtual filename to distinguish BBCLASSEXTEND variants
> > +                        if show_variants:
> > +                            provs.append((prov[1], provlayer,
> > prov[0]))
> > +                        else:
> > +                            provs.append((provfile, provlayer,
> > prov[0]))
> >                          if provlayer != preflayer:
> >                              multilayer = True
> >                          if prov[0] != pref[0]:
> > @@ -238,10 +244,12 @@ skipped recipes will also be listed, with a "
> > (skipped)" suffix.
> >                          if not items_listed:
> >                              logger.plain('=== %s ===' % title)
> >                              items_listed = True
> > +                        # When show_variants is True, use the
> > virtual filename for preference check
> > +                        pref_cmp_file = pref[1] if show_variants
> > else preffile
> >                          print_item(preffile, p,
> > self.version_str(pref[0][0], pref[0][1]), preflayer, True)
> >                          for (provfile, provlayer, provver) in provs:
> > -                            if provfile != preffile:
> > -                                print_item(provfile, p,
> > self.version_str(provver[0], provver[1]), provlayer, False)
> > +                            if provfile != pref_cmp_file:
> > +                               
> > print_item(bb.cache.virtualfn2realfn(provfile)[0] if show_variants
> > else provfile, p, self.version_str(provver[0], provver[1]),
> > provlayer, False)
> >                          # Ensure we don't show two entries for
> > BBCLASSEXTENDed recipes
> >                          preffiles.append(preffile)
> >  
> > @@ -530,6 +538,7 @@ NOTE: .bbappend files can impact the
> > dependencies.
> >          parser_show_recipes.add_argument('-i', '--inherits',
> > help='only list recipes that inherit the named class(es) - separate
> > multiple classes using , (without spaces)', metavar='CLASS',
> > default='')
> >          parser_show_recipes.add_argument('-l', '--layer', help='only
> > list recipes from the selected layer', default='')
> >          parser_show_recipes.add_argument('-b', '--bare',
> > help='output just names without the "(skipped)" marker',
> > action='store_true')
> > +        parser_show_recipes.add_argument('-v', '--show-variants',
> > help='show all BBCLASSEXTEND recipe variants (e.g., devupstream,
> > nativesdk)', action='store_true')
> 
> 
> During the patch review session, we concluded that -v usually stands
> for “verbose” or often for “version.” Would it be possible to remove -v
> for this somewhat more specific feature and only keep the long option?
> 

Sure, I'm going to send v2.

Thanks,
Osama

> Thank you.
> Adrian
> 
> >          parser_show_recipes.add_argument('--mc', help='use specified
> > multiconfig', default='')
> >          parser_show_recipes.add_argument('pnspec', nargs='*',
> > help='optional recipe name specification (wildcards allowed, enclose
> > in quotes to avoid shell expansion)')
> >  
> > 
> > -=-=-=-=-=-=-=-=-=-=-=-
> > Links: You receive all messages sent to this group.
> > View/Reply Online (#225300):
> > https://lists.openembedded.org/g/openembedded-core/message/225300
> > Mute This Topic: https://lists.openembedded.org/mt/115931358/4454582
> > Group Owner: openembedded-core+owner@lists.openembedded.org
> > Unsubscribe:
> > https://lists.openembedded.org/g/openembedded-core/unsub [
> > adrian.freihofer@gmail.com]
> > -=-=-=-=-=-=-=-=-=-=-=-
diff mbox series

Patch

diff --git a/bitbake/lib/bblayers/query.py b/bitbake/lib/bblayers/query.py
index eb7cb465b4..11341d5d53 100644
--- a/bitbake/lib/bblayers/query.py
+++ b/bitbake/lib/bblayers/query.py
@@ -52,7 +52,7 @@  layer, with the preferred version first. Note that skipped recipes that
 are overlayed will also be listed, with a " (skipped)" suffix.
 """
 
-        items_listed = self.list_recipes('Overlayed recipes', None, True, args.same_version, args.filenames, False, True, None, False, None, args.mc)
+        items_listed = self.list_recipes('Overlayed recipes', None, True, args.same_version, args.filenames, False, True, None, False, None, args.mc, False)
 
         # Check for overlayed .bbclass files
         classes = collections.defaultdict(list)
@@ -119,9 +119,9 @@  skipped recipes will also be listed, with a " (skipped)" suffix.
             title = 'Matching recipes:'
         else:
             title = 'Available recipes:'
-        self.list_recipes(title, args.pnspec, False, False, args.filenames, args.recipes_only, args.multiple, args.layer, args.bare, inheritlist, args.mc)
+        self.list_recipes(title, args.pnspec, False, False, args.filenames, args.recipes_only, args.multiple, args.layer, args.bare, inheritlist, args.mc, args.show_variants)
 
-    def list_recipes(self, title, pnspec, show_overlayed_only, show_same_ver_only, show_filenames, show_recipes_only, show_multi_provider_only, selected_layer, bare, inherits, mc):
+    def list_recipes(self, title, pnspec, show_overlayed_only, show_same_ver_only, show_filenames, show_recipes_only, show_multi_provider_only, selected_layer, bare, inherits, mc, show_variants=False):
         if inherits:
             bbpath = str(self.tinfoil.config_data.getVar('BBPATH'))
             for classname in inherits:
@@ -203,8 +203,10 @@  skipped recipes will also be listed, with a " (skipped)" suffix.
                 # We only display once per recipe, we should prefer non extended versions of the
                 # recipe if present (so e.g. in OpenEmbedded, openssl rather than nativesdk-openssl
                 # which would otherwise sort first).
+                # However, if show_variants is True, we show all BBCLASSEXTEND variants.
                 if realfn[1] and realfn[0] in self.tinfoil.cooker.recipecaches[mc].pkg_fn:
-                    continue
+                    if not show_variants:
+                        continue
 
                 if inherits:
                     matchcount = 0
@@ -229,7 +231,11 @@  skipped recipes will also be listed, with a " (skipped)" suffix.
                     for prov in allproviders[p]:
                         provfile = bb.cache.virtualfn2realfn(prov[1])[0]
                         provlayer = self.get_file_layer(provfile)
-                        provs.append((provfile, provlayer, prov[0]))
+                        # When show_variants is True, use the virtual filename to distinguish BBCLASSEXTEND variants
+                        if show_variants:
+                            provs.append((prov[1], provlayer, prov[0]))
+                        else:
+                            provs.append((provfile, provlayer, prov[0]))
                         if provlayer != preflayer:
                             multilayer = True
                         if prov[0] != pref[0]:
@@ -238,10 +244,12 @@  skipped recipes will also be listed, with a " (skipped)" suffix.
                         if not items_listed:
                             logger.plain('=== %s ===' % title)
                             items_listed = True
+                        # When show_variants is True, use the virtual filename for preference check
+                        pref_cmp_file = pref[1] if show_variants else preffile
                         print_item(preffile, p, self.version_str(pref[0][0], pref[0][1]), preflayer, True)
                         for (provfile, provlayer, provver) in provs:
-                            if provfile != preffile:
-                                print_item(provfile, p, self.version_str(provver[0], provver[1]), provlayer, False)
+                            if provfile != pref_cmp_file:
+                                print_item(bb.cache.virtualfn2realfn(provfile)[0] if show_variants else provfile, p, self.version_str(provver[0], provver[1]), provlayer, False)
                         # Ensure we don't show two entries for BBCLASSEXTENDed recipes
                         preffiles.append(preffile)
 
@@ -530,6 +538,7 @@  NOTE: .bbappend files can impact the dependencies.
         parser_show_recipes.add_argument('-i', '--inherits', help='only list recipes that inherit the named class(es) - separate multiple classes using , (without spaces)', metavar='CLASS', default='')
         parser_show_recipes.add_argument('-l', '--layer', help='only list recipes from the selected layer', default='')
         parser_show_recipes.add_argument('-b', '--bare', help='output just names without the "(skipped)" marker', action='store_true')
+        parser_show_recipes.add_argument('-v', '--show-variants', help='show all BBCLASSEXTEND recipe variants (e.g., devupstream, nativesdk)', action='store_true')
         parser_show_recipes.add_argument('--mc', help='use specified multiconfig', default='')
         parser_show_recipes.add_argument('pnspec', nargs='*', help='optional recipe name specification (wildcards allowed, enclose in quotes to avoid shell expansion)')