casts

Les casts en C++

Nombreux sont les programmeurs C++ qui ont d’abord été confrontés au C. Les deux langages partagent en effet bien des fonctionnalités… mais ont également de grandes différences.

Parmi ces différences, on trouve les opérateurs de conversion C++. Ils sont certainement l’un des points les plus mal compris par les développeurs C qui voient souvent en eux un verbiage inutile. L’objectif de cet article est de (dé)montrer l’utilité des opérateurs de conversion C++, en comparaison avec les conversions classiques, dites : “à la C” et de comprendre ce qu’ils peuvent apporter au programmeur en termes de maintenabilité et de sécurité.

Un petit mot sur les conversions

Les conversions (ou “cast” en anglais) sont un des outils incontournables du programmeur C++. Mais comme tout outil, il faut savoir les utiliser à bon escient.

Dans l’idéal, un programme doit contenir le moins possible de “casts” : les types doivent s’interfacer naturellement les uns avec les autres. Cela garantit un découplage du code et donc une meilleure maintenabilité. Cela ne signifie pas qu’il faille à tout prix éviter les “casts” mais simplement qu’il faut les utiliser avec parcimonie.

Dans les sections qui suivent, nous allons expliquer le rôle de chaque opérateur de conversion. Pour l’ensemble des sections, nous considérerons les classes suivantes lorsqu’il sera question de hiérarchie :

static_cast<>

Il permet plusieurs choses :

  • Expliciter les conversions implicites, supprimant du même fait tout avertissement que donnerait le compilateur si la conversion peut entraîner un risque. Exemple : double vers int.
  • Convertir vers et depuis n’importe quel type pointé à partir d’un void*. Exemple : void* vers unsigned char*.
  • Convertir au travers d’une hiérarchie de classe, sans effectuer de vérification préalable. Exemple : Base* vers Derived* ou Base& vers Derived&.
  • Ajouter l’attribut constant au type converti. Exemple : char* vers const char*.

Dans le dernier cas, notez que puisqu’il n’y a aucune vérification et que static_cast<> n’échoue jamais, le code suivant a un comportement indéfini (communément nommé en anglais “undefined behavior” ou “UB“) :

Notez que la notion de comportement indéfini n’offre par définition aucune garantie : le code peut avoir le comportement espéré, faire crasher le programme ou provoquer l’envoi d’un missile nucléaire sur Cuba.

Il ne permet pas de :

  • Convertir vers ou depuis un type pointé à partir d’un autre type pointé autre que void*. Exemple : unsigned char* vers char*.
  • Tester qu’une instance est celle d’un type dérivé. Exemple : tester qu’un Base* est en fait un Derived*.
  • Supprimer l’attribut constant du type converti. Exemple : const char* vers char*.

En bref

static_cast<> est sans doute l’opérateur de conversion que vous serez amené à utiliser le plus. Il ne permet que de réaliser des conversions sûres et à pour rôle principal celui d’expliciter les conversions implicites.

Dans le cas du polymorphisme, il est à préférer à dynamic_cast<> lorsque l’on a la garantie que la conversion va réussir.

dynamic_cast<>

Le seul rôle de dynamic_cast<> est de tester à l’exécution si un pointeur d’un type de base est en fait un pointeur vers un type dérivé.

Exemple :

Note : pour que dynamic_cast<> fonctionne, le type de base doit posséder au moins une méthode virtuelle.

Un appel à dynamic_cast<> est plus coûteux qu’un appel à static_cast<>car dynamic_cast<> effectue une recherche dans la “v-table” de l’instance à l’exécution pour déterminer son type exact.

On veillera donc à n’utiliser dynamic_cast<> que lorsqu’il n’y a aucune autre solution.

En bref

dynamic_cast<> est le seul opérateur de conversion à avoir un effet “indéterminé” jusqu’à l’exécution. Son utilisation n’a de sens que lorsque confronté à du polymorphisme. Dans les cas où la conversion est assurée de réussir, on lui préfèrera static_cast<> plus rapide et ne nécessitant pas que les classes possèdent une méthode virtuelle.

const_cast<>

const_cast<> permet de supprimer l’attribut constant ou volatile d’une référence ou d’un type pointé. Exemple : const char* vers char* ou volatile int vers int.

C’est notamment le seul opérateur de conversion à pouvoir le faire : même reinterpret_cast<> n’a pas ce pouvoir.

L’importance d’écrire un code “const-correct”

Directement relié aux opérateurs de conversion, l’écriture d’un code const-correct est un autre aspect du C++ souvent mal perçu par les programmeurs C. Le C est plus ancien et le mot clé const n’y a pas toujours existé; il a été emprunté au C++ par la suite.

Le fait d’indiquer qu’une variable est constante est un outil puissant permettant au compilateur de nous signaler certaines de nos erreurs qui auraient autrement passé la barrière de la compilation.

Qui ne s’est jamais trompé dans l’ordre des arguments d’un memcpy() ?

Les mots clé “const” ou “volatile” appliqués aux classes

En C++, les mots clé const et volatile s’appliquent évidemment aussi aux instances de classes mais ont des sémantiques différentes :

Le caractère const ou volatile s’applique récursivement aux membres de l’instance.

Il n’est possible d’appeler une méthode d’une classe que dans les cas suivants :

  • l’instance n’est pas const.
  • l’instance est const et la méthode est déclarée const.
  • l’instance est déclarée volatile et la méthode est déclarée volatile.
  • l’instance est déclarée const et volatile et la méthode est elle aussi déclarée const et volatile.

À propos de “volatile”

Certains lecteurs peuvent être perdus à la lecture du mot clé volatile qui, il faut bien l’avouer, n’est pas utilisé très souvent. Décrire précisément le rôle de volatile mériterait un article bien à part mais je vais tout de même dire en deux mots à quoi il sert :

Lorsqu’une variable est déclarée volatile, le compilateur n’a pas le droit d’optimiser sa valeur (mise en cache processeur) lors de tests.

Ainsi sans volatile sur la variable do_loop, le code suivant :

Risquerait d’être optimisé en tant que :

Ce qui est correct dans la plupart des cas… sauf si do_loop peut être modifié par un autre thread. C’est principalement dans ce genre de cas que volatile trouve son utilité.

Erreurs courantes

Une erreur courante concernant const_cast<> consiste à supposer que l’on peut toujours supprimer le caractère constant d’une variable.

Ceci est évidemment faux : on ne peut supprimer le caractère constant (respectivement volatile) d’une variable que lorsque celle-ci a été déclarée non-const (respectivement non-volatile).

Ainsi le code suivant a un comportement indéfini :

Un autre cas courant est celui des variables membres qui servent à mettre en cache un résultat :

L’utilisation de const_cast<> ici est erronée : si on déclare une instance const de MyClass, m_value_cache est aussi const lors de sa définition. L’utilisation de const_cast<> est la même que dans l’exemple précédent et a comportement indéfini.

La bonne solution est d’utiliser le mot clé mutable, qui permet à une variable membre de ne pas avoir les mêmes contraintes const/volatile que son instance parente :

En bref

const_cast<> est le seul opérateur de conversion à pouvoir supprimer le caractère const ou volatile d’une variable. L’utilisation de const_cast<> doit rester très rare : le contraire indique souvent une importante erreur de design. Son seul usage habituellement toléré est l’interfaçage avec des bibliothèques historiques qui ne sont pas const-correct.

reinterpret_cast<>

Il s’agit de l’opérateur de conversion le plus dangereux, et du plus mal utilisé. Son rôle est de dire au compilateur : “réinterprète-moi la représentation binaire de ce type en tant qu’un autre type”.

Il permet :

  • De convertir n’importe quel type pointé en une autre, même lorsque ceux-ci n’ont aucun rapport. Exemple : int* vers double*.
  • De convertir un type pointé en sa représentation intégrale et vice et versa. Exemple : int* vers int.

Il est à noter que ces conversions sont dépendantes de l’implémentation. En d’autres termes, le compilateur est libre de faire ce qu’il veut concernant la conversion basée sur reinterpret_cast<> mais ce comportement doit être constant : il ne s’agit pas de comportement indéfini; le comportement est bien défini, simplement pas par le standard C++ mais votre version du compilateur. Si vous vous basez sur cette dépendance de l’implémentation, votre code est donc non-portable.

La seule garantie délivrée par le standard C++ concernant reinterpret_cast<> est que si vous convertissez un type A en un type B, puis de nouveau en un type A, le comportement est bien défini et vous récupérez bien la valeur de départ.

On comprend dès lors facilement le danger que peut représenter reinterpret_cast<>.

Voici un exemple d’utilisation :

Cas particuliers

Le peu de garanties associées à reinterpret_cast<> rendent celui-ci quasiment inutile dans la plupart des cas. Il y a cependant certaines exceptions de fait qui justifient une utilisation de reinterpret_cast<> sans nuire à la portabilité :

Les conversions entre les types char* et unsigned char* bien que non spécifiées par le standard, sont en pratique supportées par tous les compilateurs et produisent le comportement attendu. Le compilateurs ont par ailleurs de plus fortes contraintes à leur égard (spécifiquement au niveau de leur représentation) pour des raisons de compatibilité ascendante avec le C.

Vous pouvez donc clairement supposer qu’un reinterpret_cast<> entre un char* et un unsigned char* sera à la fois portable et défini.

Polymorphisme

reinterpret_cast<> utilisé dans le cadre d’une conversion faisant intervenir du polymorphisme a un comportement non défini. Il n’est ainsi pas correct d’effectuer un reinterpret_cast<> entre par exemple un Base* et un Derived*.

En bref

reinterpret_cast<> est l’opérateur de conversion le plus dangereux : permettant de faire ce qu’aucun autre ne peut faire (des conversions entres des types non liés) il convient de l’utiliser avec la plus grande prudence. En pratique, on lui préfèrera static_cast<> qui permet d’effectuer des conversions plus sûres, y compris vers et depuis des types pointés génériques (void*). Son seul usage toléré est l’interfaçage avec du code C ancien qui utilise pour ses paramètres de “buffer” des char* ou unsigned char* au lieu des void*.

Old-school : les conversions “à la C”

Le C++ supporte toujours l’ancienne syntaxe concernant les conversions “à la façon C”. Cependant, le standard précise clairement l’effet d’une telle conversion :

Le “cast” suivant : (Type)valeur ou Type(valeur)

Sera équivalent à, par ordre de préférence :

  1. un const_cast<>
  2. un static_cast<>
  3. un static_cast<> suivi d’un const_cast<>
  4. un reinterpret_cast<>
  5. un reinterpret_cast<> suivi d’un const_cast<>

Les bonnes pratiques indiquent souvent que l’utilisation de ce type de conversion est à bannir, principalement parce qu’il peut résulter silencieusement en un reinterpret_cast<>, qui comme nous l’avons vu, peut se révéler extrêmement dangereux. De plus, l’usage des alternatives modernes aux opérateurs de conversion permet de spécifier clairement l’intention du programmeur et de protéger contre les erreurs involontaires (comme celles que nous avons vu avec const_cast<>).

Une autre utilité

Les “casts” à la C offrent également une possibilité qui n’est permise par aucun autre opérateur de conversion : celle de convertir vers une classe de base au travers d’un héritage privé. Ce type d’héritage est très souvent critiqué et fortement déconseillé. Je ne détaillerai pas ici les conséquences et les raisons de ce type d’héritage; c’est un sujet qui mérite son propre article.

Conclusion

Il y a beaucoup à dire sur les opérateurs de conversion et encore plus à apprendre. Nous avons vu que bien utilisés, ils sont un outil puissant et un allié du programmeur. Protégeant contre les erreurs involontaires et révélant les erreurs de conception, ils restent pour certains dangereux et sont tout de même à utiliser avec la plus grande précaution.

Une bonne connaissance de ces opérateurs de conversion et de leurs limites reste indispensable à la réalisation de programmes maintenables en C++.

Références

Voici une série de liens (en anglais, pour la plupart) qui m’ont inspiré dans la rédaction de cet article.

N’hésitez pas à les consulter pour obtenir d’autres informations. Je vous recommande également de vous inscrire sur Stack Overflow qui est à mon sens le meilleur site de questions/réponses concernant la programmation : le niveau des questions et surtout des réponses y est vraiment très élevé.

Comme toujours bien sûr, vous pouvez également utiliser les commentaires pour obtenir des précisions sur un point ou l’autre.

Merci pour votre lecture !

inline

La directive “inline” démystifiée

Le C++ est sans conteste l’un des langages les plus complets mais aussi les plus complexes existant dans le monde du développement en entreprise. Ses grandes flexibilité et diversité en font à la fois un langage puissant et dangereux. Il ne s’agit pas ici d’en faire une nouvelle présentation; de nombreux ouvrages lui sont déjà consacrés : qu’il s’agisse des “design patterns” ou de fonctionnalités générales, il y en a vraiment pour tous les goûts.

Cependant, j’ai décidé aujourd’hui de traiter d’un point en particulier, souvent mal perçu par les débutants et parfois même par des gens plus expérimentés : il s’agit de la directive inline.

Piqûre de rappel

Avant d’avancer sur le chemin de “l’inlining”, rappelons quelques principes élémentaires du C++.

Remarque : En tant que programmeur expérimenté, vous connaissez probablement déjà tout ce qui suit. Vous devriez tout de même prendre le temps de lire cette partie pour deux raisons : la première, ça ne fait jamais de mal. Et la deuxième : si jamais j’écrivais une bêtise, vous pourriez gentiment me le faire remarquer ! :D

Le C++ est un langage compilé (par opposition à langage interprété), ce qui signifie qu’il induit la génération d’un “binaire” lors d’une phase appelée compilation. Ce binaire peut être un fichier exécutable (.exe sous Windows), une bibliothèque (.so/.a sous Unix, .lib/.dll sous Windows) ou un fichier objet intermédiaire (.o sous Unix, .obj sous Windows).

La phase que l’on nomme “compilation” est en fait séparée en trois étapes successives :

  1. Le prétraitement (ou “preprocessing”), qui va se charger de remplacer les différentes macros présentes dans le code par leur véritable valeur. Le résultat de ce prétraitement est passé au “compilateur”.
  2. La compilation, qui transforme le code pré-traité en langage machine au sein de fichiers objets. En pratique, il y a un fichier objet généré par unité de traduction (ou “translation unit”).
  3. L’édition des liens, qui rassemble les fichiers objets générés au sein d’une seule entité (une bibliothèque dynamique ou un exécutable). Si on a déclaré et utilisé une fonction mais que son implémentation est absente, cette étape ne passe pas.

Remarque : Habituellement, dans le cas d’une bibliothèque statique, l’édition des liens n’est pas effectuée : il s’agit d’une simple concaténation des fichiers objets.

Les bonnes pratiques du C++ dictent ensuite que lorsque l’on écrit le code d’une classe, on place sa définition (et donc sa déclaration) dans un fichier dit “header“, et son implémentation dans un fichier “source“.

Il existe une règle nommée “règle de la définition unique” (ou ODR : “One Definition Rule“) qui dit que l’on peut déclarer autant de fois que l’on veut une classe, une fonction, etc. mais qu’on ne peut la définir qu’une seule fois. Nous verrons plus tard en quoi inline influe à ce niveau.

Un exemple simple

Prenons un exemple tout simple avec une classe “Person” qui représente une personne. :)

Voici le fichier header :

Dans ce header, nous avons déclaré et défini le type Person.

Son implémentation, elle, va dans le fichier source :

Si nous reprenons les trois étapes de la compilation, voici ce que se passe pour chacun des fichiers :

Le processus commence par le choix de l’unité de traduction à compiler : ici, il s’agit du fichier “person.cpp”.

  • Le préprocesseur analyse chaque ligne, procède à l’inclusion du fichier “person.hpp” (directive #include) tel qu’on le ferait avec un copier-coller. Au passage, tous les commentaires dans les fichiers sont supprimés, et les éventuelles macros sont remplacées.

On se retrouve avec un fichier qui se rapproche théoriquement de ça :

  • Le compilateur vérifie la syntaxe de l’ensemble du fichier et compile chaque implémentation de fonction (ou méthode) qu’il rencontre. Ici, les codes du constructeur Person::Person() et du “getter” name() sont effectivement transformés en langage machine au sein d’un fichier objet.
  • Enfin, si le programme fait référence à Person::Person() ou Person::name(), l’édition des liens associera l’appel de fonction à son adresse effective.

Les idées fausses sur la directive “inline”

S’en suit ici un florilège des idées reçues que j’ai déjà entendu (ou prononcé :D) ça et là sur inline :

  • “Ça sert à ordonner au compilateur de ne jamais compiler le code de la fonction.”
  • “C’est quand on écrit directement du code dans la définition d’une classe.”
  • “C’est pour accélérer les appels à une fonction.”
  • “Ça sert à déclarer des macros intelligentes.”
  • “Ça indique que la fonction a une liaison interne.”

En réalité, voici la raison d’être du mot clé inline, telle que définie par Bjarne Stroustrup :

The inline specifier is a hint to the compiler that it should attempt to generate code for a call of the inline function rather than laying down the code for the function once and then calling through the usual function call mechanism.

Pour ceux que l’anglais rebute :

La directive inline est une information donnée au compilateur lui indiquant qu’il devrait essayer de générer du code pour chaque appel de la fonction plutôt que de générer une seule fois le code de façon générique et d’utiliser le mécanisme habituel d’appel de fonction.

En gros, on apprend que la directive inline n’est pas un ordre, mais une simple indication, que le compilateur est d’ailleurs libre de refuser. Souvenez-vous que c’est son travail d’optimiser le code généré, pas le vôtre.

En pratique, on utilisera donc pas inline pour des raisons d’optimisation, mais simplement pour modifier la “One Definition Rule”. En effet, là où une fonction ne doit habituellement avoir qu’une seule définition parmi toutes les unités de traductions, le fait de la rendre inline change la règle et indique que la fonction doit avoir la même définition dans chacune des unités de traduction qui l’utilise.

Un exemple

Prenons pour exemple le célèbre cas de la fonction factorielle.

Remarque : Le choix de cet exemple n’est pas innocent. Bjarne Stroustrup utilise lui-même cet exemple lorsqu’il parle de la directive inline.

Une implémentation naïve de factorielle est la suivante :

Note : Cette fonction n’est pas optimale (on répète inutilement le test “(n <= 1)" à chaque itération. Mais elle convient très bien pour notre exemple.

Supposons que cette fonction est déclarée dans un header de notre bibliothèque et qu’un utilisateur de cette bibliothèque utilise quelque-part dans son code la fonction, par exemple :

Lors de la compilation de ce code, il peut se passer plusieurs choses :

  1. Le compilateur peut décider de compiler la fonction factorial comme n’importe qu’elle autre fonction. Elle aura en pratique un passage de paramètre, une pile d’appel etc.
  2. Ou il peut décider de remplacer factorial(6) par 6 * factorial(5) directement.
  3. Enfin, un compilateur très intelligent peut carrément décider “d’inliner” complètement l’appel et de remplacer factorial(6) par 720, optimisant de ce fait drastiquement le programme.

On notera que l’appel d’une fonction inline est sémantiquement identique à celle d’une fonction “classique”. Il est possible d’en hériter, de la surcharger, etc.

Utilisation au quotidien

Voici quelques usages corrects de fonctions “inline” :

  • Dans le premier cas, la méthode value() est directement définie au sein de la définition de la classe. Elle est implicitement déclarée inline. L’ajout du mot clé inline serait redondant et donc inutile.
  • Dans le second cas, la méthode add() est simplement déclarée (sans mot clé particulier) au sein de la classe. Sa définition est écrite dans le fichier header, en dehors de celle de la classe, mais toujours dans le même namespace, tel qu’on le ferait si on implémentait cette fonction dans le fichier source. Dans ce cas, la définition de la fonction étant écrite au sein même du fichier header (et donc potentiellement présente dans plusieurs unités de traduction), on doit cependant ajouter le mot clé inline pour s’affranchir de la “One Definition Rule“.
  • Enfin, dans le dernier cas, la méthode sub n’est pas une vraie méthode mais un template. L’ajout de la directive inline n’est pas obligatoire, car encore une fois, la définition de la méthode se situe dans la définition de la classe. Elle est donc implicitement inline.

N’utilisez inline que sur de très petites fonctions (notion subjective mais en gros : si votre fonction fait plus qu’une simple opération arithmétique ou un retour de valeur, elle n’a surement pas d’intérêt à être inline) et si possible, uniquement sur celles qui ont vocation à être appelées souvent. Les meilleurs candidats pour inline sont généralement bien sûr les getters, les setters, ou encore les destructeurs virtuels vides.

Conclusion

La première fois que l’on m’a parlé du mot clef inline, on me l’a présenté comme un moyen d’optimiser les appels de fonction. Pendant très longtemps, j’ai d’ailleurs soutenu cette version aveuglement. Mais nous avons vu aujourd’hui que les compilateurs sont suffisamment capables pour déterminer d’eux-même quand, quoi et comment optimiser.

En pratique, on retiendra que de bonnes connaissances concernant la “One Definition Rule” et la directive inline sont indispensables à l’écriture d’un code réutilisable et maintenable.

J’espère que cet article vous aura appris quelque-chose (ou à défaut intéressé). N’hésitez pas à me signaler dans les commentaires les éventuelles erreurs que j’aurais pu commettre.

Bon code !

Commande personnalisée (icône)

Personnaliser la barre d’action rapide sous Windows Vista/Seven

Aussi longtemps que je me souvienne, j’ai toujours été très intéressé par la personnalisation. Quand je débutais la programmation, mes premiers programmes étaient des alternatives au “shell Windows” (explorer.exe). Évidemment, mes programmes de remplacement étaient pour la plupart encore plus pauvres que ceux à remplacer et ne faisaient généralement pas long feu ! Mais il s’agissait d’un bon exercice.

Aujourd’hui, le shell Windows a bien changé. Il offre nativement sous Vista (et encore plus sous Seven) un bon nombre de raccourcis pour des fonctions utilisées souvent. Toutefois, ses capacités de personnalisation pour un utilisateur lambda restent encore hélas bien limitées.

Dans cet article, je vais vous montrer comment personnaliser la barre d’action rapide pour y ajouter des fonctions “maison”.

Barre d'action

La barre d'action modifiée

Le principe

Cette modification n’est pas officiellement supportée par Microsoft (ou en tout cas, je n’ai rien trouvé qui en parlait), mais elle reste relativement propre. En d’autres termes, si c’est pour modifier votre propre poste de travail et pour votre confort personnel, allez-y, mais si vous souhaitez baser une application commerciale dessus, c’est à vos risques et périls ! :)

Le paramétrage de la barre d’action, comme beaucoup d’autres choses sous Windows, se fait par une modification de la base de registre. Si vous n’êtes pas déjà familier avec la base de registre Windows, je vous recommande sincèrement de ne pas continuer.

Chaque “type” de répertoire possède une clé unique associée à un paramétrage. Nous allons modifier les paramètres des dossiers de type “générique” pour que nos nouvelles commandes apparaissent à coté des commandes habituelles.

Les mains dans le camboui

Ouvrez, en tant qu’administrateur, l’éditeur de base de registre (“regedit”).

Placez-vous dans la clé suivante :

Puis localisez la clé nommée :

Il s’agit du GUID associé aux répertoires génériques. Ouvrez cette clé; vous devriez obtenir une fenêtre qui ressemble à ça :

Éditeur de base de registre

Paramètres pour les dossiers génériques

Si vous n’avez pas de sous-clé nommée “TasksNoItemsSelected” ne vous inquiétez pas, c’est même plutôt normal. Nous allons justement la créer.

Par défaut, la clé sélectionnée a pour propriétaire l’utilisateur système “TrustedInstaller”, utilisé uniquement lors des mises à jour Windows. Pour ajouter nos propres clés, il nous faut nous rendre propriétaire de cette clé, et de ses sous-clés.

Faites un clic droit sur la clé “{5c4f28b5-f869-4e84-8e60-f11db97c5cc7}”, puis choisissez le menu “Autorisations”.

Autorisations

La fenêtre d'autorisations

Cliquez sur “Avancé” puis, dans l’onglet “Propriétaire”, sélectionnez votre compte comme nouveau propriétaire. N’oubliez pas de cocher la case marquée “Remplacer le propriétaire des sous-conteneurs et des objets” puis validez par “OK”.

Une fois devenu propriétaire de la clé, vous pouvez désormais créer des sous-clés.

Un exemple avec Powershell

Nous allons, pour exemple ajouter une action qui lance, dans le répertoire ouvert sous l’explorateur, une commande Powershell correctement positionnée. Cet exemple est bien entendu très facilement adaptable pour d’autres besoins.

Commençons par créer la sous-clé “TasksNoItemsSelected” si elle n’existe pas déjà.

Puis créez une sous-clé nommée ‘0’ pour la première commande que nous ajoutons. Pour les prochaines commandes, il faudra bien entendu remplacer ‘0’ par ‘1’, ‘2’, ‘3’, etc.

Ajoutez toutes les clés requises pour obtenir l’arborescence suivante :

Arborescence

L'arborescence de la commande "Ouvrir Powershell"

Pour ceux qui se demanderaient d’où sort la valeur “{C87DA2BC-C93B-439a-8568-88E93DFD2AB1}”, il s’agit en fait d’un GUID que j’ai généré arbitrairement. Vous pouvez prendre n’importe-quelle autre valeur ici, mais assurez-vous qu’elle ne corresponde pas déjà à un type connu sur le système ! Pour ceux qui ont installé Visual Studio, vous pouvez utiliser l’outil “GUID generator” pour le générer. Pour les autres, vous pouvez vous rendre sur ce site (n’oubliez pas d’ajouter les accolades).

La clé “{C87DA2BC-C93B-439a-8568-88E93DFD2AB1}” doit contenir les valeurs suivantes :

Valeurs

Les valeurs de la clé

Les différentes clés ont les significations suivantes :

  • La valeur “par défaut” contient le nom système que vous choisissez de donner à votre bouton d’action.
  • La propriété “Icon” contient le chemin vers la ressource “icône” à associer au bouton.
  • La propriété “InfoTip” contient le texte qui s’affiche lorsque l’on survole le bouton avec le curseur.
  • Enfin, la propriété “Title” contient le texte affiché sur le bouton.

Pour terminer, indiquez la commande à exécuter en modifiant la valeur par défaut de la sous-clé “command” :

Commande

La commande à exécuter

Ici, nous indiquons la commande suivante :

Je ne rentrerai pas dans les détails de cette commande qui sont propres à Powershell, mais soulignerai uniquement la présence du paramètre “%*”.

Je n’ai pas trouvé de liste exhaustive indiquant la liste et la signification des différents paramètres, mais je suis arrivé à la conclusion suivante :

  • “%*” sera remplacé dans la commande par “tous les paramètres”.
  • “%2″ sera remplacé par le dossier en cours (celui dans lequel on appuie sur le bouton d’action).

Je vous invite à expérimenter les différents paramètres possibles. Si vous en trouvez d’autres ou des informations sur leur signification, n’hésitez pas à commenter, et je mettrai cet article à jour en conséquence.

Dans tous les cas, ouvrez un navigateur (dans “C:\” par exemple) et vous devriez obtenir le résultat suivant :

Commande personnalisée

Commande "Ouvrir Powershell" personnalisée

N.B : Il est possible que le bouton ne s’affiche pas dans certains répertoires spéciaux comme par exemple “Ma bibliothèque” sous Windows Seven. Je n’ai pas encore trouvé comment résoudre ce problème et pour être franc, je n’ai pas vraiment cherché. Si vous trouvez une solution, n’hésitez pas à vous faire connaître !

Des possibilités multiples

Il ne s’agit que d’un aperçu très bref des possibilités offertes par la personnalisation de la barre d’action. Je suis convaincu que l’on peut aller bien plus loin et que bien d’autres options se cachent ça et là.

En tout cas, cette petite astuce bien pratique m’a déjà servie de nombreuses fois et j’espère que cet article vous aura intéressé. Si l’idée vous tente et que vous êtes amené à le faire de nombreuses fois, vous pouvez également générer un fichier “.reg” pour éviter la saisie manuelle.

En tout cas, bonne personnalisation ! Et n’hésitez pas à partager vos idées !

yellow

Découverte de libsystools 2.1

Cette semaine, j’ai eu l’immense honneur d’effectuer la “release” de la version 2.1 de notre bibliothèque de base : libsystools. Cette version est le fruit de nombreuses heures de travail de l’équipe freelan et apporte un bon lot de nouveautés par rapport à la dernière version.

Cet article va tenter de vous faire découvrir ces nouveautés, d’expliquer certaines décisions de design et bien entendu de vous donner envie de l’essayer !

Présentation

Il y a 2 ans, le code de freelan commençait à être volumineux. Bon nombre de classes outils étaient écrites qui pouvaient intéresser d’autres projets. Nous avons donc décidé de rendre cet ensemble de classes autonome et c’est ainsi qu’est né libsystools.

libsystools propose une interface C++ moderne pour un certain nombre de bibliothèques C mais aussi des classes nouvelles (notamment SmartBuffer).

Ses principaux domaines d’application sont :

  • La gestion du xml (parsing, génération, modification, signature);
  • la gestion de la cryptographie (RSA, AES, SHA);
  • la gestion des certificats;
  • la gestion des ports série;
  • la gestion du SSL (TLS, DTLS);
  • la gestion du réseau (Socket, SocketAddress, SocketAddressResolver) en IPv4 et IPv6.
  • la gestion facilité de la mémoire (SmartBuffer);
  • une implémentation basique d’un client UPnP;
  • une implémentation basique d’un client HTTP;
  • une implémentation simple d’une classe de log;
  • la gestion de l’encodage (UTF-8, UTF-16, ISO-8859-1, etc.);
  • différentes méthodes pour calculer de checksum, compresser des flux, etc.

libsystools a été conçue dès le départ pour être extrêmement portable, qu’il s’agisse des systèmes d’exploitation ou des architectures. Elle est donc utilisable sur Windows (MinGW, Visual Studio 2010), Linux (gcc), Mac OSX (gcc), UNIX (gcc) aussi bien en 32 bits qu’en 64 bits.

L’ensemble de ses classes est documenté et différents exemples sont fournis qui traitent de chacun de ses domaines d’application.

libsystools se base sur différentes bibliothèques :

  • libxml2
  • libxmlsec1
  • openssl
  • libiconv
  • boost

Faciliter l’existant

Les bibliothèques sur lesquelles se base libsystools sont bien écrites et fiables. Cependant, elles ne fournissent qu’une interface en C.

Lorsqu’on utilise que peu ces bibliothèques dans un projet, il est acceptable de se servir simplement de ces interfaces C. Cependant, lorsqu’un projet en fait un usage intensif, le code devient très rapidement très dur à maintenir.

Qui n’a jamais eu à écrire un code de ce style ?

Bien sûr, un bon programmeur C++ simplifiera l’écriture de ce genre de code avec l’utilisation de classes conteneurs qui se chargent de libérer la ressource associée lors de leur destruction. Mais devoir refaire ce travail d’encapsulation à chaque utilisation est fastidieux, et ne règle qu’une partie du problème.

C’est dans cet esprit qu’on été développées les classes de libsystools : des wrappers simples, faciles à utiliser et efficaces.

En utilisant libsystools, le code précédent aurait plutôt ressemblé à :

Ce qui est bien plus lisible et maintenable, et présente l’avantage d’être “exception-safe”.

Utilisation & Exemples

Nous pourrions exposer les différents aspects conceptuels qui ont motivé chaque décision pendant des heures et sur plusieurs pages, mais après tout, en programmation, il n’y a pas plus explicite que le code. Voici donc quelques exemples d’utilisation commentés.

SmartBuffer, ou comment gérer la mémoire de façon intelligente

S’il ne fallait garder qu’une seule classe, ce serait celle-ci : SmartBuffer est au coeur de libsystools. Utilisée partout, SmartBuffer représente un tableau d’octets à taille variable et dont les différentes instances peuvent partager leur mémoire.

Dans bon nombre de cas, l’utilisation de SmartBuffer permet de simplifier le code existant en remplaçant les paramètres de type :

Par un simple :

La lecture et la maintenance s’en trouvent tous deux grandement facilités.

XML, les wrappers autour de libxml2

Avec l’engouement de tous les domaines pour le web, il est rare aujourd’hui d’avoir du code à produire qui ne nécessite pas de manipuler du XML. En C++, plusieurs solutions existent.

Nous avons opté pour la libxml2 pour plusieurs raisons :

  • C’est une bibliothèque mature, complète et quotidiennement maintenue;
  • elle est portable sur plusieurs architectures et plateformes;
  • elle s’interface très bien avec OpenSSL au sein de libxmlsec1 pour le support des signatures XML.

Le module XML de libsystools se décompose en trois parties :

  • Les éléments DOM, qui représentent de façon statique un arbre XML;
  • les “writers” qui permettent de générer du XML;
  • les objets XPath, qui permettent d’effectuer des requêtes dans les éléments DOM.

Voyons un exemple d’utilisation :

Reprenons cet exemple point par point :

  • Ligne 20 : nous déclarons un xml::Initializer qui existera pour toute la portée du main. Cet objet permet d’initialiser la libxml2 et de garantir sa libération au moment opportun, de façon automatique.
  • Ligne 28 : nous créons un XmlDocumentWriter. Cet objet permet une construction facilité d’un arbre XML en construisant l’un après l’autre ses différents éléments.
  • Lignes 30 à 38 : Nous créons chacun des noeuds XML. Les différentes fonctions prennent des systools::String en paramètre et supportent donc parfaitement la gestion des différents encodages.
  • Ligne 40 : Nous récupérons un arbre XML complet à partir du writer.
  • Ligne 46 : Nous récupérons l’instance XPath associé à l’arbre XML (cette instance est partagée par tous les noeuds d’un même arbre)
  • Ligne 48 : Nous associons un nom court au namespace nommé “namespace” dans l’instance XPath.
  • Ligne 53 : Nous effectuons une requête XPath sur la racine du document.
  • Ligne 57 : Nous effectuons une requête XPath sur un sous-noeud du document.

La manipulation du XML est grandement facilitée. On voit que seules quelques instructions suffisent à construire un arbre, à y naviguer et à en extraire les informations utiles.

Le module réseau

Une autre partie importante de libsystools est son module réseau. La manipulation des différentes fonctions et structures réseau d’un système a toujours été la bête noire des programmeurs novices. Entre les spécificités propres à chaque système d’exploitation, et les fonctions dépréciées suite au prochain passage à IPv6 (ça approche, si si, croyez-moi !), il n’est pas toujours évident de produire un code propre et robuste.

Le module réseau de libsystools a été conçu pour résoudre cette problématique. Il propose :

  • Une classe qui permet représenter une adresse de socket (IPv4, IPv6, etc.);
  • une classe pour effectuer des résolutions de nom ou d’adresse sur le réseau;
  • des classes Socket et SecureSocket qui encapsulent respectivement une socket classique et une socket SSL (en TLS ou DTLS);
  • une classe “Select” qui encapsule de façon objet les appels à la méthode “select()”;
  • une classe pour représenter les adresses Ethernet;
  • des outils de conversion entre adresse IP et représentation numérique.

Démontrons la simplicité de son utilisation en montrant le code d’un example qui va successivement :

  1. Chercher l’adresse de socket associée à 127.0.0.1:34000 en TCP.
  2. Créer une socket
  3. Connecter cette socket sur le serveur TCP situé à l’adresse recherchée en 1.
  4. Attendre la réception d’un message.
  5. Se déconnecter et libérer la socket et toutes les ressources associées.

Pas si mal pour un code d’une cinquantaine de lignes qui gère correctement toutes les erreurs potentielles et la libération des ressources, non ?

Pour conclure

Vous n’avez eu ici qu’un très bref aperçu des possibilités offertes par la libsystools. Pour découvrir plus avant la bibliothèque, je vous invite à consulter sa documentation en ligne.

En tout cas, j’espère sincèrement que cette présentation aura attisé votre curiosité et vous aura donné envie d’essayer la bibliothèque lors de vos prochains développements. Bien entendu, si vous avez des questions générales sur la bibliothèque et des interrogations concernant son évolution future, n’hésitez pas à commenter cet article ou directement contacter l’équipe sur la mailing-list (en anglais).

Bon code ! :)

Développer avec Qt pour Android

C’est possible ?

Dans ce petit article je vais vous parler du développement Android avec Qt et en C++, en effet, j’ai travaillé dernièrement dans une entreprise d’automatisation et de régulation des bâtiments où un des développeurs était en charge d’un projet d’application Android. La qualité de ses développements m’a donné envie de tenter l’aventure. Malgré la magnifique API de Java pour android je voulais pouvoir déployer pour Windows, Linux, Mac, Symbian et Android la même application. Mon choix se portait donc sur mon framework préféré : Qt et naturellement mon langage préféré. Je ne serai jamais assez redevant à Bjarne Stroustrup =D.

Développer des applications basées sur Qt pour android est possible via le projet android-lighthouse, qui fonctionne très bien ! En effet ce dernier rend possible l’exécution d’une application C++/Qt complète ou encore l’utilisation en Java des libraires écrites avec le framework.

Qt Quick UI - BogDan Vatra

Lighthouse

Quant à lighthouse c’est un projet que l’équipe du Framework Qt a lancé avant la version 4.7 pour rendre le framework Qt portable à n’importe quelle plateforme facilement. En effet cela requiert très peu de code spécifique à la plateforme afin de faire fonctionner toutes les librairies Qt.

Depuis quelques semaines lighthouse est passé dans la branche stable de Qt. Grâce à android-lighthouse on peut d’ailleurs voir que le portage des bibliothèques est très rapide. Seulement quelques mois ont été nécessaires pour obtenir une version pleinement (ou presque) fonctionnelle: même les interfaces basées sur le QML fonctionnent! C’est grâce à BogDan Vatra, initiateur du projet, que le port de Qt pour android en est arrivé à cette maturité qui démontre ainsi que Qt peut être porté n’importe où: Code less, do more, deploy everywhere!

Awesome!

Cela rend le portage d’applications Qt sur Android très simple, écrire une application avec le framework Qt signifie que l’on peut désormais la compiler sans effort pour : Symbian, Windows, Mac, Linux & Android ! :) C’est à mon sens parfait pour construire une base de librairies réutilisables dans une entreprise. Dans cette idée il est également possible de développer des bibliothèques basées sur les fonctionnalités de Qt et de les lier avec JNI afin d’apporter des fonctionnalités natives aux applications Java Android existantes.

Je vous présenterai dans cet article les différentes versions d’Android supportées, les quelques limitations et clarifications nécessaires, ainsi que les procédures à suivre afin de compiler pour et lancer sur Android votre application Qt.

Les versions d’Android compatibles

Lorsque le projet Qt android-lighthouse a été créé, seuls les périphériques Android 1.5 étaient supportés avec Qt lié en statique, ce qui n’est plus le cas aujourd’hui. En effet la branche actuelle du dépôt supporte seulement Qt lié dynamiquement (cela réduit l’utilisation de la mémoire – James Noble & Charles Weir 2001 – Small Memory Software, puisque chacune des applications partagent les mêmes bibliothèques Qt). Cette dernière supporte aujourd’hui les versions d’Android actuelles du marché: 1.6, 2.0, 2.1 et 2.2. N’hésitez pas à essayer avec l’émulateur Android car il fonctionne comme les véritables périphériques, plus d’un développeur Android m’en a confirmé ses qualités. :)

Quelques Limitations

Il y a actuellement (25/11/2010) quelques limitations, par exemple le rendu est réalisé uniquement par le software, les accélérations matérielles Open GL ne sont pas utilisées. Toutefois ce n’est certainement qu’une question de jours, car jusqu’aujourd’hui le portage de Qt sur Android a été très rapide et est toujours aussi actif.

Une autre limitation qui sera bientôt fixée d’après les initiateurs du projet est que l’on ne peut utiliser QtMultimedia pour jouer des sons, il y a d’autres solutions pour y parvenir, toutefois le port de QtMultimedia sera bientôt fait, et d’après l’initiateur du projet cela devrait être “le correctif le plus facile” qu’il lui reste à faire.

Quelques Clarifications

Vous n’avez pas besoin d’être “root” ou d’avoir accès au shell root sur votre périphérique pour déployer des applications Qt, cela signifie que vous pourriez envoyer l’application sur le Google Market. Toutefois actuellement il est plutôt déconseillé de le faire, il vaudrait mieux attendre que cela soit plus testé et utilisé (ce que fait actuellement une communauté grandissante: http://groups.google.com/group/android-qt/).

Préparez votre environnement de développement

J’ai écrit les instructions suivantes en m’inspirant de la page http://code.google.com/p/android-lighthouse/wiki/Compile et de ma propre expérience sur Linux 32 bits. Si vous êtes sur Windows vous devriez jeter un oeil au problème suivant: Configure does not work with Cygwin on winxp et appliquer le patch pour cygwin qui est proposé dans l’une des réponses. Enfin si vous êtes sur Mac OS X vous devriez simplement oublier pour le moment (ou bien trouver une solution :p): broken build on mac osx – x86.

Linux semble être la meilleure plateforme pour développer avec Qt pour android actuellement, donc si vous n’utilisez pas cette plateforme, je vous conseille d’essayer avec une Machine Virtuelle, du moins c’est la solution dont je peux vous en assurer le fonctionnement. :)

Actuellement quelques éléments dits sur la page officielle traitant de la compilation de Qt et d’applications Qt pour android ne sont pas vraies, c’est pourquoi je vais vous guider dans la bonne direction pour faire fonctionner votre application Qt sur android, tel que Francisco Dalla Rosa Soares m’a montré cette semaine sur la mailing list d’android-lighthouse. Sans lui je n’aurai jamais pu lancer quoi que ce soit, si ce n’est mon pc portable…

Téléchargement

Avant tout il vous faut télécharger et décompresser QADK, qui est un Kit de Développement natif non officiel pour android, basé sur l’officiel mais avec quelques bibliothèques non supportées en plus:

Après cela il vous faudra cloner le repository git de android-lighthouse qui lui même consiste en un clone du projet Qt lighthouse qui est officiellement fourni par Nokia:

Configurer & Compiler

Vous devrez compiler Qt pour la plateforme visée, il est nécessaire de définir la variable ANDROID_PLATFORM et de faire pointer NDK_ROOT vers le dossier où vous avez décompressé QADK.

La dernière ligne est présente pour cibler les plateformes android 2.0 & 2.1, ce qui fonctionna sans problèmes pour ma part. Utilisez android-4 afin de cibler les plateformes 1.6 et android-8 pour cibler les plateformes 2.2.

Vous pouvez désormais lancer la partie de configuration (n’hésitez pas à aller voir votre petite amie pendant ce temps):

Et enfin vous pouvez compiler le tout:

Changez 3 par le nombre de coeur de votre processeur + un, cela activera la compilation parallèle avec autant de processus.

Il y a une dépendance de Qt qui n’est pas incluse au projet, c’est libcloog-ppl-dev, lancez simplement:

Pour ce que j’ai pu comprendre c’est une librarie utilisée pour l’optimisation de code, qui est destinée à générer du code permettant de passer sur chacun des points d’un Polyèdre. Je suppose que c’est utilisé dans qmake, mais je ne pourrai vous l’assurer. Plus de détails et un exemple sur le site officiel.

Installez Qt sur le Périphérique

Maintenant ce serait sympa d’avoir Qt sur le périphérique Android (ou dans l’émulateur), pour ce faire faites simplement ce que la page de wiki de google code conseille:

Connectez votre Périphérique

Si vous recevez l’erreur adb: command not found, c’est parce que vous êtes nouveau au développement Android (tout comme moi). Vous devez simplement télécharger le dernier sdk d’Android, vous pouvez trouver les instructions détaillées ici et le sdk ici.

Cependant à cette étape de l’article vous avez simplement besoin de télécharger le SDK, de définir le PATH et d’éxécuter:

Ensuite si vous voulez essayer sur votre véritable téléphone vous devrez activer la connexion avec ce dernier, pour y parvenir je vous invite à suivre la petite partie décrite sur le site d’android.

Je suis sur Linux, donc j’ai simplement mis en place la configuration suivante pour mon téléphone LGGT540 sur android 2.1. Sur mon pc avec Ubuntu 10.10 j’ai défini les informations suivantes dans le fichier /etc/udev/rules.d/51-android.rules:
Les fichiers présents dans /etc/udev/rules.d/ sont destinés à définir des règles persistantes pour les périphériques, dont l’une est de changer le CHMOD d’accès à un périphérique, en fonction d’éléments permettant de l’identifier.

Où 1004 vient d’une liste fournie de Vendor Ids pour les périphériques android: http://developer.android.com/guide/developing/device.html#VendorIds/. Prenez celui qui convient. :)

Sur Windows il vous faudra simplement installer les pilotes adb, et sur Mac OS X cela fonctionne sans rien faire, toutefois rappelez vous que android-lighthouse pour Mac OS X ne semble pas fonctionner.

Pour lister les périphériques Android existants vous pouvez lancer: adb devices.

Votre première Application Qt pour Android

Nous n’allons pas écrire notre propre code (oui je sais c’est triste), parce qu’il y a beaucoup de Hello World-like dans les demos du Qt Sdk. Nous allons donc choisir un très simple, afin d’expliquer les choses qui nous intéressent: la configuration de la compilation et comment créer un projet java afin de lancer l’application.

En effet contrairement aux dires du site officiel il n’est pas possible actuellement de compiler directement l’application en temps qu’exécutable natif. Il est nécessaire de la compiler en une bibliothèque dynamique, que l’on chargera à l’aide d’un petit launcher java basé sur les classes fournies par android-lighthouse. Ces dernières sont présentes dans le package com.nokia.qt.QtActivity.

Maintenant allez dans le répertoire /android-lighthouse/demos/mainwindow/, ici vous pouvez ouvrir le fichier mainwindow.pro, qui devrait contenir les configurations suivantes:

Il est réellement important de compiler l’application en tant que bibliothèque dynamique, ainsi pour vos prochaines applications n’oubliez pas d’utiliser les deux premières lignes données ci-dessus. Personnellement j’ai une préférence pour CMake, mais je n’ai pas encore pu préparer de configuration pour android pour le moment, et pourtant cela devrait seulement consister à éditer la méthode qt4_wrap_cpp pour lui donner la version android-lightouse spécialisée de qmake.

En effet pour compiler l’application, il faut utilisez android-lighthouse/bin/qmake afin de générer les fichiers de moc et le Makefile, et non pas la version de qmake que vous avez dans votre PATH.

Voilà, vous ne devez même pas adapter le code de votre application Qt. Le résultat des commandes que vous avez lancées devrait être un fichier so (shared object) avec différents liens symboliques afin de rendre possible la compatibilité entre versions apportée par libtool.

Envoyez simplement celle sans informations de compatibilité de versions sur votre périphérique android: adb push libmainwindow.so /data/local/qt/lib. Une fois que vous avez fait cela, l’application est sur le téléphone, mais rien n’existe pour la lancer.

Créez le Projet Android

Nous allons ainsi créer un launcher en java, basé sur le launcher fourni par le projet android-lighthouse, qui s’occupe tout seul des bindings JNI nécessaires. :D

Tout d’abord créez un projet dans un sous-dossier (javaLoader par exemple)

Créez une classe QtMain.java (vim seul ou avec eclim est un bon outil pour cela):

Et ensuite tapez simplement:

Votre application est installée, et peut facilement être lancée sur votre périphérique à l’aide de:

À propos du débogage

Pour le moment je n’ai hélas pas réussi à déboguer l’application sur le périphérique, mais les sorties consoles sont redirigées, il est donc tout de même possible d’utiliser qDebug pour faire le débogage. Ce n’est pas optimal mais ce n’est qu’en attendant de trouver un moyen simple. Je pense néanmoins que l’outil qadk-r4/ndk-gdb peut rendre le débogage possible, je n’ai pas réussi cependant à faire quoi que ce soit pour l’instant à ce sujet. Je posterai dès que j’y parviendrai. ;)

Qt Creator

Apparemment l’intégration d’Android pour Qt Creator est très avancée mais pas encore dans le dépôtd’après un mail de Tero Savolainen arrivé au moment de poster l’article, sur la liste de diffusion nommé “Re: Qt porting status and some great news” l’intégration de Qt Creator avec Androïd est faite et le débogage est la prochaine fonctionnalité à venir.

Conclusion

Comme vous avez pu le voir il devient très simple de développer nativement pour Android, le projet étant très actif, il y a fort à parier que pour fin décembre les limitations citées devraient avoir disparues et que le débogage soit possible.

Merci beaucoup pour votre lecture, je suis ouvert à toutes vos suggestions et remarques concernant cet l’article. ;)

WindowsPager qui s'intègre très bien dans Windows Seven.

WindowsPager ou comment rendre son Windows un peu plus agréable

S’il est bien une chose que l’on peut regretter lorsque l’on passe de Linux à Windows, c’est bien l’absence de bureaux virtuels. Aujourd’hui, et grâce à un ami (merci Fabien), cette absence est palliée !

Présentation

La solution miracle se nomme WindowsPager. Ce logiciel léger et configurable permet de simuler la présence de plusieurs bureaux virtuels et a le bon goût d’être gratuit et open-source (sous GPL).

Il se présente sous la forme d’un exécutable et d’un fichier de configuration au format INI et n’occupe de plus que très peu de mémoire.

J’avais déjà essayé pas mal d’émulateurs de bureau virtuel, mais je crois que j’ai finalement trouvé le bon.

WindowsPager est le seul que j’ai trouvé qui réponde à tous ces critères :

  • Intégration esthétique : un aperçu des bureaux est affiché en grand dans la barre des taches. Fini les petits icônes dans la zone de notification.
  • Légèreté : Une fois lancé, et avec 4 bureaux virtuels, celui n’occupe chez moi que 900 Ko de mémoire.
  • Réactivité : Même avec le CPU occupé à 100% (lors d’une grosse compilation par exemple), le changement de bureau se fait avec une vitesse époustouflante.
  • Disponibilité en x86 et x64 : Ok, ce n’est pas obligatoire, mais quand on voit que le développeur a fait l’effort de produire un code propre qui compile sans problème pour les deux architectures, ça inspire davantage la confiance.

WindowsPager qui s'intègre très bien dans Windows Seven.

Pour ceux à qui il prendrait l’envie de l’essayer, ça se télécharge ici.

Je ne l’utilise que depuis une journée, mais je sens déjà que ça va me changer la vie !

Console

Développer pour Android sans utiliser Eclipse

Il y a quelques jours, j’ai découvert le développement Android et Eclipse par la même occasion. Ayant abandonné il y a longtemps les IDE, j’ai tout de même décidé de sauter le pas histoire de ne pas mourir idiot.

Il faut le reconnaître, l’intégration Android dans Eclipse est très bien pensée et plutôt efficace : auto-complètement, assistants à tout va, débogueur, etc. Seulement voilà, il faut se rendre à l’évidence : quand on est habitué à Vim, l’éditeur de texte d’Eclipse fait plutôt pâle figure. Et en y réfléchissant bien, l’essentiel du développement Android reste l’écriture de code toute bête ou la modification de fichiers XML : pourquoi ne pourrait-on pas simplement utiliser une console et l’éditeur de texte de notre choix ?

Voici donc ce que propose ce tutorial : l’installation d’un environnement de développement simplifié pour Android.

Prérequis

Avant de poursuivre ce tutorial, vérifiez que vous :

  • Êtes habitué au développement “console”. Si vous n’avez jamais utilisé que des IDE, je ne peux que trop vous conseiller de rester dans cet environnement. Le développement Android en console n’est pas recommandé par Google et de plus beaucoup moins facile d’accès que pour d’autres langages (C, C++).
  • Savez ajouter/modifier/supprimer des variables d’environnement.
  • Avez téléchargé et installé le Android SDK. Si vous ne connaissez pas la marche à suivre, elle est indiquée dans cet article.
  • Êtes prêt à passer pour un fanatique auprès de vos amis qui utilisent un IDE.

Si vous remplissez toutes ces conditions, c’est parti !

Développons en Java

On a beau se passer d’Eclipse, on ne peut évidement se passer d’utiliser Java.

Commencez par télécharger le kit de développement Java (JDK) pour votre système d’exploitation, puis installez-le.

Pour ma part, j’ai choisi le chemin d’installation par défaut, c’est à dire “C:\Program Files\Java” sur mon Windows Seven 64 bits.

On se retrouve avec les deux répertoires suivants :

Répertoires Java

La dernière étape concernant Java, consiste à ajouter le sous-répertoire “C:\Program Files\Java\jdk1.6.0_22\bin” au PATH de l’environnement.

Ouvrez une fenêtre console et saisissez la commande suivante :

Si vous obtenez la sortie suivante :

C’est que tout est bien configuré :)

Un peu de ménage

Avant d’installer le JDK, je me suis rendu compte que j’avais déjà une version du runtime Java installée.

Si c’est également votre cas, rien ne vous empêche de la garder, mais pour éviter les conflits potentiel, et ne pas gaspiller inutilement de l’espace disque, j’ai choisi de procéder manuellement à sa désinstallation avant d’installer le JDK.

J’ai également à ce moment là, fait le ménage dans les variables d’environnement qui faisaient référence à Java.

Ant, un “Makefile-like” pour Java

Le Android SDK utilise Ant pour automatiser la compilation des projets. Pour ceux qui connaissent, c’est une alternative orientée Java à Makefile, CMake, SConstruct ou encore BJAM.

Pour les plus curieux, vous pouvez faire un tour sur la page officielle de Ant.

Sinon, passons directement au téléchargement : Télécharger Ant.

Décompressez l’archive où bon vous semble (j’ai choisi encore une fois de tout mettre dans C:\) et ajoutez les variables d’environnement suivantes :

  • ANT_HOME : Le chemin vers l’archive décompressée. Chez moi : “C:\apache-ant-1.8.1″
  • JAVA_HOME : Le chemin vers l’installation du JDK. Chez moi : “C:\Program Files\Java\jdk1.6.0_22″
  • PATH : Ajoutez le chemin vers les binaires de Ant. Chez moi : “C:\apache-ant-1.8.1\bin”

Une fois que tout est configuré, ouvrez une nouvelle console et tapez :

Si vous obtenez la sortie suivante :

C’est que Ant est correctement installé.

Si ça ne fonctionne pas, vérifiez bien que l’environnement de votre console est bien à jour. Sous Windows, il faut fermer toutes les fenêtres consoles et les ré-ouvrir pour appliquer les modifications faites à l’environnement.

C’est tout ?

Oui. Il n’en faut pas plus pour avoir un environnement de compilation simple pour Android.

Nous pouvons d’ores et déjà voir comment créer un nouveau projet, le compiler et le déployer sur un émulateur.

Création d’un projet

Pour créer un nouveau projet, nous allons utiliser la commande “android”.

Voici la syntaxe pour créer un nouveau projet :

La signification des différents paramètres est la suivante :

  • version_cible : l’identifiant de version Android cible à utiliser. Pour avoir la liste des identifiants disponibles sur votre poste, utilisez la commande “android list targets”.
  • nom : Le nom de votre projet. Ce paramètre est optionnel, mais s’il est spécifié, ce nom sera celui du paquet “.apk” généré ultérieurement.
  • chemin : Le répertoire cible où sera créé votre nouveau projet.
  • activité : Le nom complet de l’activité. Exemple : “MyAndroid”.
  • espace_de_nom : L’espace de nom (ou “namespace”) utilisé par votre projet. Exemple : “org.freelan.myandroid”.

Google donne la commande exemple suivante :

Qui crée dans le répertoire courant un sous-répertoire “MyAndroidAppProject” contenant le nouveau projet.

Arborescence d'un nouveau projet Android

Nous ne rentrerons pas ici dans les détails de cette arborescence, mais voici tout de même dans les grandes lignes les choses intéressantes :

  • Les fichiers source Java sont situés dans le répertoire “src”.
  • Tout ce qui concerne les chaînes de caractères, fichiers XML représentant l’interface graphique (ou “Layouts”) ou images sont dans le répertoire “res”.
  • Ne touchez jamais aux fichiers “*.properties” ! Ils sont utilisés par Ant pour la phase de “build” et n’ont pas vocation à être modifiés manuellement.

Compilation du projet

Le projet, tel que créé par défaut est simpliste mais fonctionnel. Le rôle de ce tutoriel n’étant pas d’apprendre à concevoir une application Android mais de simplement maitriser les outils du SDK, nous ne ferons aucune modification de ce projet.

Pour être diffusée, une application Android doit être signée. Ceci implique plusieurs démarches dont nous traiterons dans un autre tutoriel. Pour l’heure, nous choisissons de compiler notre projet en “debug”, ce qui nous permet de nous affranchir de cette étape.

Dans la même console, toujours à la racine du projet, tapez simplement la commande :

Qui a pour effet de générer dans le répertoire “bin” différentes choses, dont le fichier “MyAndroidApp-debug.apk”.

Ce n’est pas plus compliqué que ça.

Création d’un périphérique virtuel

Pour tester notre application, il nous faut soit un téléphone sous Android relié en USB et configuré en mode développeur, soit un téléphone virtuel lancé dans un émulateur.

Si vous n’avez pas encore créé de téléphone virtuel, voici la marche à suivre :

Dans votre console, tapez la commande :

Ce qui a pour effet d’ouvrir la fenêtre suivante :

Gestion des téléphone virtuels

Cliquez sur “New…”, puis spécifiez les caractéristiques de votre téléphone virtuel :

Caractéristiques du téléphone virtuel

Puis validez en cliquant sur “Create AVD”.

Si tous les paramètres sont corrects, votre téléphone virtuel est créé. Vous pouvez d’ores et déjà le démarrer en le sélectionnant dans la liste et en cliquant sur le bouton “Start…”.

Ce premier démarrage peut être assez long, aussi, soyez patient.

Installer son application sur le téléphone

Une fois le paquet “apk” créé, l’installation sur un téléphone (qu’il soit virtuel ou non) se fait très simplement :

La commande prends quelques secondes et vous indique le succès ou l’échec de l’opération.

Si vous disposez de plusieurs émulateurs, ou d’un émulateur et d’un téléphone physique, adb ne peut pas deviner où installer votre paquet.

Utilisez alors la syntaxe suivante pour spécifier le périphérique à utiliser :

Ou positionnez la variable d’environnement ANDROID_SERIAL avant vos appels à adb.

Pour obtenir la liste des numéros de série des périphériques, vous pouvez utiliser la commande suivante :

La commande “adb install” possède tout un tas d’option qu’il ne serait pas raisonnable de détailler ici. Vous devriez cependant y jeter un coup d’oeil. Pour les lister, tapez simplement :

Qui produit la sortie suivante :

Démarrer une activité

Une fois installée, vous pouvez démarrer l’activité sur votre téléphone comme vous le feriez pour n’importe quelle autre application. Mais si vous le souhaitez, vous pouvez également le faire en ligne de commande (voire automatiquement, si vous mettez toutes les commandes dans un script).

La commande ci-après démarre votre activité sur le téléphone spécifié (ou sur le seul téléphone connecté) :

Vous pouvez d’ailleurs démarrer n’importe-quelle activité en utilisant cette méthode.

Une seule commande pour tout

Astuce qu’il est agréable de connaître : Il est possible de réunir les dernières étapes en une seule commande en utilisant la commande suivante :

Qui va se charger de faire un “ant debug”, “adb install…” pour vous. Plutôt sympa non ?

Conclusion

Le développement Android en mode console s’avère moins pénible à mettre en place que je ne l’aurais pensé. Google a fait un travail impressionnant en fournissant aux développeurs des outils simples et facile à intégrer à n’importe quel environnement.

Certains argueront que l’apprentissage du développement Android est bien plus facile sous Eclipse, et je pense que dans un sens ce n’est pas faux : il est clair qu’avoir le complètement automatique et des assistants permet d’apprendre peu à peu et facilement les différentes structures de données à utiliser. Cependant, la découverte de cet environnement console permet assurément de comprendre tout ce qu’Eclipse fait pour nous de façon automatique.

L’utilisation directe de “adb” peut notamment fournir au développeur des outils avancés indispensables et une aide précieuse au développement.

L'émulateur de périphérique Android

Installer l’environnement de développement pour Android

Il existe déjà sur la toile un bon nombre d’articles traitant du développement sur Android. La plupart sont d’ailleurs très bien écrits et assez faciles à suivre mais supposent souvent que le lecteur connaisse Java ou en tout cas soit familier avec son environnement de développement. Si comme moi, ce n’est pas votre cas mais que vous souhaitez tout de même développer pour Android :  ce retour d’expérience cet article est fait pour vous.

Commençons par le début, voulez-vous ?

Nous allons supposer que vous disposez d’un ordinateur, d’une connexion à l’Internet et éventuellement d’un téléphone sous Android. Ce dernier point n’est évidemment pas obligatoire mais il faut reconnaître que c’est quand même moins marrant de tester son application dans un émulateur que sur un vrai téléphone.

Les instructions que je vais décrire sont pour Windows, mais il ne sera certainement pas très difficile de les transcrire pour Linux ou Mac OSX.

Installer le support de Java

Le langage de choix pour le développement Android est le Java. Il s’agit d’un langage complètement portable : le code est le même indépendamment du système d’exploitation ou de son architecture (x86, x64, etc.). Pour s’exécuter sur les différents systèmes, Java requiert l’installation d’une JVM, (“Java Virtual Machine” ou encore “Machine Virtuelle Java”) qui “traduit” le code Java en instructions compréhensibles par le système hôte.

Installons donc cette JVM : Télécharger la JVM

Le “Android SDK”

Il faut ensuite télécharger le kit de développement Android fourni par Google. Encore une fois, rien de plus simple : Télécharger le Android SDK

Une fois l’archive récupérée, décompressez-la où bon vous semble. Pour ma part, j’aime avoir mes différents environnements de développement sous Windows à la racine du C:\, mais vous pouvez très bien décider de la mettre ailleurs*.

* Évitez tant que possible d’utiliser un chemin contenant des espaces, ce ne serait pas la première fois que ça cause des problèmes !

Il faut ensuite ajouter au PATH le répertoire de l’archive contenant les outils du SDK. Sur mon poste, j’ai donc ajouté “C:\android-sdk-windows\tools” à mon PATH :

Ajouter les outils du Android SDK à son PATH

Eclipse, l’outil de prédilection

Pour développer, il faut ensuite au moins un éditeur de texte et au mieux un IDE. Bien que ne connaissant que très peu Java, j’avais cependant déjà entendu parler d’Eclipse. Google ayant en plus eu le bon goût de développer un plugin Eclipse pour le développement Android : il semble s’agir d’un bon choix.

Mon instinct de développeur à la page m’inciterait à télécharger la dernière version d’Eclipse (la 3.6 au moment où ces lignes sont rédigées), mais Google indique sur la page de présentation de son plugin que celui-ci ne fonctionne qu’avec la version 3.5.

Téléchargeons donc la version 3.5 : Page de téléchargement d’Eclipse

Rendez-vous dans l’onglet “Older versions” puis choisissez “Eclipse Galileo SR2 Packages (v 3.5.2)” puis enfin prenez “Eclipse IDE for Java Developers“.

Décompressez l’archive, et placez le dossier “eclipse” où bon vous semble. Encore une fois, j’ai choisi de le mettre à la racine du C:\ par souci de cohérence.

Rendez-vous dans le répertoire fraîchement décompressé puis lancez “eclipse.exe”. Ceci peut prendre un peu de temps, puis le programme vous demande où vous souhaitez enregistrer vos futurs projets.

Le plugin ADT

Il ne manque plus que l’installation du plugin officiel Google pour Android (ADT).

Rendez-vous sur cette page. Et suivez les instructions concernant votre version d’Eclipse.

Pour ceux qui auraient un problème avec la langue de Shakespeare, voici les premières instructions traduites :

  1. Démarrez Eclipse, et rendez-vous dans le menu “Help” puis “Install New Software”.
  2. Cliquez sur le bouton “Add…”
  3. Dans le premier champ, entrez “Android Developer Tools” puis dans le second champ, saisissez “https://dl-ssl.google.com/android/eclipse/”. Validez par un clic sur le bouton “OK”.
  4. Vous devriez désormais voir une entrée “Developer Tools” dans la liste plus bas. Sélectionnez la case à cocher, ce qui a pour effet de sélectionner automatiquement les deux sous-cases.
  5. Faites “Next” autant de fois que nécessaire, acceptez la license d’utilisation (si vous la comprenez), puis cliquez sur “Finish”. Eclipse télécharge ensuite les composants.
  6. Redémarrez Eclipse pour terminer l’installation du plugin.

Installer de nouveaux composants pour Eclipse

Ajouter la source ADT

Acceptation de la licence

Avant d’être utilisé, le plugin ADT doit être configuré. Rendez-vous dans “Windows”, puis “Preferences” et sélectionnez “Android” dans la liste à gauche.

Spécifiez le chemin vers le SDK installé en cliquant sur le bouton “Browse…” et en cherchant l’endroit où vous avez décompressé le Android SDK. Chez moi, il s’agit de “C:\android-sdk-windows”.

Validez par “OK” pour terminer la configuration.

Configuration du Android SDK

La dernière étape avant de pouvoir développer pour Android consiste à configurer le Android SDK.

Rendez-vous dans le répertoire où vous avez décompressé le Android SDK, puis exécutez le programme : “SDK Manager.exe”.

Configuration du Android SDK

Choisissez les paquets à installer en les acceptant ou en les refusant.

Pour ma part, j’ai conservé le choix par défaut, puis j’ai cliqué sur “Install”. S’en suit une série de téléchargements, plus ou moins rapides.

Créer un périphérique virtuel

Cette étape n’est pas obligatoire pour ceux qui disposent d’un téléphone sous Android, mais il peut être pratique d’avoir un téléphone virtuel prêt à l’emploi pour faire des tests rapides (ou lorsqu’on est dans le train et qu’avoir 15 000 trucs sur les genoux n’est pas une option !).

Toujours dans le “Android SDK Manager”, rendez-vous dans la catégorie : “Virtual Devices” puis faites “New…”.

Choisissez un nom significatif pour votre périphérique virtuel. Dans mon cas, j’ai décidé de reproduire les caractéristiques physiques de mon téléphone : je l’ai donc nommé “HTC_Desire”.

Choisissez une version de l’OS à utiliser (dans mon cas toujours, “Android 2.2 – API Level 8″) et une taille pour la carte SD. Ici, ça dépend vraiment de votre espace disque : j’ai choisi “4096 Mo” comme ma vraie carte SD, mais si vous êtes limité en place, quelque-chose comme “128 Mo” peut être suffisant.

Pour le reste, j’ai laissé les réglages par défaut qui semblaient convenir.

Cliquez sur “Create AVD” pour finaliser la création.

Vous pouvez, si vous le souhaitez, vous amuser à démarrer le téléphone virtuel en cliquant sur le bouton “Start” à droite. Le téléphone peut mettre un peu de temps à démarrer (surtout la première fois) aussi, soyez patient.

L'émulateur de périphérique Android

Félicitations !

Ça y est ! Vous avez terminé la configuration de l’environnement de développement et vous êtes prêt à développer pour votre nouvelle plateforme préférée !

Rendez-vous dans Eclipse, faites “New”, “Project” puis choisissez “Android Project” et laissez-vous guider !