Suivez-nous sur X
|
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
ALL
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
A propos d'Obligement
|
|
David Brunet
|
|
|
|
Programmation : DICE - DiceConfig et programmes résidents
(Article écrit par Laurent Faillie et extrait d'Amiga News - mai 1993)
|
|
Après l'installation, il est temps de programmer notre premier utilitaire avec DICE. La version
enregistrée ayant beaucoup trop d'options pour utiliser les alias comme pour la version gratuicielle, nous allons donc créer
un programme de configuration. Il faut se rappeler que DCC prend ces options aussi bien dans la ligne de commande que
dans DCCOPTS.
Attention : il s'agit d'une variable de type "Commodore" (donc stockée dans ENV:), en opposition aux variables "ARP"
utilisées par Csh.
Notre programme va remplir cette variable en fonction de l'exécutable que nous voulons créer. Tapez le listing de DiceConfig
et compilez avec :
Dcc -2.0 -ms -// -r DiceConfig.c -o DiceConfig
|
DiceConfig a besoin d'un fichier de configuration nommé "DiceConfig.cfg".
La première ligne contient toutes les options toujours présentes (-2.0 pour l'utilisation des includes et bibliothèques du 2.0...).
Les lignes suivantes indiquent, par groupes de 2, les bibliothèques que l'on peut lier (linker) :
- La première ligne contenant le nom,
- La seconde les actions à faire.
A l'exécution, le programme ouvre une fenêtre où l'on peut :
- Choisir le niveau de profiling (profilage). Il s'agit de code que DICE ajoute et qui donne des statistiques sur l'exécution
d'un programme. Très utile pour savoir où un programme perd son temps.
- Créer un programme pure (pur) (qui peut être rendu résident).
- Unix permet d'ouvrir les fichiers avec une syntaxe à l'UNIX.
- Dynastack crée un programme avec une pile dynamique. Très utile pour les programmes récursifs !
- Enfin, Debug ajoute le "hunk-symbole" à l'exécutable (lors du réassemblage avec Dobj par exemple, les
étiquettes sont conservées). Il fait aussi un #define DEBUG pour une compilation conditionnelle. Nous y reviendrons
par la suite (toujours des promesses...).
- Le dernier groupe de gadgets sert à choisir les bibliothèques à lier. Pour le moment, il ne devrait y avoir
que "math" de sélectionnable.
Le code
Regardons un peu le code. D'abord, on peut voir que les messages peuvent être
en français en mettant la variables "Lang" à "français". Je préfère cette solution à la locale.library qui n'est pas
compatible avec le 1.3 (de toute façon, je n'ai pas les documentations...).
Il contient aussi quelques particularités de DICE :
- La première chose qui peut surprendre les utilisateurs d'autres compilateurs est que je n'ai ouvert aucune bibliothèque :
DICE le fait tout seul. Cela évite quelques Gurus !
- Une des fonctions de ce programme est aussi de se rappeler la configuration des gadgets entre deux appels. J'ai donc
utilisé la propriété "__config" pour deux variables qui contiennent l'état du programme. DICE crée le code pour que ces
variables soient automatiquement lues au départ et sauvegardées à la fin de l'exécution.
Grâce à l'option -r, notre exécutable peut être mis résident. Voilà une bonne occasion pour se pencher sur les programmes
pure.
"Pure"
Un programme pure est un programme qui peut être mis résident. Cette possibilité est apparue avec le système 1.3 pour les
utilisateurs du Shell standard et depuis beaucoup plus longtemps pour ceux qui préfèrent les Shells utilisant l'arp.library
(Csh, AShell...). Une fois de plus, grâce à Commodore, les deux résidents ne sont pas compatibles ! (mais ils peuvent
quand même cohabiter comme nous avons pu le voir dans le premier épisode).
Pour résumer, la table Commodore est gérée par "Res1.3" alors que la table Arp est gérée par "resident" (le résident du Shell).
Or DCC se trouve dans l'Arp (pour être accessible depuis le Shell) et ne gère que la table Commodore où doit donc se trouver
Dc1, Das, Dlink. Les dernières versions de Csh (V5.19 par exemple) permettent d'utiliser aussi la table Commodore mais ce
n'est pas encore parfait (et ça ne marche pas sous 2.0). Une autre différence, l'Arp reteste l'intégrité de la commande à
chaque fois qu'il l'exécute, mais pas Commodore. Essayez de rendre résident une commande non pure dans le Shell du 1.3.
La première exécution passe... la seconde casse ! Csh nous aurait indiqué que la commande a été altérée.
Quelles différences y a-t-il entre un programme ordinaire et une commande pure ?
Un programme normal peut modifier, comme il le veut, ces variables, voire son propre code, car à chaque nouvelle
exécution, tout sera rechargé depuis le disque ; pour un programme résident, ceci n'est plus possible car le même
segment mémoire est utilisé à chaque fois. Prenons le programme suivant :
int i=5;
Void main(){
i++;
printf("%d\n",i);
}
|
"Non Pure"
Dans le cas d'un programme non pure, le compilateur réservera la place pour "i" en y mettant directement la valeur 5. Si
ce programme est mis résident de force, la première exécution donnera 6 (5+1), mais la seconde donnera 7 (6+1) - ou ne
marchera pas dans un Shell Arp car la somme de contrôle (checksum) de la commande a changé. En effet, rien n'a remis "i"
à sa valeur initiale après la première exécution !
Un programme pure s'y serait pris autrement : les variables globales sont créées dynamiquement - ce qui permet à la
commande de s'exécuter simultanément dans plusieurs Shells, les variables étant recréées pour chaque tâche - et son affectées
ensuite à leurs valeurs initiales.
Comment ce n'est pas clair ? Allez prendre une bière - ou un Pastis - et relisez calmement ce qui précède.
De toute façon, le C est un langage de haut niveau, donc nous ne devrions pas nous soucier de ces questions très techniques.
Ouais, bof, les utilisateurs du Lattice ou de Aztec peuvent vous en parler (peut-être que leurs dernières versions permettent
ce genre de manipulations). Avec DICE, rien de plus simple, il n'y a qu'à ajouter un -r à la ligne de commande et le tour est joué.
Presque, car si le programme comporte des données en mémoire Chip, elles doivent obligatoirement être constantes. Enfin,
DICE permet de partager des variables entre plusieurs tâches d'un même programme s'il est résident, avec l'attribut
__shared mais ça ne marche pas avec les Shells Arp (somme de contrôle modifiée).
Bon, c'est fini pour aujourd'hui. La prochaine fois nous verrons les bibliothèques partageables...
Note : vous pouvez télécharger une archive contenant le binaire de DiceConfig
v1.0 avec le fichier source.
|