As you may know KConfig is a well-known system for configuring software modules, as used by busybox, linux kernel, u-boot and many more.
If you are unfamiliar you might want to read this nice tutorial.
So as KConfig is well established it is used at different locations throughout YOCTO.
Basically YOCTO is doing it the following way.
You have a base configuration file called "defconfig". This is placed somewhere in the recipe-tree. It describes the absolute minimum of configuration needed.
Depending on the feature you want to add, there are *.cfg-file around the recipe-tree.
The configuration is done with all the *.cfg-files being merged into the defconfig.
This is passed to "make oldconfig" to sanity check and put all the not defined symbols into the configuration. And voila you have a fresh valid configuration to build your software.
It's pretty obvious that this is one stage where things can go very wrong...!
Mostly the basis (KConfig) is changing over the time, so symbols come and go or might change their meaning from version to version.
Which is the second stage where things can go wrong.
And that a fundamental problem.
Most of the developer I know, work like this
If you are unfamiliar you might want to read this nice tutorial.
So as KConfig is well established it is used at different locations throughout YOCTO.
Basically YOCTO is doing it the following way.
You have a base configuration file called "defconfig". This is placed somewhere in the recipe-tree. It describes the absolute minimum of configuration needed.
Depending on the feature you want to add, there are *.cfg-file around the recipe-tree.
The configuration is done with all the *.cfg-files being merged into the defconfig.
This is passed to "make oldconfig" to sanity check and put all the not defined symbols into the configuration. And voila you have a fresh valid configuration to build your software.
It's pretty obvious that this is one stage where things can go very wrong...!
Mostly the basis (KConfig) is changing over the time, so symbols come and go or might change their meaning from version to version.
Which is the second stage where things can go wrong.
And that a fundamental problem.
Most of the developer I know, work like this
- on version X the define a feature-set and so a set of configuration symbols they want to apply
- they test this combination
- they put into the SCM
- they keep the fingers crossed that any future update will not break anything
- they are upset/confused/what so ever if a future update is really breaking things
If you look at it in a detail the following scenarios might happen
- Symbol set in version A - Symbol set in version b
- Symbol set in version A - Symbol has other value or is unset in version B
- Symbol in n.a. in version A - Symbol is set in version B
- Symbol is unset in version A - Symbol is n.a. in version B
- Symbol is n.a. in version A - Symbol is unset in version B
- Symbol set in version A - Symbol is n.a. in version B
while points 1, 4 and 5 are definitely uncritical the other you might want to be warned about.
And as YOCTO is based on layer, each layer multiplies the complexity of factors that could change the effective configuration of your software module. Just imagine you have 10 layers (each with the very own release cycle) and in these 10 layers everybody could add/remove/change configuration as they like. Long story short: very bad for you, as you typically just want the feature set that was once defined and tested.
Now one could say, one could always compare the resulting file against a known configuration placed somewhere in repository - and mismatch just shout out some warning or whatever.
IMHO this is not enough.
Most of the KConfig files I know include a version-string somewhere in the file, so although nothing effectively changed the effective configuration and the one from your repo look different.
Second point is, that most of the projects using KConfig-based systems tend to "reorganize" the order of the symbols from time to time.
So what you really need to do is check every symbol (and therefore every line) of both files to be 100% sure (also on all the cases I mentioned above).
I've been working on this topic some month ago and implemented a helper class you can find here.
With the help of this class you are able to
- check if a *.cfg-file is made effective in the resulting configuration
Which is often a common mistake I did, because I forgot some obscure dependency of a configuration symbol.
Short example:
I wanted
CONFIG_FOO=y
and I put it into a *.cfg-file, referenced it, was 100% sure that it will make it to resulting config
but CONFIG_FOO depended on CONFIG_BAR=y which wasn't set anywhere,
so my CONFIG_FOO was simply ignored - you can check the resulting configuration is matching a reference configuration
(you can see this as a enhanced diff) - you can set the action on any finding for the numbered point above
Sometimes you might don't car if a new feature is automatically activated, sometimes you want to abort the build in the same case
Quick example:
in version a we got CONFIG_FOO=1 and in version b CONFIG_FOO=2.
In this particular case I don't want to warned just informed.
On the other hand if we got in version a we got CONFIG_FOO=1 and in version b
# CONFIG_FOO is not set that is clearly a case where I want the build to be aborted
The helper-class makes use of the LibKconfig so it will give you a explanation why a symbol didn't make it into the resulting configuration.
I used rightly this class will always ensure that you can concentrate on the important things, no on regression testing all features you worked on ages ago.
If there is something to look at in detail the build process will tell you (and this hopefully in the right amount).
I wrote the kconfig-sanity.bbclass as part of my collection meta-buildtuils of useful helper functions.
I would be happy to get your input here in the comments or over on GitHub.
Kommentare
Kommentar veröffentlichen