]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
build: add support for virtual provides
authorGeorge Sapkin <george@sapk.in>
Thu, 25 Dec 2025 13:32:29 +0000 (15:32 +0200)
committerRobert Marko <robimarko@gmail.com>
Wed, 31 Dec 2025 17:16:48 +0000 (18:16 +0100)
Allow defining virtual provides using the PROVIDES field by prefixing
them with @, e.g.:

PROVIDES:=@ca-certs

Virtual provides don't own the provided name and multiple packages with
the same virtual provides can be installed side-by-side. Packages must
still take care not to override each other's files.

Add an implicit self-provide to packages. apk can't handle self
provides, be it versioned or virtual, so opt for a suffix instead. This
allows several variants to provide the same virtual package without
adding extra provides to the default one, e.g. wget implicitly provides
wget-any and is marked as default, so wget-ssl can explicitly provide
@wget-any as well.

Filter out virtual provides when generating metadata.

Filter out virtual provides prefix and self provide where appropriate.

Signed-off-by: George Sapkin <george@sapk.in>
Link: https://github.com/openwrt/openwrt/pull/21288
Signed-off-by: Robert Marko <robimarko@gmail.com>
include/package-pack.mk
include/package.mk
scripts/metadata.pm

index 7080b8362b1ed3f52806c52d784db16dd77d0b47..853832d90ffaba19aafcbe465162ef66d98e1644 100644 (file)
@@ -78,6 +78,25 @@ define FixupDependencies
   $(call AddDependency,$(1),$$(DEPS))
 endef
 
+# Format provide and add ABI and version if it's not a virtual provide marked
+# with an @.
+#
+# 1: provide name
+# 2: provide version
+# 3: (optional) ABI preformatted by FormatABISuffix
+define AddProvide
+$(if $(filter @%,$(1)),$(patsubst @%,%,$(1)),$(1)$(3)=$(2))
+endef
+
+# Remove virtual provides prefix and self. apk doesn't like it when packages
+# specify a redundant provide pointing to self.
+#
+# 1: package name
+# 2: list of provides
+define SanitizeProvides
+$(filter-out $(1),$(patsubst @%,%,$(2)))
+endef
+
 # Format provides both for apk and control
 #
 # - If ABI version is defined:
@@ -108,16 +127,33 @@ endef
 #       this implies that only one version of a provide can be installed at the
 #       same time
 #
+# - Both with and without an ABI, if a provide starts with an @, treat it as a
+#   virtual provide, that doesn't own the name by not appending version.
+#   Multiple packages with the same virtual provides can be installed
+#   side-by-side.
+#
+# - apk doesn't like it when packages specify a redundant provide pointing to
+#   self. Filter it out, but keep virtual self provides, in the form of
+#   @${package_name}-any.
+#
+# - Packages implicitly add a virtual @${package_name}-any provide in Package.
+#
 # 1: package name
 # 2: package version
 # 3: list of provides
 # 4: list of alternatives
 define FormatProvides
 $(strip $(if $(ABIV_$(1)), \
-  $(1) $(foreach provide,$(3), $(provide)$(ABIV_$(1))=$(2)), \
+  $(1) $(foreach provide, \
+    $(filter-out $(1),$(3)), \
+    $(call AddProvide,$(provide),$(2),$(ABIV_$(1))) \
+  ), \
   $(if $(4), \
-    $(3), \
-    $(foreach provide,$(3), $(provide)=$(2)) \
+    $(filter-out $(1),$(3)), \
+    $(foreach provide, \
+      $(filter-out $(1),$(3)), \
+      $(call AddProvide,$(provide),$(2)) \
+    ) \
   ) \
 ))
 endef
@@ -237,7 +273,7 @@ endif
        $(if $(ABI_VERSION),echo '$(ABI_VERSION)' | cmp -s - $(PKG_INFO_DIR)/$(1).version || { \
                mkdir -p $(PKG_INFO_DIR); \
                echo '$(ABI_VERSION)' > $(PKG_INFO_DIR)/$(1).version; \
-               $(foreach pkg,$(filter-out $(1),$(PROVIDES)), \
+               $(foreach pkg,$(call SanitizeProvides,$(1),$(PROVIDES)), \
                        cp $(PKG_INFO_DIR)/$(1).version $(PKG_INFO_DIR)/$(pkg).version; \
                ) \
        } )
@@ -336,7 +372,7 @@ endif
                        fi; \
                done; $(Package/$(1)/extra_provides) \
        ) | sort -u > $(PKG_INFO_DIR)/$(1).provides
-       $(if $(PROVIDES),@for pkg in $(filter-out $(1),$(PROVIDES)); do cp $(PKG_INFO_DIR)/$(1).provides $(PKG_INFO_DIR)/$$$$pkg.provides; done)
+       $(if $(PROVIDES),@for pkg in $(call SanitizeProvides,$(1),$(PROVIDES)); do cp $(PKG_INFO_DIR)/$(1).provides $(PKG_INFO_DIR)/$$$$pkg.provides; done)
        $(CheckDependencies)
 
        $(RSTRIP) $$(IDIR_$(1))
index 5392bdf4652b14e7413c982814fd5568fa826f84..087e374ea929799b55306385833c269e172ea085 100644 (file)
@@ -332,6 +332,13 @@ define BuildPackage
   $(eval $(Package/Default))
   $(eval $(Package/$(1)))
 
+  # Add an implicit self-provide. apk can't handle self provides, be it
+  # versioned or virtual, so opt for a suffix instead. This allows several
+  # variants to provide the same virtual package without adding extra provides
+  # to the default one, e.g. wget implicitly provides wget-any and is marked as
+  # default, so wget-ssl can explicitly provide @wget-any as well.
+  PROVIDES+=@$(1)-any
+
 ifdef DESCRIPTION
 $$(error DESCRIPTION:= is obsolete, use Package/PKG_NAME/description)
 endif
index dec9e62dff1295db33019dc2b2c8f2faa0b4f479..6cb63608d23683773d2b9972c6063cdcb1421421 100644 (file)
@@ -263,6 +263,9 @@ sub parse_package_metadata($) {
                /^Default: \s*(.+)\s*$/ and $pkg->{default} = $1;
                /^Provides: \s*(.+)\s*$/ and do {
                        my @vpkg = split /\s+/, $1;
+                       foreach (@vpkg) {
+                               s/^@//;
+                       }
                        @{$pkg->{provides}} = ($pkg->{name}, @vpkg);
                        foreach my $vpkg (@vpkg) {
                                next if ($vpkg eq $pkg->{name});