Lorsqu'un projet gagne en ampleur et se diversifie, de plus en plus de directives de compilation apparaissent (#ifdef, ...). Il devient alors difficile de savoir quelle action effectue chaque directive surtout si elles ont des dépendances entre elles.
L'exemple typique est la compilation d'un noyau linux. En effet, le noyau 3.8.0 contient plus de 4000 symboles. Heureusement, il existe une interface simple permettant la configuration de ces symboles. Elle est appelée par la commande
make menuconfig
Nous allons voir ici comment utiliser cette même interface pour nos propres projets.
L'utilitaire kconfig présent dans le noyau linux n'existe pas en tant que projet autonome. Pour pouvoir l'utiliser, il faut soit l'extraire des sources du kernel, soit faire appel à des projets qui ont fait ce travail pour nous. C'est cette deuxième solution qui a été choisie pour cet article.
Le projet kconfig-frontends (http://ymorin.is-a-geek.org/projects/kconfig-frontends) extrait des sources du kernel l'utilitaire kconfig et adapte le système de build. L'intérêt de ce projet par rapport à un autre est que le code est régulièrement réaligné sur les releases du kernel.
Afin de profiter de toutes les interfaces graphiques offertes par cet utilitaire, il faut au préalable installer les dépendances suivantes: ncurses et qt4.
Une fois l'archive téléchargée (depuis http://ymorin.is-a-geek.org/download/kconfig-frontends/) et extraite, il suffit de faire:
$> ./configure && make
On retrouve les différents utilitaires dans le répertoire frontends/:
- conf configuration en ligne
- mconf configuration à travers une interface ncurses
- qconf configuration à travers une interface graphique
On peut donc ajouter les règles suivantes dans le Makefile:
.PHONY: menuconfig menuconfig: ifneq ($(MCONF),) $(MCONF) Kconfig endif .PHONY: config config: ifneq ($(CONF),) mkdir -p include/ mkdir -p include/config include/generated $(CONF) --silentoldconfig Kconfig endif
La règle menuconfig va appeler l'utilitaire mconf et générera un fichier .config.
La règle config va appeller l'utilitaire conf. Avec l'option --silentoldconfig, cet utilitaire va traduire le fichier .config en un fichier include/generated/autoconf.h. (NOTE: il est possible de changer le nom et l'emplacement de ce fichier en exportant la variable KCONFIG_AUTOHEADER).
Le fichier autoconf contient une suite de #define représentant la configuration choisie.
Attention! Tous les symboles définis dans le fichier Kconfig seront préfixés par CONFIG_
/* * * Automatically generated file; DO NOT EDIT. * Linux/i386 3.8.0-rc3 Kernel Configuration * */ #define CONFIG_HAVE_ARCH_SECCOMP_FILTER 1 #define CONFIG_KERNEL_GZIP 1 #define CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK 1 #define CONFIG_INOTIFY_USER 1 #define CONFIG_X86_MINIMUM_CPU_FAMILY 5 #define CONFIG_X86_TSC 1 #define CONFIG_ARCH_SUSPEND_POSSIBLE 1 #define CONFIG_HAVE_KERNEL_BZIP2 1 #define CONFIG_UEVENT_HELPER_PATH "" #define CONFIG_STEP_WISE 1
Il ne reste plus qu'à inclure ce fichier dans vos sources.
Le dernier aspect de cet article concerne l'écriture des fichiers Kconfig.
La syntaxe de ces fichiers est décrite dans la Documentation du noyau linux.
Les principales commandes sont
- source Importe un autre Kconfig
source "submodule1/kconfig"
source "submodule2/kconfig" - config Créer une entrée
config MY_SYMBOL - menu Créer une sous section. Le contenu sera affiché dans une nouvelle page.
menu "DEBUG option"
config DEBUG_OPTION1
config DEBUG_OPTION2
endmenu - choice Permet de sélectionner une valeur
choice "Do a choice"
config CHOICE_1
config CHOICE_2
endchoice
Les entrées peuvent être de différents types:
- bool Booléen
- string Une chaine de caractères
- hex Une valeur hexadécimale
- int Une valeur entière
- tristate Peut valoir 'n', 'y' ou 'm'. Ce type est principalement utilisé dans la configuration du kernel: non, statique ou module
Chaque entrée peut également avoir plusieurs options:
- prompt Label qui sera affiché pour ce symbole
- help Texte qui sera affiché lors de la demande d'aide sur ce symbole
- default Valeur par défaut du symbole
- range Intervalle de valeur pour des entrées de type hex ou int
- depends on Cette entrée ne sera affichée que si la dépendance est vérifiée
- select Force une valeur pour un autre symbole (dépendance inverse) A utiliser avec précaution!
Il est également possible d'effectuer un affichage conditionnel suivant la valeur des symboles:
if FOO config BAR bool prompt "about BAR" endif
Je terminerai cet article par un exemple de fichier Kconfig:
# un commentaire config BASE_ADDR hex prompt "Base address" menu "Duration config" choice "Time unit" config TIME_MS bool prompt "Time in ms" config TIME_S bool prompt "Time in s" endchoice config MAIN_LOOP int default 10 prompt "Duration of main loop" help Set the duration of main loop. The unit is defined in Time unit config OTHER_LOOP int prompt "Duration of other loop" endmenu menu "Debug option" config DEBUG bool prompt "Allow debug" config DEBUG_WARNING bool prompt "Debug warning" depends on DEBUG endmenu