summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Fietkau2026-01-13 09:31:22 +0000
committerFelix Fietkau2026-01-22 10:20:17 +0000
commit6d5c71f7485da47e5c2a0318dafd47ba50311dd4 (patch)
tree2315a6392573920396a8bbda8307c0d8ef0cc0c9
parent46129bbbf5a423fd44a21b2f80f27a5a579fbb56 (diff)
downloadopenwrt-6d5c71f7485da47e5c2a0318dafd47ba50311dd4.tar.gz
build: auto-generate CONFLICTS for package variants sharing PROVIDES
Packages using PROVIDES to declare virtual package alternatives (like tc-tiny, tc-bpf, tc-full all providing 'tc') could be simultaneously selected as =y, causing installation conflicts. The PROVIDES mechanism only handles dependency resolution, not mutual exclusion. Add add_implicit_provides_conflicts() to automatically generate CONFLICTS from default variants to non-default variants sharing the same PROVIDES. This ensures only one variant can be built-in (=y) at a time. Skip generating implicit conflicts when the non-default already has explicit CONFLICTS with the default, to avoid Kconfig dependency cycles with the select-based dependency resolution. Signed-off-by: Felix Fietkau <nbd@nbd.name>
-rwxr-xr-xscripts/package-metadata.pl47
1 files changed, 47 insertions, 0 deletions
diff --git a/scripts/package-metadata.pl b/scripts/package-metadata.pl
index 82bd4360f3..518dae2dfd 100755
--- a/scripts/package-metadata.pl
+++ b/scripts/package-metadata.pl
@@ -255,6 +255,52 @@ sub mconf_conflicts {
return $res;
}
+sub add_implicit_provides_conflicts {
+ foreach my $provide (keys %vpackage) {
+ next if $provide =~ /-any$/;
+
+ my $providers = $vpackage{$provide};
+ next unless $providers && @$providers > 1;
+
+ my $default_pkg;
+ my @non_defaults;
+
+ foreach my $pkg (@$providers) {
+ next if $pkg->{buildonly};
+ if ($pkg->{variant_default}) {
+ $default_pkg = $pkg;
+ } else {
+ push @non_defaults, $pkg;
+ }
+ }
+
+ next unless $default_pkg && @non_defaults;
+
+ my %existing_conflicts;
+ if ($default_pkg->{conflicts}) {
+ %existing_conflicts = map { $_ => 1 } @{$default_pkg->{conflicts}};
+ }
+
+ foreach my $non_default (@non_defaults) {
+ next if $existing_conflicts{$non_default->{name}};
+
+ my $already_conflicts = 0;
+ if ($non_default->{conflicts}) {
+ foreach my $c (@{$non_default->{conflicts}}) {
+ if ($c eq $default_pkg->{name}) {
+ $already_conflicts = 1;
+ last;
+ }
+ }
+ }
+ next if $already_conflicts;
+
+ $default_pkg->{conflicts} ||= [];
+ push @{$default_pkg->{conflicts}}, $non_default->{name};
+ }
+ }
+}
+
sub print_package_config_category($) {
my $cat = shift;
my %menus;
@@ -350,6 +396,7 @@ sub print_package_overrides() {
sub gen_package_config() {
parse_package_metadata($ARGV[0]) or exit 1;
+ add_implicit_provides_conflicts();
print "menuconfig IMAGEOPT\n\tbool \"Image configuration\"\n\tdefault n\n";
print "source \"package/*/image-config.in\"\n";
if (scalar glob "package/feeds/*/*/image-config.in") {