0

In openwrt, as we known, usually the patches for a certain package should be put in package/[pkg]/patches and it will be applied in Makefile via $(Build/Patch). Example:

  • package/test/0001-1.0.1.8.fix-A.patch

  • package/test/0002-1.0.1.8.fix-B.patch

When the package update to a new version, the patches sometimes also need to be updated. Example:

  • package/test/0001-1.0.1.9.fix-A.patch
  • package/test/0002-1.0.1.9.fix-B.patch

OR

  • package/test/0001-1.0.2.0.fix-A.patch
  • package/test/0002-1.0.2.0.fix-B.patch

For a single certain package version, this works well. The only thing is to update the package version and patches manually.

For a certion reason the old patch can not be applied and submit to package source when pacakge upgrade. So they have to be maintained via patches.

What I am doing is that, if the Makefile could automatically find the right patches based on the package version. I choose to put all these patches in "package/test/file/patches/" directory base on package verion, such as:

  • package/test/file/patches/1.0.1.8/0001-v1.0.1.8.fix-A.patch
  • package/test/file/patches/1.0.1.8/0002-1.0.1.8.fix-B.patch
  • package/test/file/patches/1.0.1.9/0001-1.0.1.9.fix-A.patch
  • package/test/file/patches/1.0.1.9/0002-1.0.1.9.fix-B.patch
  • package/test/file/patches/1.0.2.0/0001-1.0.2.0.fix-A.patch
  • package/test/file/patches/1.0.2.0/0002-1.0.2.0.fix-B.patch

In the Makefile, the right patches should be copied to "package/test/patches/" directory first in "define Build/Prepare" section, before $(Build/Patch).

Match rule: (I don't know how to insert a table here, I put an image instead ...)

match the latest version

So, in this way, all the patches can be stored in the "pacakge/test" directory and they will be auto matched and applied when building.

The question is , how can I achieve to find out the right match? Since it's a little complex to compare and match the version, especially in Makefile rather than in shell script.

Actually I found some interesting script to do part of this, such as:

how-to-compare-two-strings-in-dot-separated-version-format-in-bash

Robert Hu
  • 131
  • 1
  • 5

1 Answers1

1

While I don't exactly understand which version number you want to compare to which patch or the other way around, the following snippet will give you an idea how solve the task with GNUmake programming with the help of the GNUmake table toolkit which was designed for such problems:

include gmtt/gmtt.mk

# Helper function which converts a list of numbers into a decimal
# number with 3 digits per original version place:
vers-to-num = $(call lpad,$(word 1,$1),3,0)$(call lpad,$(word 3,$1),3,0)$(call lpad,$(word 5,$1),3,0)$(call lpad,$(word 7,$1),3,0)

VERSION := 1.1.1.4
VERS_LIST := $(call glob-match,$(word 1,$(VERSION)),*.*.*.*)
$(info VERS_LIST = $(VERS_LIST))

VERS_NUM := $(call vers-to-num,$(VERS_LIST))
$(info $(VERS_NUM))


PATCH := 1.0.2.0


# Patch to version relation:
# Table with 3 columns: patch-nr | first applicable version | last applicable version
# In case there is only one version it has to go into both columns (no empty cells!)
define PATCH_TO_VER :=
3
1.0.1.8   1.0.1.8   1.0.1.8
1.0.1.9   1.0.1.9   1.0.1.9
1.0.2.0   1.0.2.0   1.1.1.3
1.1.1.4   1.1.1.4   1.1.3.9
endef

VA_VB := $(call select,2 3,$(PATCH_TO_VER),$$(call str-eq,$(PATCH),$$1))
$(info VA_VB = $(VA_VB))

VA_LIST := $(call glob-match,$(word 1,$(VA_VB)),*.*.*.*)
VA_NUM := $(call vers-to-num,$(VA_LIST))
$(info $(VA_NUM))

VB_LIST := $(call glob-match,$(word 2,$(VA_VB)),*.*.*.*)
VB_NUM := $(call vers-to-num,$(VB_LIST))
$(info $(VB_NUM))

# Instead of comparing each version digit against upper and lower
# allowed value (the if-else tree for this gets hellish, try it
# yourself) we use gmtt's numeric range capability of at least 64
# digits to compare versions :
COMPARE_RESULT := $(if $(call int-ge,$(VERS_NUM),$(VA_NUM)),$(if $(call int-le,$(VERS_NUM),$(VB_NUM)),yes))

$(info patch version in range (empty=no): <$(COMPARE_RESULT)>)
                                                                                                                                                                                                                                             

Output:

VERS_LIST =  1 . 1 . 1 . 4
001001001004
VA_VB = 1.0.2.0 1.1.1.3
001000002000
001001001003
patch version in range (empty=no): <>
make: *** No targets.  Stop.
Vroomfondel
  • 2,704
  • 1
  • 15
  • 29
  • This is based on gmtt/gmtt.mk Does it aviable in every openwrt project and how I install it ? What if I don't have gmtt. – Robert Hu Jun 30 '20 at 09:57
  • Actuall I have write some in Makefile and acchieve part of this. #part-A : compare version such as a.b.c.d, return YES if ge version_greater_equal = $(shell if printf '%s\n%s\n' '$(2)' '$(1)' | \ sort -Ct. -k1,1n -k2,2n -k3,3n -k4,4n ; then echo YES; else echo NO; fi) #part-B: get the subfolder name and each one is such as SUB_DIR_LISTS := $(foreach eachdir, $(filter %/, $(wildcard ./files/patches/*/)), $(shell echo ${eachdir} | cut -d/ -f4)) – Robert Hu Jun 30 '20 at 10:02
  • sorry ... I failed to insert code as format required .... – Robert Hu Jun 30 '20 at 10:06
  • @RobertHu No need to install gmtt, just download it from github and put it aside your makefile or whereever you see it fit. It is a simple `include`able makefile. – Vroomfondel Jun 30 '20 at 16:09