Syndication : Atom 1.0  RSS 2.0
Blogs des développeurs   »   Blog du projet ZiK

Article complet: Adapter une bibliothèque C pour ruby (1)

01/10/2010

Permalink 16:17:24, Catégories: Récapitulatif, Ruby, debian-fr, 1016 mots   French (FR) , vinc-mai

Adapter une bibliothèque C pour ruby (1)

Introduction

J'utilise régulièrement ruby-taglib. Malheureusement, certains bugs empêchent son utilisation avec ruby 1.9. Après avoir tenté, avec plus ou moins de succès, de corriger ces bugs, j'ai décidé de réécrire cette bibliothèque. La version originale est basée sur ruby/DL, bibliothèque que je n'ai jamais utilisée. Je profite de cette réécriture pour proposer une série d'articles sur la manière d'adapter une bibliothèque C.

[Suite:]

Préparation

Je développe pour l'instant sous ubuntu 10.04 (je terminerai sûrement ces articles sous la version 10.10). J'ai installé taglib, ruby et rdoc soit les paquets debian suivant : libtagc0, libtagc0-dev, ruby, ruby-dev, rdoc.

Hiérarchie

La commande tree présente l'arborescence de mon répertoire de travail.

$ tree 

├── extconf.rb 
├── lib 
│   └── taglib2.rb 
└── taglib2.c 

Le fichier extconf.rb, écrit en ruby, permettra de préparer les sources en vue de compiler la bibliothèque. Le fichier lib/taglib2.rb, lui aussi écrit en ruby, est le fichier lu par l'interpréteur ruby lors de l'appel à require "taglib2" qui chargera notre future bibliothèque.Le fichier taglib2.c, écrit en C, contiendra les méthodes qui permettent d'interfacer taglib.

Ruby

Dans un premier temps, j'utiliserai seulement le langage ruby. J'écris donc les premières lignes de code dans le fichier lib/taglib2.rb.

$ cat lib/taglib2.rb  
module TagLib 
  VERSION=[0, 0, 1] 
end 

Une constante nommée VERSION est définie comme un tableau contenant 3 entiers. D’ores et déjà, je peux tester mon code grâce à irb, un interpréteur ruby en ligne de commande. La bibliothèque n'étant pas encore installée, j'utilise un chemin relatif pour y accéder.

$ irb 
> require "./lib/taglib2" 
=> true 
> TagLib::VERSION 
=> [0, 0, 1] 

Interface ruby/C

Exceptions

Nous nous intéressons enfin au fichier taglib2.c. Nous définissons, tout d'abord, les différents types d'exceptions qui peuvent être levés par la bibliothèque.

$ cat taglib2.c 
#include <ruby.h> 
#include <taglib/tag_c.h> 
 
VALUE mTagLib; 
VALUE eBadPath, eBadFile, eBadTag, eBadAudioProperties; 
 
void 
Init_taglib2() 

  mTagLib=rb_define_module("TagLib"); 
  eBadPath=rb_define_class_under(mTagLib, "BadPath", rb_eException); 
  eBadFile=rb_define_class_under(mTagLib, "BadFile", rb_eException); 
  eBadTag=rb_define_class_under(mTagLib, "BadTag", rb_eException); 
  eBadAudioProperties=rb_define_class_under(mTagLib, "BadAudioProperties", rb_eException); 

Les fichiers nécessaires au développement de la bibliothèque sont tout d'abord inclus puis nous déclarons des variables de type VALUE. Ce type est utilisé pour toute variable représentant un objet du langage ruby. Les noms de variables représentant des exceptions sont généralement préfixés par la lettre e. Pour les modules, la lettre m est utilisée, pour les classes, la lettre c.
Il s'agit d'une convention et non d'une règle. Finalement, on retrouve la fonction Init_taglib2 qui (re)définit le module TagLib ainsi que 4 classes descendant de la classe ruby Exception représentée en C par la variable rb_eException.

Le code suivant, écrit en ruby, est équivalent à la définition donnée en C de l'exception TagLib::BadPath

 
module TagLib 
class BadPath < Exception 
end 
end 

Compilation

Afin de compiler notre bibliothèque, nous devons créer un fichier Makefile. La bibliothèque mkmf nous facilite le travail.

$ cat -n extconf.rb 
1  require 'mkmf' 
2  
3  have_header('ruby.h') || exit 1 
4  have_header('taglib/tag_c.h') || exit(1) 
5  
6  create_makefile("taglib2") 
$ ruby extconf.rb  
checking for ruby.h... yes 
checking for taglib/tag_c.h... yes 
creating Makefile 

Dans le fichier extconf.rb, la présence des fichiers « header » de ruby et de taglib sont vérifiées ligne 3 et 4. La ligne 6 permet de créer le fichier Makefile du projet taglib2. Lors du chargement d'une interface ruby/C, la fontion appelée est de la forme Init_NomDuProjet,c'est pourquoi l'unique fonction du fichier taglib2.c s'appelle Init_taglib2. Il s'agit de l'équivalent de la fonction main d'un programme C traditionnel.

Après avoir créer le fichier Makefile, compilons.

$ ruby extconf.rb 
$ make 

Un bibliothèque dynamique taglib2.so vient de faire son apparition. Ruby permet de charger directement ce type de bibliothèque. Nous ajoutons donc l'instruction (require "taglib2.so") de chargement dans le fichier lib/taglib2.rb.

$ cat lib/taglib2.rb  
require "taglib2.so" 
 
module TagLib 
VERSION=[0, 0, 1] 
end 

Test

Nous testons notre code sous irb.

$ irb 
> $:.unshift('.') 
> $:.unshift('lib') 
> require "taglib2" 
=> true 
> TagLib.constants 
=> ["BadFile", "BadPath", "BadAudioProperties", "VERSION", "BadTag"] 
> TagLib::BadPath.new 
=> #<TagLib::BadPath: TagLib::BadPath> 

J'ajoute tout d'abord le répertoire courant et le répertoire lib dans les chemins vérifiés lors du chargement d'un fichier afin que les appels à require "taglib2" et à require "taglib2.so" n'échouent pas. Cette astuce ne sera plus nécessaire une fois la bibliothèque installée. On vérifie que les constantes définies dans les fichiers sources lib/taglib2.rb et taglib2.c sont accessibles.

Conclusion

Lors de ce premier billet, j'ai mis en place les différents éléments (bibliothèques, fichiers) qui seront nécessaires à l'interface ruby de taglib. Nous avons, déjà, réussi à obtenir un code fonctionnel. Il nous reste à porter les fonctions proposées par taglib afin de pourvoir accéder, en ruby, aux tags de fichiers musicaux.
À la prochaine.

Je ne suis pas un spécialiste du langage C, si vous avez des suggestions à faire sur mon code
commentez ce billet.

Addendum

Je rajoute la liste des billets faisant suite à celui-ci :

Social Bookmarking:

                                     

Commentaires:

Connectez-vous pour vous abonner à cet article:

Flux de commentaires pour cet article : Atom 1.0  RSS 2.0
Commentaire de: vinc-mai [Membre]
Correction d'un oubli.
Permalien 05/03/2011 @ 18:07
Commentaire de: epo2011 [Membre]
Super mais cela serait interessant d'avoir aussi la même bib pour une version windows Ruby ....
Permalien 20/07/2011 @ 12:15
Commentaire de: vinc-mai [Membre]
Je ne me suis pas encore penché sur le cas window...
Permalien 20/07/2011 @ 16:04

Vous devez être identifié pour poster un commentaire.

Liste des blogs

Blog du projet ZiK

Catégories


Rechercher

<  Décembre 2011  >
Lun Mar Mer Jeu Ven Sam Dim
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  

Syndiquez ce blog XML

Articles :

Commentaires :

 
 
 
 
Partenaires

Hébergement Web