If you read through the OpenWRT documentation, you may think that compiling your own image or reading through the documentation is witchcraft. Well, mostly it is. But as I had to go through this on my own, I would like to share my experience with you. First, you will need the OpenWRT SDK. To give you a quick overview what is available:

  • OpenWRT from scratch, called "build system". You clone the OpenWRT Git, execute some scripts and it will compile the whole cross-compile toolchain on your computer along with various libraries. Takes ages. You will need this if you would like to customize the kernel or mach files, the dirty hardcoded precessor of device trees.
  • OpenWRT imagebuilder. You will find this at the very bottom of the download page of your target and it should have a filename similar to openwrt-imagebuilder-18.06.2-ar71xx-generic.Linux-x86_64.tar.xz depending on your target. This allows you to customize the target by recompiling packages, selecting the ones which should be part of the image, adapting device trees and so on.
  • OpenWRT SDK. You will find this right next to the imagebuilder URL, in this example it would be named openwrt-sdk-18.06.2-ar71xx-generic_gcc-7.3.0_musl.Linux-x86_64.tar.xz. This allows you to select and recompile specific packages which is exactly what we want.

So why would you ever use the imagebuilder then if you just want to modify an image? Reason is the fact that on most embedded OpenWRT devices there are two partitions. One is SquashFS which is read-only and the other one is JFFS2. Now if you upload your OpenWRT image, all of the packages which are part of your image which is SquashFS. All changes you do afterwards like installing new packages or changing a package can't be saved on this SquashFS filesystem because as said, it is read-only. It has to be put on the JFFS2 partition where it takes more space due various reasons, if you're interested there is a whole page at the OpenWRT wiki. Where were we? Well, I was consulting you when to use the imagebuilder. If you're low on flash or want to save space as much as possible, create a whole new image using the imagebuilder and it will be straight in the image you flash. Hint: On x86 platforms you have a straight ext4 partition so that won't give you any benefits there.

I'll continue with the OpenWRT SDK as this should be about how to modify packages which is similar to the imagebuilder. There is a nice guide about the SDK on https://openwrt.org/docs/guide-developer/using_the_sdk and you should go through that guide till you're at "Compile Packages". Now comes the fun part. You have to find your package feed folder, in this case it is located at openwrt-sdk-number-andsoon/feeds/packages/net/https-dns-proxy . There is a makefile which defines where to get the files which includes the commit and hash because mostly these are hosted on e.g. Github. Lets say we want to update to the latest commit. You open up the  PKG_SOURCE_URL which is https://github.com/aarond10/https_dns_proxy and search for the latest commit hash which is at the moment 758f913fcc205113bd93a925dd1bf2bd1445a7a8. Replace PKG_SOURCE_VERSION with this commit hash, don't forget to update PKG_VERSION to something meaningful and eventually PKG_VERSION if needed. Empty the mirror hash like this PKG_MIRROR_HASH:="" because that should match hash the .tar.xz PKG_SOURCE which we don't know yet.

Run

make package/net/https-dns-proxy/download V=s

so that it will download the .tar.xz and afterwards

make package/net/https-dns-proxy/check V=s FIXUP=1

which will automatically fill in the PKG_MIRROR_HASH. Tada. If you now run a

make package/net/https-dns-proxy/compile

you should have a ipk at the following location, depending on your makefile settings and target it may be named different:

./bin/packages/your_target/packages/https_dns_proxy_2019-02-01-1_x86_64.ipk

PS: That also works wonderfully with the open-vm-packages in case you're also running OpenWRT on ESXi. See https://github.com/fangli/openwrt-vm-tools for a description on how to do that.