Trois points d’appuis suffisent à un bon équilibre

L’entropie est une notion sympathique. Il y en a partout, puisque la nature a horreur du vide. C’est donc tout naturellement qu’on en trouve plein la boîte crânienne des architectes, qui manquent systématiquement une occasion de se taire. Petit cas concret.

Un logiciel a été commandé par le client, il va falloir le développer. Ce logiciel fera plein de choses magiques et intéressantes. La révolution est en marche, la singularité à portée de vue. Parmi toutes les activités de ce logiciel, il est en une particulièrement épineuse. Il va remplir des traces dans un format cryptique, par exemple les résultats de son auto-analyse. Oui, les logiciels fiables savent dire si tout se barre en sucette et qu’ils doivent être remplacés par la nouvelle génération. Sac-à-papier ! il va également falloir fournir un analyseur de traces alors ? Ça se complique méchamment.

Hé ! oui, ça se complique : ce n’est plus un logiciel qu’il faut fournir, mais deux. Et puis surtout, il va falloir trouver un moyen pour forcer le pinpin qui devra se servir de tout ça à utiliser l’analyseur de traces qui correspond au logiciel qui tourne. Imaginez, s’il cherche à lire les traces produites par la version B avec l’analyseur de la version A, ou le contraire … Il risque de détecter des erreurs qui n’en sont pas, nous pourrir en réunion, et on passera trop de temps à chercher des problèmes qui n’en sont pas. Non, vraiment, il faut garantir que l’analyse des traces soit consistante.

Aujourd’hui, c’est jour de chance. L’architecte a déjà pensé à tout. On va introduire des numéros de version dans les binaires, et modifier l’analyseur pour que la première chose qu’il fasse soit de comparer son numéro de version avec celle du logiciel qui a produit les traces, comme ça, ni une, ni deux, si c’est pas pareil, il refuse de travailler, et fini les soucis. À cette fascinante idée j’opposerai deux arguments :

  1. Un bon numéro de version doit être unique. Il devrait donc être généré automagiquement, sinon il risque de mal vieillir. Et non, il ne faut pas juste un nouveau numéro à chaque livraison, mais bien à chaque production, sinon je ne sais pas trop comment les testeurs peuvent travailler. Ah ! tiens : subtilement, ce que l’on imaginait comme une activité pour le gestionnaire de configuration vient de vous échoir, là, pour vous, intégrateur ;
  2. Est-ce que le client va vraiment se contenter d’un analyseur de traces muet ? Je suis d’accord, mieux vaut se taire que de dire n’importe quoi (non, même là, il n’a pas compris), mais pour autant on ne rend pas plus service. Pire, du point de vue du client, on ne respecte pas le contrat : on devait faire une analyse qu’on ne conduit pas de toute évidence avec notre outil muet.

Au final, j’ai proposé une solution alternative : et si on s’assurait plutôt de la rétrocompatibilité des traces ? C’est-à-dire que les traces de la version B n’auraient pas rien à voir avec les traces de la version A, mais seraient un sur-ensemble ? Et le tout stocké dans un format ultra-novateur, du genre (identifiant, valeur) ? Au pire, si l’identifiant est inconnu de l’analyseur, il afficherait la donnée binaire brute, histoire de mettre la puce à l’oreille.

Allez comprendre pourquoi, cette solution trop simple a déplu. Je m’en fiche, je n’assure pas le S.A.V., bonne chance à eux.

Qui ne peut pas dormir trouve son lit mal fait

Les réjouissances continuent. De Jean-Pierre Liégois, jeune lecteur du Var (ou presque) :

Hier soir, plantage de l’appli au démarrage. Après investigation au debugger, un S/T explique que c’est la fonction d’initialisation de la RAM à 0 qui plante.
Du coup ca matin, tout le monde sur le pont pour vérifier la gestion de la RAM, la taille utilisée, regénérer l’exe pour être sûr qu’il n’ y a pas des décalages d’adresse ou truc du même genre … Impossible de résoudre le problème.
Dans l’après-midi, on retourne sur le banc pour refaire un coup de debugger, et la, surprise, le plantage n’est pas du tout sur la fonction indiquée la veille mais bien plus loin dans l’appli, sur une ligne qui, oh surprise encore, a été modifiée dans un correctif !!!
Conclusion : quand un S/T vous dit que le problème est là, surtout ne pas regarder là …

Là encore, rien que le pain quotidien du développement logiciel de logiciels embarqués. Le logiciel n’arrête pas de grossir, il y a forcément un moment où les constantes de dimensionnement appliquées depuis toujours ne conviennent plus : nécessité de faire grossir tel ou tel segment mémoire, de revoir les options du compilateur pour espérer gagner de la place, etc. Ce genre de choses est d’autant plus réjouissant que l’on sait que ça va arriver, tôt ou tard. Et pourtant, il n’y a jamais personne pour préparer la copie, car c’est autant de sous d’économisés tant que les limites ne sont pas atteintes. Par contre, une fois atteintes, la balance financière est rarement gagnante quand il s’agit de revenir à la normale. Mais passons.

À votre petit niveau d’intégrateur, que pouvez-vous faire dans le cas décrit plus haut ? Et bien avant tout, vous méfier ! Alors comme ça, d’un coup, la gestion de la mémoire est bancale parce qu’on a rajouté une condition dans le code ? Moi-même je ne compte plus les remarques du genre « ha non mais le problème est dans la libc » ou bien « c’est le compilateur qui doit être buggé ». Il faut avouer qu’il est difficile de lutter contre ce genre d’argument souvent invérifiable, d’autant plus si les outils en question sont connus et reconnus pour être particulièrement obsolètes et truffés de (non-)fonctionnalités amusantes. Sans compter les messages amusants que peuvent produire un débordement de pile … Tout de même, ce genre d’alerte doit effectivement vous inquiéter, mais ce n’est pas le message premier le plus inquiétant !

Il n’y a donc pas trente-six solutions : reprendre l’analyse du problème avec le porteur de mauvaise nouvelle. Avant de sortir la grosse artillerie des experts techniques qui, bien que roués à cet exercice, seront d’autant plus amers que le problème incriminé sera tout sauf avéré.

Fedora – Patcher un logiciel à partir de son SRPM finalement

Bon, reprenons. Après avoir joué avec la configuration cachée de rhythmbox, j’ai trouvé une politique de mélange satisfaisante. Malheureusement, à chaque fois qu’on active/désactive la lecture aléatoire, cette préférence disparaît. Autant dire que c’est intolérable, et qu’il va vraiment falloir mettre les mains dans le cambouis. Reprenons donc où nous en étions précédemment.

Écriture du patch

Vu que de nombreuses politiques sont possibles, mais qu’on retombe toujours sur la même en passant en mode aléatoire, c’est forcément quelque part en dur dans le code. Commençons par trouver quel callback gère l’activation du mode aléatoire.

Dans rb-shell-player.c, on trouve l’initialisation du menu « Contrôle », la définition du raccourci clavier, et… le fameux callback :

static GtkToggleActionEntry rb_shell_player_toggle_entries [] =
{
{ "ControlPlay", GTK_STOCK_MEDIA_PLAY, N_("_Play"), "<control>space", N_("Start playback"), G_CALLBACK (rb_shell_player_cmd_play) },
{ "ControlShuffle", GNOME_MEDIA_SHUFFLE, N_("Sh_uffle"), "<control>U", N_("Play songs in a random order"), G_CALLBACK (rb_shell_player_shuffle_changed_cb) },
{ "ControlRepeat", GNOME_MEDIA_REPEAT, N_("_Repeat"), "<control>R", N_("Play first song again after all songs are played"), G_CALLBACK (rb_shell_player_repeat_changed_cb) },
{ "ViewSongPositionSlider", NULL, N_("_Song Position Slider"), NULL, N_("Change the visibility of the song position slider"), G_CALLBACK (rb_shell_player_view_song_position_slider_changed_cb), TRUE },
};

Dans le même fichier, un peu plus loin, on tombe sur la définition de la fonction rb_shell_player_shuffle_changed_cb. Son fonctionnement est assez simple : elle lit l’état d’activation, l’inverse, et applique une politique définie par deux états d’activation :

  • la lecture aléatoire ;
  • la lecture en boucle.

Cette fonction est codée sous la forme d’une table d’association à deux dimensions, appelée state_to_play_order, que l’on retrouve en tête de fichier :

static const char* const state_to_play_order[2][2] =
 {{"linear",    "linear-loop"},
 {"shuffle",    "random-by-age-and-rating"}};

Il suffit donc de changer « shuffle » par « random-by-age », et le tour devrait être joué.

Pour faire le patch, il faut d’abord copier le fichier d’origine, modifier le fichier comme décrit, puis utiliser la commande diff :

# cp rb-shell-player.c rb-shell-player.c.shuffle
# ... édition de rb-shell-player.c ...
# diff -up rb-shell-player.c.shuffle rb-shell-player.c > ../../rb-better-use-random-by-age.patch

Modification du fichier SPEC

Il faut maintenant ajouter notre patch à la liste des patchs à appliquer  lors de la construction du RPM de rhythmbox. Il va également falloir trouver un numéro de version pour le RPM qui devra permettre de mettre à jour la version officielle, sans rentrer en conflit avec les numéros des prochaines versions officielles. Le plus simple est encore de suffixer le numéro de version du RPM bâtit, par exemple en le passant de 4 à 4.1.

En vert, voici les modifications appliquées à rhythmbox.spec :

Version: 0.12.8
Release: 4.1%{?dist}
License: GPLv2+ with exceptions and GFDL
...
Patch2: 0001-Don-t-load-AFC-devices-using-the-MTP-plugin.patch
Patch3: rb-better-use-random-by-age.patch
...
%patch2 -p1 -b .no-mtp-for-afc
%patch3 -p1 -b .shuffle
...

Construction du nouveau RPM, publication, et fin

Il n’y a plus qu’à finaliser tout ceci en produisant le RPM patché :

# rpmbuild -ba --clean --sign SPECS/rhythmbox.spec

puis en ajoutant le nouveau RPM à votre dépôt. La prochaine mise-à-jour yum fera le reste.

Tags: , , , , ,

Fedora – Patcher un logiciel à partir de son SRPM, ou pas

Quelque chose m’énerve dans le fonctionnement de rhythmbox : j’ai 8.534 morceaux à écouter et pourtant, même en lecture aléatoire, je retombe toujours sur les mêmes. En tout cas j’en ai l’impression (ce qui est totalement différent). Alors je voudrais faire deux choses :

  1. Modifier la règle de lecture aléatoire pour n’autoriser à la lecture que les fichiers les moins lus ;
  2. Éventuellement, vérifier la façon dont est fait le mélange des morceaux et le corriger pour éviter tout biais le cas échéant.

Comme mes études ont coûté beaucoup d’argent à mes parents en leur temps, et que je ne veux pas me prendre la tête à tout reconstruire de zéro, on va essayer de faire ça bien, à partir du SRPM de rhythmbox, pour en patcher le contenu, et produire un nouveau rpm qui sera dans mon propre dépôt, avec mon patch.

Télécharger un SRPM

yum n’est pas fait pour déployer les paquetages sources. Pour cela, il faut déjà avoir installé yumdownloader :

# yum install yum-utils

Grâce à ce petit utilitaire, on va pouvoir récupérer le paquetage source de rhythmbox à moindre frais :

# yumdownloader --source rhythmbox

Magie des nuits d’Arabie, un magnifique SRPM vient d’apparaître dans le répertoire courant :

# ls
rhythmbox-0.12.8-4.fc13.src.rpm

Installer les dépendances du SRPM d’origine

Comme on va vouloir chercher à reproduire ce logiciel presque à l’identique, autant commencer par en installer les dépendances. rpmbuild les donne bien volontiers :

# rpmbuild --rebuild rhythmbox-0.12.8-4.fc13.src.rpm
erreur: Dépendances de construction manquantes:
 libgpod-devel est nécessaire pour rhythmbox-0.12.8-4.fc13.x86_64
 gnome-media-devel est nécessaire pour rhythmbox-0.12.8-4.fc13.x86_64
 brasero-devel est nécessaire pour rhythmbox-0.12.8-4.fc13.x86_64
 gstreamer-plugins-base-devel >= 0.10 est nécessaire pour rhythmbox-0.12.8-4.fc13.x86_64
 totem-pl-parser-devel >= 2.21.1 est nécessaire pour rhythmbox-0.12.8-4.fc13.x86_64
 gnome-vfs2-devel >= 2.7.4 est nécessaire pour rhythmbox-0.12.8-4.fc13.x86_64
 avahi-glib-devel >= 0.6 est nécessaire pour rhythmbox-0.12.8-4.fc13.x86_64
 libmusicbrainz3-devel est nécessaire pour rhythmbox-0.12.8-4.fc13.x86_64
 dbus-devel >= 0.90 est nécessaire pour rhythmbox-0.12.8-4.fc13.x86_64
 dbus-glib-devel >= 0.70 est nécessaire pour rhythmbox-0.12.8-4.fc13.x86_64
 libnotify-devel est nécessaire pour rhythmbox-0.12.8-4.fc13.x86_64
 gstreamer-devel est nécessaire pour rhythmbox-0.12.8-4.fc13.x86_64
 gnome-doc-utils est nécessaire pour rhythmbox-0.12.8-4.fc13.x86_64
 pygtk2-devel est nécessaire pour rhythmbox-0.12.8-4.fc13.x86_64
 libsoup-devel >= 2.3.0 est nécessaire pour rhythmbox-0.12.8-4.fc13.x86_64
 lirc-devel est nécessaire pour rhythmbox-0.12.8-4.fc13.x86_64
 libmtp-devel est nécessaire pour rhythmbox-0.12.8-4.fc13.x86_64
 gstreamer-python-devel est nécessaire pour rhythmbox-0.12.8-4.fc13.x86_64
 libgudev-devel est nécessaire pour rhythmbox-0.12.8-4.fc13.x86_64
 libgnome-keyring-devel est nécessaire pour rhythmbox-0.12.8-4.fc13.x86_64
 libSM-devel est nécessaire pour rhythmbox-0.12.8-4.fc13.x86_64

Ah ! oui, quand même ! Bon, on ne se décourage pas :

# rpmbuild --rebuild rhythmbox-0.12.8-4.fc13.src.rpm 2>&1 | grep est | cut -d ' ' -f 1 | xargs yum install -y

et tout ce petit monde est installé en deux temps, trois mouvements.

Déployer le contenu du SRPM pour le patcher

Ce n’est pas la partie la plus compliquée. D’abord, installer le rpm source :

# rpm -i rhythmbox-0.12.8-4.fc13.src.rpm

Puis déployer l’archive de code d’origine :

# tar xjf rhythmbox-0.12.8.tar.bz2

qui nous créé un joli répertoire rhythmbox-0.12.8.

Écriture du patch … et changement de plan

On rentre dans le vif du sujet ! En fouillant un peu le projet, on tombe rapidement sur tout un tas de fichiers qui prennent (déjà !) en charge différentes manières d’opérer la lecture aléatoire :

# ls shell/rb-play-order-random*
shell/rb-play-order-random-by-age-and-rating.c
shell/rb-play-order-random-by-age.c
shell/rb-play-order-random-by-rating.c
shell/rb-play-order-random.c
shell/rb-play-order-random-equal-weights.c

Sac-à-papier ! C’est déjà tout fait ! Mais alors, pourquoi diable ce choix n’est-il pas disponible via l’interface graphique de rhythmbox ? Typiquement, ce que je souhaite, c’est appliquer la politique « random-by-age ».

Appliquer une politique donnée dans rhythmbox

On reprend les fondamentaux : je cherche « rhythmbox random age » dans Google, et paf ! Le premier lien m’instruit comment opérer une configuration moins immédiate de rhythmbox et de le régler enfin comme je le souhaite. Pour information, voici la marche à suivre :

# gconf-editor

Menu « /apps/rhythmbox/state », paramètre « play_order ». Il faut passer sa valeur de « shuffle » à « random-by-age » dans mon cas précis. Et le tour est joué.

Conclusion

L’investissement financier de mes parents n’est toujours pas rentabilisé. Même en cherchant à travailler intelligemment, je n’ai pas été suffisamment paresseux. À ma décharge, il n’était pas évident a priori que :

  • rhythmbox propose en natif de modifier la politique qui régit la lecture aléatoire, vu que ce n’est pas dans l’interface du logiciel ;
  • de connaître le nom de la politique qui correspond à mon besoin, et donc de trouver la bonne requête Google qui vient à mon secours.

Désolé donc, ce ne sera pas cette fois qu’on ira au bout de la manipulation, les développeurs de GNOME ont presque trop bien travaillé. Mais il y aura bientôt une autre occasion de reprendre ce thème et de l’adresser complètement !

Tags: , , , ,

Les paroles s’envolent les écrits restent

Je ne résiste pas à poursuivre l’analyse de tranches de vie que je reçois :

Hier matin, nouvelle génération : Ca plante toujours à la compilation. Conclusion : quand y a un mec qui dit dans son mail de mise- à-disposition des entrées « attention j’ai modifié le nom d’un fichier, faut mettre à jour les scripts » c’est pas pour faire chier, c’est bien parce qu’il faut mettre à jour les scripts.

C’est bien plus court que la fois précédente, et pourtant c’est toujours aussi riche en enseignements. Sur chaque projet, il ya un processus plus ou moins officiel de livraison : méls, bordereau de livraison, etc. Ils permettent deux choses :

  1. À celui qui le rédige, de vérifier qu’il n’oublie rien avant de passer le relais ;
  2. À celui qui le reçoit, de prendre connaissance d’informations complémentaires éventuelles en plus des informations habituelles qui permettent d’adresser le travail quotidien.

Du coup, négliger cet acte de livraison, par l’un ou l’autre des parties, est nécessairement source de soucis.

Deuxième point, plus directement destiné à l’intégrateur : les index de production, c’est la lie ! Quel est le but premier d’un index de production ? Lister les fichiers qui seront pris en compte dans l’exécutable final. À l’origine, l’intention est louable : ça donne l’illusion de maîtriser son périmètre de production. Je dis illusion parce que ça ne fait pas tout : identifier un nom de fichier ne permet pas d’en donner la version. Et puis surtout, avec le temps, un index de production, ça sert aussi à plein d’autres choses. Ça sert à filtrer le contenu du système de fichiers. Ça sert à ranger proprement ce qui ne l’est effectivement pas dans le système de fichier. Ça sert à cacher ce qui ne devrait pas être visible de tous. Ça sert d’excuse quand ce n’est pas à jour. Un vrai cache-misère. D’autant plus que par construction un index de production est obsolète et un frein à la productivité. Une surcouche inutile à l’encontre de la logique, qui fait bien souvent dire « mais il est là mon fichier, vas-y, compile, [propos ordurier exclusivement destiné au sélectionneur de l'Équipe de France, donc censuré]« 

Quel outil doit être le garant du contour de la production, c’est-à-dire la liste des fichiers et leurs versions ? Il y a un piège, il faut deux outils :

  1. Le gestionnaire de version de code source, qui permet toujours de retrouver un certain état global du projet à partir d’un identifiant approprié pour peu qu’il ait été posé ;
  2. La chaîne de production, basée sur des règles simples, comme par exemple : tout fichier dans SRC est compilé, et tout entête trouvé dans le répertoire INC est public.

Utilisez les outils pour ce qu’ils sont sensés faire, et tout de suite, ça ira mieux.