Ravi
Welcome
Documentation
Documentation
About Ravi
Documentation
Introduction
Premiers pas avec Ravi
ravitool
Scheme Tutorial
Objets Scheme
Le shell ravi
Starting Ravi
Le module trace
Les ports d'E/S
The C Parser
load, require, modules
Système d'interruptions
Scheme compiler
C++ mode
Generating C++ Modules
La déclaration struct
Le type "C-object"
More information
Installation

[PREV][SUIV]

load, require, modules

Introduction: LOAD et REQUIRE

On trouve sur cette page:

La fonction load sert à charger un fichier. Dans le cas le plus simple, c'est un fichier avec des définitions des fonctions Scheme; il suffit de taper


	(load "monfichier")
pour que monfichier.scm soit ainsi chargé - le load est capable d'ajouter le bon suffix.

Détail important: dans quel répertoire trouve-t-on ce fichier? Le load cherche dans les répertoires donnés par la variable Unix RAVI_DLD_PATH; il est important que celle-ci inclut le répertoire courant ./

La fonction include: include est synonyme de load pour des programmes interprétés. Par contre, include est traité très différemment par le compilateur. Voir la doc du compilateur.

Lorsqu'on avance dans un projet de programmation, on exige plus d'une fonction de chargement - en effet, la fonction load est capable de beaucoup de choses qu'on prendra la patience à expliquer.

Le manuel du load

Le load a 3 paramètres:


	(load s path-l err-fn)
dont seul le premier est obligatoire: une chaine s. Dans le cas le plus simple, s est le nom d'un fichier qu'on charge. Plus généralement, le load procède en trois étapes:
  1. analyse de s, qui est decomposé en répertoire/nom/suffixe
  2. recherche d'un fichier cible
  3. chargement du fichier trouvé.
Précisons chaque etape

1 Analyse de l'argument s

Cette analyse fournit trois chaines de caractères:

  • Dir - un nom de repertoire, s'il est present, est donné par le préfixe de s allant jusqu'au dernier caractere / Ce préfixe peut comporter des noms de variables Unix, qui sont alors substitués. Limitation: un tel nom est delimité par /

  • Nom - le nom de fichier

  • Suf - le suffixe, s'il est présent, commence avec le dernier caractère . dans s

2 Recherche de fichier

On balaie une liste de répertoires Dir-List à la recherche d'un fichier Nom.su Le suffixe su est le Suf déterminé au 1, s'il existe; sinon, il doit être dans la liste des suffixes standards: .mobj .scm .o .so (cf. Init.scm)

La Dir-List et déterminée en fonction du préfixe Dir, du parametre path-l, et de la variable globale *ld-path* comme suit.

* Si au 1 on a trouvé un préfixe Dir non vide, on cherche seulement dans le répertoire ainsi défini: soit en absolu, si le 1ier caractère de Dir est / soit en relatif, par rapport au répertoire . (Question: meme si dans un load recursif?)

* Sinon, si l'appel du load comporte un parametre path-l explicite, c'est la Dir-List. (path-l doit être une liste pour être pris en compte).

* Sinon, si le load est appelé au "premier niveau", la Dir-List est donnée par la variable *ld-path*, qui, normalement, dérive de la variable Unix RAVI_DLD_PATH (cf. Init.scm).

Attention: en principe, RAVI_DLD_PATH doit commencer par un .

* Si le load a été appelé, récursivement, à l'intérieur d'un load, la Dir-List commence par le répertoire courant, puis la variable *ld-path*. C'est une forme de liaison lexicale de fichier qui assure une bonne transparence, mais que ne colle pas avec l'esprit Unix.

Si aucun fichier convenable n'est trouvé lors de la recherche, on appèle la fonction err-fn, si load a été appelé avec un 3ieme paramètre. err-fn doit être une fonction sans arguments. Si ce 3ieme parametre n'est pas fourni, on provoque une erreur.

Remarques

1) C'est la variable *current-load-path* qui indique au load ou il en est. Il me semble raisonnable de mettre (set! *current-load-path* "") dans votre .RaviInit.scm - comme c'est deja fait dans Init.scm Sans quoi un load dans le fichier init peut ne pas fonctionner!

2) Le load-once a exactement les mêmes paramètres. La seule différence: il charge le fichier seulement si le nom extrait de l'argument s ne figure pas dans la liste des modules chargés. (variable *features*)

3) Le paramètre path-l est pris en compte seulement s'il est une liste non vide, (ca doit évidemment être une liste de chaines de caractères). On peut donc fournir une fonction err-fn sans imposer de Dir-List.

3 Chargement a proprement parler

En mode verbose, un message est imprimé avec le nom complet du fichier.

======================================================================

require et la gestion des modules

Où la fonction require trouve-t-elle un module? Désormais, le require effectue une recherche dans un certain nombre de répertoires.

C'est un changement majeur par rapport au passé, où on utilisait une table qui listait tous les modules, table initialisée par appels à la fonction register-module; cette fonction disparait, ainsi que la table au nom de *modules*.

C'est un changement important qui devrait simplifier la vie à tout le monde!

Fonctions

(require nom) La fonction require recherche, dans une liste de répertoires, le premier fichier nom.suffixe ; le suffixe étant un parmi .x.scm .mobj .scm .so {ou .o sur SunOS4}.

La liste de répertoires par défaut dépend de la variable système RAVIREP:

("$RAVIREP/Module" "$RAVIREP/Module/$RAVIARCH" "$RAVIREP/Module/GenModule" "$RAVIREP/Runtime")

Si ce défaut n'est pas suffisant, il faut utiliser une variable système au nom de RAVI_MOD_PATH; le défaut est équivalent à

setenv RAVI_MOD_PATH $RAVIREP/Module"':'"$RAVIREP/Module/$RAVIARCH"\ ':'"$RAVIREP/Module/GenModule"':'"$RAVIREP/Runtime

La liste des répertoires utilisée par require se trouve dans la variable globale *module-path* qui est initialisée dans le Init.scm.

(locate-module nom sl)

Cherche le fichier d'un module, avec un des suffixes de la liste sl; résultat #f si pas trouvé, sinon c'est la liste

(dir name suffix fullname)

(calcule-path2 var défaut) devrait remplacer calcule-path

La fonction


	(link-module nom-module nom-fichier)
permet de faire face au cas où nom de module et nom de fichier divergent; on cherchera à éliminer ce cas.

=============================================

Definition en autoload

Un "truc" simple et elégant à connaitre, notamment pour les fichiers d'initialisation (.RaviInit.scm notamment): la définition qui effectue un chargement ou autre au premier appel, et qui disparait aussitot après.

Prenons des exemples dans Init.scm, pour voir deux versions:

Première version: fonction normale


	(define (pretty-print . l)
	  (require 'pretty-print)
	  (apply pretty-print l))

Deuxième version: avec macro


	(define-macro (trace . l)
	  (require 'trace)
	  (cons 'trace l))

Lors du premier appel de trace, le (require 'trace)effectue les initialisations necéssaires, puis la macro provoque un nouvel appel de la trace, avec les mêmes arguments; la définition qui vient d'être chargée est alors trouvée et s'exécute normalement.

C'est astucieux pour plusieurs raisons:

  1. aux appels suivants, il n'y a aucun surcoût, la définition préliminaire disparait sans laisser trace.
  2. la trace est utilisable comme une fonction standard, mais elle est chargée uniquement lorsqu'elle est effectivement utilisée.
  3. on rend invisible le require
  4. c'est adaptable a tout systéme Lisp

C'est intéressant pour les modules qui ont 1 ou 2 fonctions principales.

Notez le nombre d'arguments variables: cela permet tout nombre d'arguments dans la définition définitive.

La première version semble préférable: les macros ne font pas partie de la définition de Scheme, et on peut compiler des appels de pretty-print sans pb, ce qui n'est pas le cas pour la macro.

Attention: si, par erreur, la require ne (re-)définissait pas la fonction trace, il y aurait une boucle infinie.

Ce type de définition est utilisé (dans le fichier Init.scm) pour:

pretty-print trace silent-trace help a-propos defrule assert .

Mise en place d'une boite à outils

Nous appelons "boite à outils" un ensemble de modules interdépendants (ou non), qui peuvent faire appel à des fichiers auxiliaires. Ce paragraphe décrit un schéma d'installation standard que nous proposons. Schéma facile à adapter.

Principe: les modules, au sens Ravi, résident dans un répertoire. Ce répertoire figure dans la variable *module*. Aucun fichier auxiliaire ne se trouve dans ce répertoire (cela évite der erreurs), mais dans des sous-répertoires. Cela assure qu'on peut facilement déplacer une boite complète, et qu'on trouvera toujours les bons fichiers auxiliaires!

Trois variables Ravi permettent de paramétrer tout cela: *module-path*, *ld-path*, *roo-load-path*.Elles sont définies dans le fichier ~/.ravi/paths.scm Par ailleurs, il faut que le LD_LIBRARY_PATH soit correctement défini pour les chargement via Ravi (rien n'a changé sur ce point).

*module-path*
Cette variable contient la liste des répertoires de recherche pour la fonction require. Cette liste est parcourue de facon séquentielle, pour trouver le module.

*ld-path*
Cette variable contient la liste des répertoires de recherche pour la fonction load. Ne sert pas pour les modules.

*roo-load-path*Cette variable est utilisée pour charger les .sodepuis un fichier Scheme: elle donne une liste de répertoires en relatif!C'est nouveau - ce petit point est important! Remarque: si la variable *roo-load-path* a pour valeur #f, on retombe dans la convention ancienne, selon laquelle les .so sont cherchés dans les répertoires de *ld-path*.

Exemple: la boite à outils libvision.

Mon fichier ~/.ravi/paths.scm est comme suit:

(la fonction dir-name traduit les variables Unix, elle a été ajoutée dans Init.scm)


(define *module-path*
  (list
   (dir-name "$GLOBALVISION/Mod")
   (string-append *library-root* "/Module")
   (string-append *library-root* "/Module/" *system-architecture*)
   (string-append *library-root* "/Module/GenModule")))
 ;; cette derniere ligne doit disparaitre tres bientot

(set! *roo-load-path* (cons (string-append "../Lib/" (getenv "RAVIARCH") "/") *roo-load-path*)) (define *ld-path* '("."))

==============================================

A discuter:

nous avons 2 noms d'architecture: RAVIARCH et *system-architecture*