d`ici 2006

publicité
Introduction
Expert-solutions est éditeur de sa propre version de CLAIRE nommée « XL CLAIRE »
et créée il y a 4 ans. Au cours des différents projets menés par XL, CLAIRE a pris une place
de plus en plus dominante dans les développements et devient aujourd’hui le seul langage
utilisé pour la réalisation des (nouveaux) projets : XL fait du « tout CLAIRE ». Pour assurer
cette position industriellement, XL à développé des compétences sur les couches basses du
langage CLAIRE afin de pouvoir comprendre, maîtriser et corriger « rapidement » tout type
de dysfonctionnement. Aujourd'hui, XL peut intervenir à la fois sur le noyau/GC de
CLAIRE, sur les « meta » et autres modules et dans une moindre mesure sur le compilateur
CLAIRE.
XL à mis en place son propre environnement de production de code. A l'origine intégré
dans l'IDE Eclaireur pour win32, la gestion des projets multi-modules et le partage des
modules a été re-développé en CLAIRE et accessible à la ligne de commande. Cette étape a
été nécessaire car la plateforme de développement et déploiement préférée est aujourd'hui
UNIX.
XL réalise des projets type « application internet » et a développé toute une
infrastructure dédiée à ce type d'application. Cela comprend la génération dynamique de
pages HTML multilingues, la production de documents PDF signés numériquement et
l'envoie de message électroniques. De telles applications prennent la forme d'agent CLAIRE
placé derrière un serveur web.
Enfin XL est très sensible aux problèmes de performances, sur les algorithmes de
recherche de solution d'une part, et sur les problèmes de montée en charge des serveurs
derrière lesquels peuvent se trouver de multiples agents d'autre part.
Vers le noyau XL
Dans ce document on fait référence au noyau développé par Yves Caseau par <ycs>. Le
noyau XL est une évolution du noyau <ycs>, certaines fonctionnalités ont étés ajoutées
d'autre modifiées mais sans jamais changer la sémantique du langage.
* Traces du noyau
Tous les traces du noyau XL (par exemple le trace GC) sont systématiquement
redirigés vers ctrace() plutôt que sur stdout. On le vera plus loin il est nécessaire dans un
environnement CGI que la sortie (redirigée) du processus ne soit pas polluée. Pour cela le
noyau XL dispose de sa propre méthode de trace analogue à printf.
* La classe module
Un slot verbose a été ajouté à la classe module dans le noyau XL. Ainsi chaque module
peut avoir sa propre politique de trace. C'est particulièrement pratique pour filtrer les traces
d'applications ayant 10 voir 20 modules. Par défault le champ verbose d'un module est à false
ce qui correspond au comportement du noyau <ycs>. Ce champ peut prendre les valeur
suivantes :
•
•
•
•
false (défault) : identique à <ycs>
true : tout les traces du module sont issus
<int> : comme si la verbose système valait <int> pour ce module
Interval : les traces sont issus seulement si leur niveau appartient à
l'intervale
La façon dont est traitée l'instruction de trace a donc été modifiée. De plus, le message
de trace est automatiquement préfixé par :
[<module>:<niveau>] le message du trace
Si, de plus, le processus qui génère le trace est un processus « forké » alors le prefixe
devient :
[<pid>][<module>:<niveau>] le message du trace
Dans le noyau XL, les modules ont également un slot version qui permet de partager (le
partage de module est décrit en deuxième partie) plusieurs version d'un même module. La
version d'un module est une chaîne de caractère.
Enfin le slot made_of d'un module peut contenir dans XL CLAIRE des fichiers .cpp ou
.h. Les .cpp seront ajouter au makefile lors de la compilation et les .h seront inclus dans le .h
du module généré (via compiler.headers).
* Séquences d'échappement
Le Reader XL CLAIRE supporte des séquences d'échappement pour exprimer des
nombres des chaînes ou des caractères dans les base binaires octale et hexadécimales. Une
séquence est introduite par le caractère anti-slash « \ », suivi d'un indicateur de base :
Pasted Graphic 9.tiff ¨
* Représentation des chaînes de caractère
Les chaînes <ycs> sont à l'image des string en C/C++. Pour en connaître la longueur on
utilise strlen, ces chaînes ne peuvent contenir de caractère nul. C'est une limitation quand on
manipule des données binaires (arbitraire). Dans le noyau XL, on adopte le style pascal pour
la représentation des chaînes CLAIRE. Dans cette représentation, la longueur d'une chaîne est
stockée en entête de la zone mémoire qui contient la chaîne, par exemple la chaîne "toto" est
représenté ainsi :
Pasted Graphic 10.tiff ¨
La longueur d'une chaîne se calcule quasi-instantanément avec ce type de
représentation alors que strlen doit parcourir la chaîne entièrement pour en donner la
longueur. Les chaînes C/C++ restent cependant supportées pour toutes les chaînes qui
résident en dehors de Cmemory (cas des chaînes statiques ou importées). Les API de
manipulation de chaîne ont donc été modifiées pour utiliser la nouvelle API length_string :
int length_string(char *s) {
return CLMEM(s) ?
*((int*)s - 1) :
strlen(s);
}
Note : on réserve systématiquement un caractère nul en fin de chaîne, ainsi les chaînes
CLAIRE sont entièrement compatibles avec les chaînes C/C++ et peuvent êtres passées en
argument à des appels fonctionnels de bibliothèques externes sans causer de dommage.
* Destructeurs: freeable_object
Le besoin d'un destructeur a été évoqué sur le forum claire-language et implementé
dans le noyau XL pour un nouveau type d'objet:
freeable_object <: ephemeral_object(
freeme?:boolean = false)
Un objet de type freeable_object est éphémère, lorsque le GC détruit une instance de ce
type il appelle free! donnant l'opportunité de faire un nettoyage, par exemple :
long_double* <: import()
long_double <: freeable_object(value:long_double*)
close(self:long_double) : long_double ->
(sel.value := externC(
"(long double*)::malloc(sizeof(long double))",
long_double*),
self)
free!(self:long_double) : void ->
externC("::free(self->value)")
Une liste d'instances de freeable_object est maintenue par le noyau. Lors d'un GC, le
conteneur de cette liste est d'abord marqué, puis, à la suite de l'opération de marquage les
instances de cette liste qui n'ont pas étés marqués sont marqué « à la main » et leur slot
freeme? est mis à true de sorte qu'a la fin du GC (lorsque la mémoire est dans un état sain) on
peut reparcourir cette liste et appeler free! pour les objets qui ont freeme? à true.
L'appel à free! peut générer un GC (récursif), auquel cas le traitement ci-dessus n'est
pas effectué, l'ensemble des freeable_object sont marqués et leur slot freeme? reste inchangé.
Note : Lorsque CLAIRE se termine free! est appelé pour tous les freeable_object
encore en mémoire afin de terminer proprement l'exécution.
* freeContent
Dans le noyau XL lorsqu'un bag est ré-alloué (par exemple à la suite d'une insertion)
l'ancien contenu est désalloué immédiatement. Une méthode freeContent à été ajoutée au GC
à cet effet.
* GC & congestion mémoire
Egalement évoqué sur le forum claire-language, le noyau XL apporte une solution au
problème de congestion mémoire. L'idée principale est de profiter de la gestion efficace de la
mémoire virtuelle (VM) sous une architecture UNIX. Les schémas ci-dessous illustrent la
congestion :
Pasted Graphic 11.tiff ¨
Lorsque l'option « -auto » est utilisée et qu'une congestion mémoire intervient, la
mémoire est automatiquement augmentée. Avec cette option, le plus grand block possible est
alloué lors de l'initialisation de Cmemory (comme si « -s 9 j » était donné). Cependant
CLAIRE est contraint dans un espace plus petit conformément à l'option « -s i j ». En cas de
congestion de la mémoire (chunk ou object) on opère à un simple décalage de la borne de la
mémoire concerné ce qui est instantané et ne provoque aucune ré-allocation dynamique.
On prend en compte deux type de congestion :
• spatiale : il n'y a de toute façon pas assez de place pour alloué un objet
donc on augmente la mémoire
• temporelle : on passe plus de temps à faire des GC que du calcul donc
on donne plus d'espace au programme afin d'éviter de passer trop de temps dans le
GC.
Note 1: Sous win32, ceci est totalement inefficace car la gestion de la mémoire
virtuelle est en fait physique! En revanche sous UNIX ceci est particulièrement efficace:
temps que la mémoire n'est accédée qu'en lecture aucune page mémoire n'est effectivement
allouée.
Note 2: En « -auto » les différentes piles allouées par le noyau (GC, exécution et
monde) supportent la congestion. Les piles sont automatiquement ré-allouées pour prévenir
un dépassement. Seule la table des symboles ne supporte pas la congestion.
Note 3: Aucun mécanisme de décongestion n'est supporté: la mémoire utilisée ne peut
qu'augmenter.
* API supplémentaire de la librairie C
Un certain nombre d'API de la lib C ont étés ajoutées au noyau XL. Ces API
concernent les domaines suivants:
•
•
•
•
•
•
•
accès au système de fichier
manipulation de l'environnement du processus
manipulation de chaîne de caractère
manipulation de date/time
création et attente de processus
fork
port réseau (socket)
Ces API ont historiquement étés ajoutées directement au noyau du fait de leur
implémentation en C++. Cela augmente la taille du noyau et il est aujourd'hui question d'en
créer un module dédié (voir roadmap).
Note : Fork est le moyen naturel sous unix pour créer un nouveau processus (attention:
pas de fork sous win32). C'est un mécanisme très intéressant pour CLAIRE au regard du
metaLoad. En effet on peut avoir un processus père qui va effectuer le metaLoad puis
attendre un événement, les traitements effectués en réponse à cet événement peuvent ensuite
être réalisés dans un processus « forké » (pour lequel le metaLoad à déjà été effectué)...
* Signaux
Le noyau XL supporte les signaux et on peut écrire ses propres services d'interruption
en CLAIRE. Par définition les signaux sont des événements asynchrones et il est dangereux
pour l'intégrité de la mémoire de CLAIRE de les traiter de cette manière sans aller droit au
crash (cas d'une interruption pendant un newChunk!). Le choix qui a été fait est de dissocier
l'interception du signal de sont traitement. Pour cela le noyau maintient une cache de signaux
qui seront redistribués depuis un point d'exécution approprié au routines d'interruption. Ces
points appropriés sont les GC_UNBIND et GC_UNLOOP après lequel sont ajoutés, par le
compilateur CLAIRE, un appel à la (nouvelle) macro POP_SIGNAL :
#define POP_SIGNAL {if (n_pending_signal > 0) \
kernel_pop_signal();}
Une fois encore, seule la plateforme UNIX supporte les signaux, un signal sous win32
termine l'exécution du processus.
* Référencement des OID à l'adresse nulle
Dans le noyau XL les OID ne sont pas référencés par rapport à l'adresse de Cmemory
mais par rapport à l'adresse nulle ce qui est bien plus performant car on économise
l'indirection dynamique de Cmemory nécessaire à une conversion OID/adresse.
Macro de conversion <ycs> :
#define OBJECT(A,B) \
((class A*)&Cmemory[(B & ADR_MASK) + 1])
#define _oid_(A) \
(OBJ_CODE + (((int)A - (int)&Cmemory[0]) >> 2) - 1)
Macro de conversion XL :
#define OBJECT(A,B) ((class A *)((unsigned)B << 2))
#define _oid_(A) (OBJ_CODE | ((unsigned)A >> 2))
Ce n'est qu'un jeu d'écriture mais les gains de performances observé sont de l'ordre de
10 à 20%. Ces gains sont plus important encore dans le cas ou plusieurs processus sont
simultanément en cour d'exécution.
* Ligne de commande
Le processus d'initialisation de XL CLAIRE est le suivant :
•
•
•
•
allocation de Cmemory
metaLoad
call_main
lecture des options de la ligne de commande
Call_main est rendu obsolète par la gestion des options de la ligne de commande
introduite dans XL CLAIRE mais reste présente pour la compatibilité avec <ycs>. XL
CLAIRE dispose d'un moteur de parsing des options de la ligne de commande, chaque
module peut définir des handlers répondant à une option donnée. Dans la distribution XL
CLAIRE le fichier ccmain.cl à été éclaté afin que chaque option supportée soit prise en
charge par le module approprié. Par exemple l'option -cm est prise en charge par le module
Generate et l'option -f est prise en charge par le module Reader :
[option_parsed() : void ->
// appelé une seule fois pour chaque module qui définit
// cette restriction et une fois que toutes les options
// ont été parsées
none]
[option_usage(opt:{"-f", "-ef"}) :
tuple(string, string, string) ->
tuple("Load file",
"{-f | -ef} <file:path>",
"Load the CLAIRE file <file>. The given path may
contain an extension assuming .cl by default. When
the <-f> option is used, the file is assumed to
contain CLAIRE definitions (variables, class,
methods) wheheas <-ef> attemps to read a file made
of CLAIRE expression.")]
[option_respond(opt:{"-f", "-ef"}, l:list) : void ->
if not(l) invalid_option_argument(),
let path := l[1]
in (l << 1,
case opt
({"-f"} load(path),
{"-ef"} eload(path)))]
Ainsi, dès qu'une application est compilée avec le module Reader l'option -f est
implicitement supportée. L'option -h est supportée par le module Core et se sert des
restrictions d'option_usage pour dresser une aide accessible à la ligne de commande. Ainsi on
peut demander l'aide de l'option -f:
Pasted Graphic 14.tiff ¨
* Interprète et complétion automatique
Dans XL CLAIRE l'invite de commande est préfixée du PID du process. Cela permet
notamment de faire des fork à l'interprète et de savoir vers quel processus on envoie les
commandes.
Si le système sur lequel XL CLAIRE est installé dispose de la librairie editline alors
l'interprète peut en tirer parti pour proposer une interface avec un historique des commandes
ainsi que la complétion automatique de symboles connus par claire avec la touche TAB. De
plus, l'interprète est capable de lister les restrictions d'une propriété lorsque l'on tape TAB
après la parenthèse d'un appel fonctionnel :
[18386]claire> princ([TAB]
princ(string) -> void
princ(string, integer, integer) -> void
princ(symbol) -> void
princ(integer) -> void
princ(float) -> void
princ(char) -> void
princ(bag) -> void
[18386]claire> princ(
Enfin, si on tape TAB alors que la ligne de commande est vide on permute entre un
shell système et l'interprète CLAIRE sans quitter CLAIRE .
* Sampling Cmemory
Un lot de bug concernant le GC ont étés levé en 2004, dans ce contexte XL a
développé des outils pour tracer l'évolution de Cmemory en cours d'exécution. L'option «
-sample <period> » permet d'activer le trace de Cmemory avec une périodicité de <period>
millisecondes. A l'issue de l'exécution on peut utiliser le fichier texte généré
clmemory.sample avec une application type Excel ou gnuplot pour produire un graphique de
l'évolution de Cmemory au cours du temps.
Cette opération ne peut être effectuée que sous UNIX car l'API fork est utilisée. Chaque
échantillon est généré depuis un processus fils qui effectue un GC dans lequel les objets de
Cmemory sont comptabilisés en différentes sortes. Les processus fils sont crées de façon
asynchrone par une alarme levée toutes les <period> millisecondes. Ainsi le processus père
peut continuer sont exécution pendant que le fils produit son échantillon et l'activation de
l'échantillonnage ne perturbe pas l'exécution du processus sur une machine multiprocesseur.
Par exemple, le graphique ci-dessus à été réalisé sur une compilation des métas de
CLAIRE en « -s 3 3 » avec une période de 10 millisecondes :
Pasted Graphic 8.tiff ¨
Le temps d'exécution en abscisse est exprimé en seconde et l'occupation mémoire en
ordonnée est exprimé en méga-octet. On distingue les real short des short (respectivement
real chunk et chunk), le premier comptabilise tous les objets de la mémoire short qui sont
pointés par une racine tandis que le deuxième comptabilise tous les objets y compris ceux qui
ne sont plus pointés et qu'un prochain GC devrait détruire. Ainsi on vérifie à tout instant
l'identité suivante :
(real short) + (real chunk)
=
(object) + (string) + (symbol) + (bag) + (array)
Le graphique montre que deux GC se sont produits, après un GC ont vérifie idéalement
l'identité suivante :
(chunk) = (real chunk)
(short) = (real short)
Le graphique montre également une augmentation régulière du nombre de
bag/string/objet qui s'interprète par le nombre croissant d'objets instanciés par le Reader lors
de la lecture des fichiers méta. On voit enfin l'évolution des objets temporaire crées lors de
compilation des métas sur les deux courbes chunk et short.
* pré-allocation des listes annulables
Depuis CLAIRE 3 les listes annulables doivent être allouées une fois pour toute, cela
rend le mécanisme de changement de monde plus performant car seule les adresses
(directement sur le contenu de liste), où s'effectue les « updates », ont besoin d'être retenues
par les piles de monde. Par contre, il reste fastidieux de créer de telles listes vide par défaut
sans bricolage. Par exemple :
lesson <: ephemeral_object(
students:list[student] =
make_list(100, student, default_student))
(store(students))
lesson!() : lesson ->
let l := lesson()
in (shrink(l.students, 0),
l)
Dans cet exemple if faut prévoir une instance par défaut (default_student) pour
initialiser la liste puis faire un shrink car on désire une liste vide à l'initialisation, en plus on
alloue inutilement une liste pour le prototype de la classe. Pour simplifier la création de ces
listes, les bags ont un champ prealloc, dans le noyau XL, qui modifie la politique de copie du
bag :
class bag: public ClaireType {
public:
int length;
ClaireType *of;
OID* content;
int prealloc;
...
};
bag *copy_bag(bag *l) {
...
obj->prealloc = l->prealloc;
int m = l->length;
if (obj->prealloc > m) m = obj->prealloc;
if (ClAlloc->statusGC != 2) GC_PUSH(obj);
OID *x = ClAlloc->makeContent(m);
...
}
Deux méthodes relatives ont étés ajoutées pour la création de liste « pré-allouées » :
prealloc_list(t:type, len:integer) -> list
prealloc_set(t:type, len:integer) -> set
Ces deux méthodes renvoient des bags vides mais avec le champ prealloc initialisé à
len. Elles sont particulièrement utiles pour construire le prototype d'une classe qui contient
des slots de type « liste storé ». La liste allouée pour le prototype ne prendra pas de place en
mémoire, c'est seulement lors de l'instantiation, qui fait implicitement appel à la copie de
liste, qu'un contenu sera effectivement alloué. Ainsi l'exemple ci-dessus peut être réécrit
comme suit :
lesson <: ephemeral_object(
students:list[student] =
prealloc_list(student, 100))
(store(students))
lesson!() : lesson -> lesson()
Note : Avec le champ prealloc, une instance de bag a une taille de 4*sizeof(int) et peut
toujours tenir dans une cellule de la zone mémoire short object. Autrement dit, cette feature
ne nécessite pas de mémoire supplémentaire.
* printf @ port
Avec XL CLAIRE on peut utiliser la construction printf avec comme premier argument
un port. Ce qui allège certaines écritures ou l'on souhaite se passer d'une re-direction avec
use_as_output, par exemple :
printf(ctrace(), "Hello\n")
qui est équivalent à :
let p := use_as_output(ctrace())
in (printf("Hello\n"),
use_as_output(p))
* Toplevel et debugger
Dans XL CLAIRE la toplevel à été réécrite en CLAIRE et insérée dans le module
Reader. Le debugger CLAIRE à été amélioré, inspiré par gdb, ce nouveau debugger est
encore à l'état de prototype et demande un recettage approfondi (voir le paragraphe roadmap).
* Ports
Les ports XL CLAIRE ont subit une première évolution. Ils sont organisés en une
hiérarchie d'objet dérivés de freeable_object et ne sont plus des imports. Ainsi, on assure que
tous les ports sont correctement fermé à l'issue de l'exécution par l'implémentation de free! @
port. L'API de port <ycs> est toujours supportée :
•
•
•
•
putc(char, port) -> void
getc(port) -> char
flush(port) -> void
fclose(port) -> void
Des API proches de celles de la lib C ont étés ajoutées :
•
•
•
•
•
•
•
eof?(port) -> boolean
fread(port, string) -> integer
fread(port, integer) -> string
fwrite(string, port) -> void
freadwrite(port, port) ->integer
freadline(port, string) -> string
freadline(port, subtype[string]) -> tuple(string, string)
Ces API en combinaison avec la nouvelle représentation de string permet de manipuler
facilement des flux binaires. La méthode freadwrite permet de transmettre un flux, la famille
de méthode freadline (dont deux restrictions seulement sont mentionnée ci-dessus) permet de
« lire jusqu'à », par exemple :
explode_words(self:port) : list[string] ->
let words := list<string>()
in (while not(eof?(self))
let (w, blank) := freadline(self,
{"\n", "\r", " ", "\t"})
in words :add w,
words)
Note: L'implémentation des ports est en cours de réécriture tout en CLAIRE (voir le
paragraphe roadmap).
* Tables
Dans la version XL CLAIRE les tables, lorsqu'elles ne sont pas nommées (instanciées
avec make_table), peuvent être détruites par le GC. Ainsi on peut avoir des tables
temporaires.
* Terminal et couleurs
Le noyau XL supporte les couleurs pour la sortie vers le terminal (et en HTML comme
on le vera plus tard). Les couleurs sont sélectionnées par des séquences d'échappement
envoyée au terminal. Pour envoyer une chaîne colorée vers le terminal il faut utiliser la
méthode color_princ qui sait interpréter des séquences d'échappement commençant par un
backquote (comme `RED), un double backquote active le style gras. Pour que les couleurs
apparaissent à l'écran il faut spécifier l'option -color sur la ligne de commande, par exemple :
Pasted Graphic 26.tiff ¨
La construction printf utilise la méthode color_princ pour les parties statiques de la
chaîne de formatage et alterne les couleur dès qu'une partie dynamique (~S/~A/~I) est
rencontrée. Les messages d'erreur, qui sont affichés en rouge, deviennent ainsi beaucoup plus
lisibles :
Pasted Graphic 27.tiff ¨
* Script UNIX
Avec XL CLAIRE on peut écrire des script UNIX. Un script UNIX est un fichier texte
ayant des droits d'exécution et dans lequel est spécifié sur la première ligne un interpréteur
(CLAIRE dans notre cas). Le Reader à été adapté pour ignorer une telle ligne si elle est
présente. Voici un exemple de script :
#!/usr/local/bin/claire -x
(printf("Hello world\n"))
D'après la spec UNIX on ne peut spécifier qu'une seule option sur cette première ligne.
La famille d'option -x est prévue à cet effet :
Pasted Graphic 28.tiff ¨
Note 1: L'option -nologo sert à ne pas afficher le message d'initialisation de CLAIRE ni
le « bye... » final. L'option -q sert à quitter CLAIRE sans lancer d'interpréteur.
Note 2: Le noyau intercepte l'option -x<S>-<W> avant l'initialisation de CLAIRE afin
de lancer claire avec les paramètres mémoire spécifiés.
L'environnement de production
Eclaireur est un IDE pour CLAIRE qui offre une gestion de projets et une gestion de la
compilation. Eclaireur tourne exclusivement sous win32 et ne permet pas de créer et compiler
aisément des applications pour la plateforme UNIX. Sous UNIX on préférera utiliser la ligne
de commande pour compiler ses modules. XL CLAIRE a été étoffé d'un ensemble d'options
de ligne de commande qui facilitent la création, la compilation et le partage de modules.
* Installation et architecture
Afin de diminuer les incompatibilités que l'on peut rencontrer d'un UNIX à l'autre le
processus d'installation d'XL CLAIRE commence par le lancement d'un script configure
chargé de lever ces incompatibilités. Durant cette phase de configuration on définit également
une variable identifiant l'OS (darwin, linux, sun...), l'architecture matérielle (ppc, i386) et le
compilateur C++ (cc, gcc) ainsi que la version de ce compilateur que l'on utilise pour mettre à
jour le slot compiler.env, comme par exemple :
Linux-i686-g++3.3.3
Darwin-ppc-g++4.0.0
Le processus d'installation est le suivant, on se place dans le dossier des sources d'XL
CLAIRE puis :
./configure [--prefix=<dossier d'installation>]
make
[sudo] make install
On peut spécifier un dossier d'installation particulier, se dossier est « /usr/local » par
défault. A l'issue de l'installation on se retrouve avec un dossier claire crée au path
d'installation qui contient:
Pasted Graphic 31.tiff ¨
Ainsi on peut avoir plusieurs versions de claire, pour plusieurs architectures et pour
différents compilateurs C++, installées dans le même dossier. Le dossier lib est réservé aux
publications de module (voir le paragraphe partage de module).
* Création de nouveaux modules : option -nm
L'option -nm « new module » permet de créer facilement un nouveau module. L'aide en
ligne associée est la suivante :
Pasted Graphic 18.tiff ¨
Le module ainsi crée est vide (aucune définition) mais peut être compilé directement.
Si, plus tard, on ajoute des fichiers sources au module il faudra éditer le fichier init.cl. Le
fichier init.cl généré contient la définition du module, son load, ainsi qu'en commentaire
toutes les configurations possibles du compilateur ce qui évite de perdre du temps à se
souvenir de telle ou telle option (voir plus bas). Par exemple, pour créer un module
myModule utilisant Core et fait de model.cl on fait:
Pasted Graphic 16.tiff ¨
Le fichier init.cl généré est le suivant :
// init file for module myModule
// created Thu Aug 18 10:33:36 2005 by claire v3.3.35
(use_module("Core"))
myModule :: module(
uses = list(Core),
made_of = list("model.cl"),
source = "source",
version = "v1.0.0") // put your version here
(load(myModule))
// Here you can customize the C++ compiler.
// You can uncomment and set any of the following option :
// ==== external libraries needed at link time ====
;(compiler.libraries :add "-lsome_lib")
// ==== C++ compiler options ====
;(compiler.options[1] :/+ "-a_cpp_option") // Optimize mode (-O)
;(compiler.options[2] :/+ "-a_cpp_option") // Debug mode (-D)
;(compiler.options[3] :/+ "-a_cpp_option") // Release mode
// Here you can customize the CLAIRE compiler.
// You can uncomment and set any of the following option :
// ==== compiler safety ====
// 0 -> super safe
// 1 -> safe
// 2 -> trust explicit types & super
// 3 -> no overflow checking
// 4 -> assumes no selector or range error
// 5 -> assume no type errors of any kind
;(compiler.safety := 1)
// ==== compiler naming convention ====
// 0 -> long & explicit names
// 1 -> shorter names
// 2 -> protected names
;(compiler.naming := 0)
// ==== compiler inline flag ====
// set it to true if you want to include inline definitions in the generated library
;(compiler.inline? := false)
// ==== compiler overflow flag ====
// set it to true to produce safe code with respect to owerflow
;(compiler.overflow? := false)
// ==== fast dispatch flag ====
;(FCALLSTINKS := false)
// Here you can customize the CLAIRE code generator.
// Some symbol may be reserved in the target language,
// for such symbol you have to define a translation :
;(Generate/C++PRODUCER.Generate/bad_names :add some_symbol)
;(Generate/C++PRODUCER.Generate/good_names :add
symbol!("some_symbol_translated"))
Note : La commande use_module est décrite plus bas au sujet du partage de module.
* Compilation de module : option -cm
L'option -cm « compile module » permet de compiler un module en un exécutable.
L'aide en ligne associée est la suivante :
Pasted Graphic 13.tiff ¨
Contrairement à la version <ycs> on peut omettre le module lorsque l'on utilise l'option
-cm depuis le répertoire d'un module.
Des options ont été ajoutées pour customizer la compilation rapidement:
Pasted Graphic 21.tiff ¨
Par exemple pour compiler le module myModule en -O2 rapidement, on utilisera :
claire -cpp -O2 -cm
* Partage de module : options -publish et -export
Les options -publish et -export permettent de partager un module. Par cette opération
une copie du module (version, sources, init.cl, header et librairie) est effectuée vers un
dossier connu par CLAIRE. CLAIRE sait ainsi retrouver la liste des modules partagés, cette
liste est utilisée par la commande use_module que l'on place dans un fichier init.cl avant une
définition de module afin que tous les modules utilisés (slot uses) soient connus. L'aide en
ligne pour ces options est:
Pasted Graphic 20.tiff ¨
Ces deux options ne peuvent être utilisées que depuis le répertoire d'un module sur
lequel elles s'appliquent.
On distingue les publications, placées dans le répertoire de la version de CLAIRE
installée, des exports qui prennent place dans un dossier définit par l'utilisateur via la variable
d'environnement CLAIRE_LIBS. Ainsi on peut avoir une version de CLAIRE installée dans
un dossier partagé avec des publications de modules généraux et utilisables par plusieurs
utilisateurs et des modules locaux accessibles par un utilisateur en particulier.
On peut publier plusieurs versions d'un même module pour une architecture donnée,
par exemple voici la structure du module Casper une fois publié (dans le dossier d'installation
de claire):
Pasted Graphic 32.tiff ¨
Dans le cas d'un export la structure de dossier est identique. Ainsi pour chaque version
publiée d'un module on retrouve le init.cl et les sources de la version publiée ainsi que la
librairie et le (ou les) .h du module pour un couple « version de CLAIRE - architecture »
donné.
Connaissant cette architecture, la commande use_module sait énumérer le dossier lib
(ou un dossier définit dans la variable d'environnement CLAIRE_LIBS) pour retrouver un
module donné.
* Compilation de librairie : options -cls et -call
L'option -cls permet de compiler la librairie d'un module (on doit se trouver dans le
dossier du module) et l'option -call permet de compiler un ensemble de module (on doit se
trouver dans un dossier parent d'un ou plusieurs modules). L'aide en ligne de ces options est:
Pasted Graphic 22.tiff ¨
Ces options peuvent être combinées avec les options de publication, par exemple la
commande suivante va recompiler toute les librairies release (-call) des modules qui se trouve
dans des sous dossiers du dossier courant en safety 5 (-os 5) avec l'option d'optimisation C++
-O2 (-cpp -O2). Chaque module recompilé sera ensuite publié (-publish) avec les droits root
(-sudo) et éventuellement écrasera (-ov) des publication existantes:
claire -os 5 -cpp -O2 -call -sudo -ov -publish
Lorsque l'option -call est utilisée et que les modules à compiler sont interdépendants les
sources des versions locales sont préférée aux versions éventuellement déjà publiées.
* Informations de partage: option -ml et -mi
L'aide de ces options est la suivante :
Pasted Graphic 25.tiff ¨
L'option -ml « module list » donne une liste des modules partagés. La commande
use_module évoquée plus haut ne pourra trouver qu'un module de cette liste. A titre
d'exemple voici la liste des modules publiés sur mon système à l'heure de l'écriture de ce
document :
Pasted Graphic 23.tiff ¨
Sur chaque ligne se trouve le nom d'un module partagé et l'ensemble des versions
disponibles pour ce module. Pour chaque version se trouve entre crochets les lettre r et/ou d
qui indique la présence d'une version release et/ou debug.
Enfin on peut obtenir des informations sur un module en particulier avec l'option -mi «
module information », par exemple:
Pasted Graphic 24.tiff ¨
L'infrastructure Web
* Le module Wcl
Après avoir développé certains projets à l'aide du langage PHP, XL s'en est inspiré et à
conçu sa propre infrastructure pour la génération de page dynamique. Le module Wcl « Web
CLAIRE » est au coeur de cette infrastructure.
A l'origine Wcl est un interpréteur de balises de code CLAIRE embarqué dans une
source HTML. Aujourd'hui Wcl rempli plusieurs tâches supplémentaires dont la prise en
charge des protocoles HTTP et CGI, la lecture des données de formulaires HTML et la
sauvegarde des données de session utilisateur dans un format binaire à l'aide du module
Serialize. Ci-dessous on a un schéma de principe concernant le rôle du module Wcl :
Pasted Graphic 29.tiff ¨
Un agent CLAIRE équipé du module Wcl sait communiquer avec le serveur web
populaire Apache 2 par l'intermédiaire du module apache mod_wcl développé par XL. Ce
dernier est chargé, lors d'une connexion au serveur, de lancer l'agent CLAIRE dans un
environnement type CGI et de lire la sortie de l'agent qui contient à la réponse à la requête
(par re-direction des entrée/sortie). Pour cela il est important, comme mentionné plus haut,
que la sortie de l'agent ne soie pas polluée par des traces de GC par exemple. Les traces sont
redirigés vers un fichier et peuvent être visualisés à l'aide, par exemple, de la commande
UNIX tail.
Le module mod_wcl lance un agent CLAIRE avec l'option -wcl qui, lorsqu'elle est prise
en charge (option_respond @ {"-wcl"}), décode l'environnement CGI pour trouver et loader
le fichier requis. Avant de charger effectivement le fichier wcl requis le moteur Wcl remplit
une table nommée $ avec les variables de formulaire décodées depuis stdin et
l'environnement:
claire/$[key:string] : any := false
* fichiers .wcl
On appelle fichier wcl un fichier HTML qui contient des balises de code CLAIRE. Par
exemple :
<html>
<? (printf("Ce message est généré par CLAIRE")) ?>
</html>
Une fois passer dans la moulinette wcl le fichier devient :
<html>
Ce message est généré par CLAIRE
</html>
La balise <? introduit donc du code CLAIRE, deux balises supplémentaires sont
disponibles pour introduire du code: <?= et <?== qui, non seulement, évalue l'expression
qui suit mais invoque également une méthode de print (respectivement echo et self_html) sur
le résultat de l'évaluation. Par exemple:
<html>
1 + 2 = <?= (1 + 2) ?>
</html>
qui produit le résultat :
<html>
1 + 2 = 3
</html>
L'interpréteur Wcl introduit est en fait une nouvelle facilité de print. En effet (dans un
fichier claire classique) on peut introduire une séquence wcl par la balise ?>, et on en fait
largement usage avec les modules Pdf ou Mail (voir plus bas).
* session utilisateur
Les sessions utilisateur contiennent des données temporaires qui permettent un suivi
entre deux connexions successives. On utilise la méthode session_start ou session_url pour
démarrer une session utilisateur depuis un fichier wcl. L'identifiant de session peut être
transmit sous forme de cookie (session_start) ou directement sur l'URL (session_url).
A une session est associé un fichier sérialisé contenant les variables qui auront étés
mises en session grâce aux API register et rregister :
register(var:string, val:any) -> any
rregister(var:string, val:any) -> any
Les variables mises en session sont ensuite accessibles via la table $. rregister est une
variante de register qui sérialise l'arbre d'objets inter-pointés via val jusqu'aux objets
nommés.
* Erreurs en Wcl
Les erreurs générées par un srcipt wcl ne sont pas fatales, mais seulement affichées
dans la syntaxe HTML. La gestion des couleurs évoquée plus haut n'est plus basée sur des
séquences d'échappement mais sur des balises HTML.
Les erreurs sont également rappelées dans le fichier de trace.
* Un binaire pour un site web!
Les fichiers wcl peuvent être compilés en C++. Ainsi on peut créer un binaire qui
contient tout un site web. Les performances en terme de temps de réponse sont fantastiques
comparé à d'autre technologie comme PHP.
* Infrastructure de modules
XL a développé des modules utilitaires pour réaliser différentes tâches répétitives
comme le dialogue avec une base de donnée, la génération de document PDF ou encore
l'envoie d'email. Cette infrastructure logicielle peut être schématisée comme suit:
Pasted Graphic 1.tiff ¨
Serialize: Permet de stocker un arbre d'objets (y compris les relations inter-objets) dans
une forme binaire. Un flux serialisé peut par exemple être transmis sur un port réseaux pour
transmettre des instances CLAIRE à un processus distant. On utilise Serialize pour stocker en
fichier les données de session.
Locale: Implémente la méthode translate pour les applications multilingues et gère un
dictionnaire de termes.
Zlib: Implémente un port dédié à la compression/décompression d'un flux. Basé sur la
librairie populaire zlib.
Soap: Permet de faire des appels distants à des procédures (client) avec le protocole
SOAP ainsi que de créer un service SOAP (serveur).
WclSite: Couche d'abstraction pour l'écriture de site web. Administration d'application
internet et gestion de menu, de groupe, d'utilisateur, d'authentification et de droit d'accès.
Pdf: Lecture et écriture de document PDF éventuellement compressés. Basé sur un
convertisseur HTML vers PDF pour une écriture concise de documents complexes
(paragraphe, titres, tables, image, listes, saut de page automatiques...). Supporte la signature
digitale par certificat X509 en écriture ainsi que la validation d'une signature en lecture. C'est
un outil puissant quand il est utilisé avec la syntaxe Wcl, par exemple:
doc :: Pdf/document!("A4")
(Pdf/print_in_html(doc) ?>
<p align=center>
Hello world,
by CLAIRE v<?== release() ?>
</p>
<? Pdf/end_of_html(doc))
(Pdf/print_in_file(doc, "helloworld.pdf"))
Mail: Lecture, écriture et envoie de message électronique via le protocole SMTP.
Comme pour Pdf on profitera largement de la syntaxe Wcl pour écrire le corps d'un message
HTML.
Db: Couche d'abstraction pour la communication avec un SGBD. Permet de soumettre
des requêtes SQL et d'en lire les résultats.
Mysql & Postgres: Driver de base de donnée, ces deux modules implémentent
l'interface définie dans le module Db.
Dbo: « database objects », prend en charge le mapping entre une classe CLAIRE et une
table en base de donnée. Dbo permet de communiquer avec une base de donnée sans écriture
la moindre requête SQL.
Openssl: remonte en CLAIRE des fonctionnalités de la librairie OpenSSL (gestion de
certificats, gestion de clefs publique/privée, chiffrement...). Pdf utilise Openssl pour traiter les
signatures digitales.
Roadmap
* Septembre 2005
Les ports sont en cours de réécriture tout en CLAIRE. Avec les nouveaux ports, on
pourra écrire ses propres ports en CLAIRE. Les nouveaux ports CLAIRE définissent deux
classes de base :
claire/port <: freeable_object(
firstc:integer = 32,
closed?:boolean = false)
claire/device <: port(filters:list[filter])
claire/filter <: port(dev:device, target:port)
(inverse(dev) := filters)
Les notions de périphérique et de filtre sont introduites:
• un filtre (filter) est un port qui peut transformer/collecter/analyser un flux
• un périphérique (device) correspond à un port physique (fichier, socket ...), on
peut lire et écrire sur un périphérique à travers une chaîne de filtres.
Allié au string du noyau XL CLAIRE, cette nouvelle implémentation permet de
prendre charge facilement des flux encodés par différents protocoles imbriqués.
XL possède déjà un prototype prometteur entièrement compatible avec l'API existante.
Cette nouvelle implémentation fait largement usage du fast dispatch (introduit dans CLAIRE
3) qui s'avère bien plus efficace que les appels virtuels C++ qui sont aujourd'hui utilisés. De
plus, sont implémentés en CLAIRE, des filtres qui remplacent l'interface C FILE*(buffering
par ligne et par block) ainsi que différents services comme compter les lignes lues par le
reader.
Sur la compilation des métas et du compilateur, qui fait beaucoup de lecture/écriture de
fichier on observe un gain de 40% sur le temps de compilation!
* Septembre 2005
Dans le noyau, il faut changer le champ ascii de la classe ClaireChar (interface C++ de
char) en unsigned char afin de lever les ambiguïtés introduites avec un char signé. La table
de caractère (ClRes->ascii) sera ainsi parfaitement définie sur l'intervalle 0, 255 (aujourd'hui
elle en contient 512).
* Septembre 2005
Lever la limitation MAXBUF en changeant ClEnv->buffer en un tableau dynamique
réallouable. Le buffer ne sera plus dans la mémoire CLAIRE.
* octobre 2006
Création d'un module dédié aux API de la libC ajoutées historiquement au noyau. Ceci
afin de diminuer la taille du noyau.
* d'ici 2006
Wcl va être « explosé » en trois entités différentes:
• La partie purement liée à la syntaxe Wcl va être descendue au niveau du
Reader. On pourra utiliser cette syntaxe comme une alternative à printf sans l'usage
d'un quelconque module (lève la dépendance inutile à Wcl pour les modules Pdf et
Mail).
• La partie chargée de des protocoles CGI et HTTP va faire partie d'un module à
part: Http. Ce module sera utilisé par le module Soap et le module WclSite qui font
aujourd'hui usage de Wcl.
• La partie qui prend en compte les sessions va être intégrée au module WclSite.
* d'ici 2006
Finition, recettage du deboggeur.
* fin 2005 - 2006
Implémentation de la construction scanf. scanf est à la lecture ce que printf est à
l'écriture.
* 2006
Mise à jour du site claire-language.com. Le site claire-language utilise déjà
l'infrastructure web et sera mis à jour avec les évolutions des modules Mail, Wcl et WclSite.
Téléchargement