best approach of image versioning in yocto
You are interested in os-release recipe. This gives provision to add version details to the image. This recipe installs a file /etc/os-release
in the target.
If you are interested in adding custom fields based on your application or purpose of the image, you can add extra fields in OS_RELEASE_FIELDS
variable in os-release.bbappend
in your custom layer. For example,
OS_RELEASE_FIELDS += "BUILD_VERSION"
BUG_FIXED_VERSION = "1.0.0-B1"
BUILD_VERSION = "${BUG_FIXED_VERSION}"
This adds the build id into /etc/os-release
and you can increment the versions based on bug fix or new delivery.
About yocto /etc/os-release versioning
Could it be you still have to tell Yocto to use the os-release recipe?
With a os-release.bbappend you can modify the recipe that is part of openembedded-core.
There are a few examples how to do at that webpage. A good one is e.g. the one used in meta-yoe.
But all this is just telling Yocto how to build the recipe. You still have to tell Yocto to add it to your image.
This can be done in the local.conf file or e.g. the recipes-images/images/your-image.bb
file or in a packagegroup. The first solution is the quick and dirty one.
How to include git revision of image layer in boot output or /etc/issue?
Linux and U-Boot git hashes are the ones from the Linux/U-Boot git repository. This is how it is commonly done with OpenEmbedded. There is certainly a way to pass the git hash from OE to the U-Boot/Kernel build system, but I would not recommend doing that since it is not how it is commonly done.
As for the /etc/issue
file, this typically gets generated in the meta/recipes-core/base-files/base-files_3.0.14.bb
recipe. It should be fairly straight forward to add a bbappend to your layer and extend the task, e.g. something like this:
def get_layer_rev(d):
return bb.process.run('git rev-parse HEAD')
LAYER_REV="${@get_layer_rev(d)}"
do_install_basefilesissue_append() {
# Overwrite /etc/issue with a custom version of it
printf "${DISTRO_NAME} " > ${D}${sysconfdir}/issue
printf "${LAYER_REV}" >> ${D}${sysconfdir}/issue
}
How to handle distro versions in Yocto
Ubuntu and RedHat have a remote repositories. The systems have a internal list of installed packages. When you update the repository you get a new list of packages. You can then compare this list of installed packages against the new package list and install them. This is basically done with apt-get update && apt-get upgrade
and the yum equivalent.
Yocto actually supports rpm and deb package format and their remote repositories. I am not familiar with opkg and if they have the option of a remote repository.
When I implemented a system I narrowed it down to the following options:
- have a repository (deb and rpm definitely work here)
- have a version package
- using images
Version packages have the big disadvantages since you have to get your own logic on which packages to install. But you can require that version-1.deb needs software-v2.deb and tool-v1_5.deb. That works well with you own software but is a big manual overhead for the entire Yocto package stack.
Repository would be the usual way such as: apt-get update && apt-get -y upgrade
. Works well and easy, but lacks also a risk free path to newer Yocto version.
The image way is more complicated and depends on your used hardware, size of image and transfer of the image. If you have a huge image and a slow network you might not want to do this. Basically you push your new image (or automatically pull it based on a version) d push it then to the device. The device dd's it to a secondary partition and then you flip the bootload to use the other partition. Depending on bootloader and/or hardware you can automatically flip back in case the partition you booted in is broken. Helpful for remote systems. Advantage is: you can also easily upgrade the entire OS without manually picking versions. And you can have (automatic) fail-over.
Yocto - git revision in the image name
After some research it turned out the problem was in this line
IMAGE_VERSION = "${@get_image_version(d)}"
because the function get_image_version()
was called during parsing. I took inspiration from the source file in aehs29's post and moved the code to the anonymous Python function which is called after parsing.
I also had to add vardepsexclude
attribute to the IMAGE_NAME
variable. I tried to add vardepvalue
flag to IMAGE_VERSION
variable as well and in this particular case it did the same job as vardepsexclude
. Mentioned Bitbake class uses both flags, but I think in my case using only one of them is enough.
The final code is below:
IMAGE_VERSION ?= "${MACHINE}-${DATETIME}"
IMAGE_NAME = "${IMAGE_BASENAME}-${IMAGE_VERSION}"
IMAGE_NAME[vardepsexclude] += "IMAGE_VERSION"
python () {
import subprocess
import os.path
try:
parentRepo = os.path.dirname(d.getVar("COREBASE", True))
version = subprocess.check_output(["git", "describe", "--tags", "--long", "--dirty"], cwd = parentRepo, stderr = subprocess.DEVNULL).strip().decode('UTF-8')
d.setVar("IMAGE_VERSION", version)
except:
bb.warning("Could not get Git revision, image will have default name.")
}
EDIT:
After some research I realized it's better to define a global variable in layer.conf
file of the layer containing the recipes referencing the variable. The variable is set by a python script and is immediately expanded to prevent deterministic build warning:
layer.conf:
require conf/image-version.py.inc
IMAGE_VERSION := "${@get_image_version(d)}"
image-version.py.inc:
def get_image_version(d):
import subprocess
import os.path
try:
parentRepo = os.path.dirname(d.getVar("COREBASE", True))
return subprocess.check_output(["git", "describe", "--tags", "--long", "--dirty"], cwd = parentRepo, stderr = subprocess.DEVNULL).strip().decode('UTF-8')
except:
bb.warn("Could not determine image version. Default naming schema will be used.")
return d.getVar("MACHINE", True) + "-" + d.getVar("DATETIME", True)
I think this is cleaner approach which fits BitBake build system better.
Related Topics
Shipping Gnu/Linux Firefox Plugin with Shared Libraries (For Installation with No Root Access)
Run Any Linux Terminal Command from Typescript
Create/Delete Users from Text File Using Bash Script
How Does The 64 Bit Linux Kernel Kick Off a 32 Bit Process from an Elf
Is There Any Posix Way Through Fstat() to Check Whether a File Is a Symbolic Link or Not
Would It Be Possible to Read Out Physical Keyboard Strokes in Node.Js
Bash Redirect to /Dev/Stdout: Not a Directory
Why Do I Get The Information of "Suspended (Tty Input)" When I Run My Script in The Background
What Is an Interface Identifier
What Is The Most Efficient Way to Exchange High Volume Data Between 2 Process
How to Give to Some User Permissions Only to Subfolder
Cron Expression to Run on Different Days for Different Months
Socket Getting Created with Same Ip and Port on Local Host
What Do Getresuid() and Setresuid() Do
When Will Send() Return Less Than The Length Argument
Docker with '-User' Can Not Write to Volume with Different Ownership