Obligement - L'Amiga au maximum

Lundi 02 juin 2025 - 03:50  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

Actualité (récente)
Actualité (archive)
Comparatifs
Dossiers
Entrevues
Matériel (tests)
Matériel (bidouilles)
Points de vue
En pratique
Programmation
Reportages
Quizz
Tests de jeux
Tests de logiciels
Tests de compilations
Trucs et astuces
Articles divers

Articles in English


Réseaux sociaux

Suivez-nous sur X




Liste des jeux Amiga

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


Trucs et astuces

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


Glossaire

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


Galeries

Menu des galeries

BD d'Amiga Spécial
Caricatures Dudai
Caricatures Jet d'ail
Diagrammes de Jay Miner
Images insolites
Fin de jeux (de A à E)
Fin de Jeux (de F à O)
Fin de jeux (de P à Z)
Galerie de Mike Dafunk
Logos d'Obligement
Pubs pour matériels
Systèmes d'exploitation
Trombinoscope Alchimie 7
Vidéos


Téléchargement

Documents
Jeux
Logiciels
Magazines
Divers


Liens

Associations
Jeux
Logiciels
Matériel
Magazines et médias
Pages personnelles
Réparateurs
Revendeurs
Scène démo
Sites de téléchargement
Divers


Partenaires

Annuaire Amiga

Amedia Computer

Relec


A Propos

A propos d'Obligement

A Propos


Contact

David Brunet

Courriel

 


Programmation : Le C sur Amiga (clib, pragmas, inlines, bibliothèques stub, proto, amiga.lib...)
(Article écrit par l'équipe de GuruMed et extrait de GuruMed.net - janvier 2003)


La principale différence entre le "bête" C ANSI/ISO et le C sur Amiga est l'utilisation de bibliothèques partagées. La quasi-intégralité d'AmigaOS se trouve dans des bibliothèques partagées (exec.library, dos.library, intuition.library...), et il existe également de nombreuses bibliothèques additionnelles créées par des auteurs tiers.

Le langage C utilise la pile pour passer les paramètres aux fonctions, tandis que ce sont les registres du 68k qui sont utilisés pour les fonctions d'AmigaOS et des autres bibliothèques. Pour utiliser ces dernières, un programmeur doit donc faire appel à des fichiers d'en-tête ou à des bibliothèques de liens ("link-libs") particulières. Ces fichiers ne sont pas les mêmes selon le compilateur que vous utilisez, et les auteurs de bibliothèques ne fournissent pas toujours ceux dont vous avez besoin.

Cet article vise à clarifier le sujet des inlines, pragmas, protos, fd, sfd, clib et autres bibliothèques "stub" (bouchons, de remplacement) utilisés sur Amiga, et à vous expliquer comment les générer s'il vous en manque pour utiliser une bibliothèque particulière. Il abordera également brièvement le sujet de l'amiga.lib.

Le répertoire "clib"

Ce répertoire contient les prototypes des fonctions des bibliothèques partagées. C'est du C standard : le compilateur doit connaître le prototype d'une fonction avant que celle-ci ne soit appelée dans un source. Le fichier "clib" d'une bibliothèque doit donc être inclus dans tout programme souhaitant utiliser cette dernière.

Extrait du fichier clib/amigaguide_protos.h :

LONG LockAmigaGuideBase( APTR handle );
VOID UnlockAmigaGuideBase( LONG key );
APTR OpenAmigaGuideA( struct NewAmigaGuide *nag, struct TagItem * );
APTR OpenAmigaGuide( struct NewAmigaGuide *nag, Tag tag1, ... );

Les prototypes sont les mêmes quels que soient le compilateur et le processeur/système cible (68k, PowerPC, x86, AmigaOS, PowerUP, WarpOS, MorphOS ou Amithlon).

Les pragmas

Les pragmas se trouvent généralement dans un répertoire "pragmas", ou parfois "pragma" (dans le cas d'Aztec C, et aussi lorsqu'on utilise fd2pragma (voir la fin de l'article)). Ils sont par définition spécifiques à chaque compilateur. Ils sont utilisés pour l'accès aux bibliothèques partagées par les compilateurs SAS/C, StormC 3, DCC, MaxonC, Lattice et Aztec.

Ces fichiers contiennent la description des registres du processeur utilisés pour transmettre les paramètres aux fonctions des bibliothèques, ainsi que la base de bibliothèque à utiliser.

Voici un exemple de pragma dans le format utilisé par SAS/C, DCC et Lattice :

#pragma libcall AmigaGuideBase LockAmigaGuideBase 24 801
#pragma libcall AmigaGuideBase UnlockAmigaGuideBase 2a 001
#pragma libcall AmigaGuideBase OpenAmigaGuideA 36 9802
#pragma tagcall AmigaGuideBase OpenAmigaGuide 36 9802

Vous n'y comprenez rien ? Moi non plus. Notez que le pragma "tagcall" n'est valable que pour SAS/C ; les deux autres compilateurs ne peuvent apparemment pas appeler de fonctions à nombre variable d'arguments (aussi appelées "tag functions") par cette méthode.

Voici la description des mêmes fonctions, mais pour StormC, Maxon et Aztec C cette fois :

#pragma amicall(AmigaGuideBase, 0x24, LockAmigaGuideBase(a0))
#pragma amicall(AmigaGuideBase, 0x2a, UnlockAmigaGuideBase(d0))
#pragma amicall(AmigaGuideBase, 0x36, OpenAmigaGuideA(a0,a1))
#pragma tagcall(AmigaGuideBase, 0x36, OpenAmigaGuide(a0,a1))

C'est déjà un petit peu plus compréhensible à l'oeil nu, puisqu'on y remarque la liste des registres utilisés. Comme précédemment, le pragma "tagcall" ne marche qu'avec StormC et pas avec Maxon ni Aztec C.

Les inlines

Les inlines se trouvent dans le répertoire "inline". Ce sont des macros qui remplissent exactement la même fonction que les pragmas mentionnés ci-dessus, mais pour les compilateurs GCC et vbcc (ainsi que StormC 4 puisqu'il utilise GCC).

Exemple, pour GCC :

#define LockAmigaGuideBase(handle) \
   LP1(0x24, LONG, LockAmigaGuideBase, APTR, handle, a0, \
   , AMIGAGUIDE_BASE_NAME)
#define UnlockAmigaGuideBase(key) \
   LP1NR(0x2a, UnlockAmigaGuideBase, long, key, d0, \
   , AMIGAGUIDE_BASE_NAME)
#define OpenAmigaGuideA(nag, attrs) \
   LP2(0x36, APTR, OpenAmigaGuideA, struct NewAmigaGuide *, nag, a0, struct TagItem *, attrs, a1, \
   , AMIGAGUIDE_BASE_NAME)
#define OpenAmigaGuide(a0, tags...) \
   ({ULONG _tags[] = { tags }; OpenAmigaGuideA((a0), (struct TagItem *)_tags);})

Je vous laisse décider si vous trouvez ça plus ou moins clair que les pragmas (mais rassurez-vous, ça doit être une question d'habitude). Notez que la syntaxe "({ ... })" n'est pas du C standard, mais est une notation spécifique à GCC qui sert à assigner au bloc la valeur de la dernière expression évaluée en son sein.

Et pour vbcc, ça ressemble à ça :

LONG __LockAmigaGuideBase(__reg("a0") APTR handle, __reg("a6") struct Library *)="\tjsr\t-36(a6)";
#define LockAmigaGuideBase(handle) __LockAmigaGuideBase((handle), AmigaGuideBase)

void __UnlockAmigaGuideBase(__reg("d0") long key, __reg("a6") struct Library *)="\tjsr\t-42(a6)";
#define UnlockAmigaGuideBase(key) __UnlockAmigaGuideBase((key), AmigaGuideBase)

APTR __OpenAmigaGuideA(__reg("a0") struct NewAmigaGuide * nag, __reg("a1") struct TagItem * *,
                       __reg("a6") struct Library *)="\tjsr\t-54(a6)";
#define OpenAmigaGuideA(nag, *) __OpenAmigaGuideA((nag), (*), AmigaGuideBase)

L'auteur de vbcc a donc opté pour l'assembleur inline (ce qui n'est pas du C standard non plus). Personnellement, j'aime bien, mais chacun ses goûts.

Ici aussi, OpenAmigaGuide(), qui a un nombre variable d'arguments, n'est pas présente. Mais cela ne veut pas dire qu'on ne peut pas l'utiliser... Il existe en effet, pour tous les compilateurs, la possibilité d'utiliser des bibliothèques stub.

Les bibliothèques stub

Les bibliothèques stub sont des bibliothèques statiques (ou de liens) remplissant la même tâche que les fichiers pragmas et inlines. Elles sont utilisables par tous les compilateurs, mais chacun a bien sûr un format de bibliothèques différent (sinon, ça ne serait pas drôle).

Elles contiennent des "stubs" (bouchons), qui sont des fonctions C standard se chargeant de prendre les paramètres sur la pile pour les placer dans les registres, avant d'appeler la fonction correspondante de la bibliothèque.

Vous avez généralement le choix entre utiliser des inlines ou pragmas et utiliser une bibliothèque stub.

Une chose à noter est que pour les compilateurs dont les inlines/pragmas ne gèrent pas les fonctions à nombre d'arguments variable, vous devez utiliser une bibliothèque stub pour pouvoir appeler ces fonctions. Vous n'aurez normalement pas de souci avec les fonctions du système d'exploitation, car des bouchons devraient être inclus dans l'amiga.lib de votre compilateur, et donc liées à vos exécutables par défaut.

Pour utiliser une bibliothèque stub, procédez de la même façon que pour n'importe quelle bibliothèque de liens : en rajoutant "-lnom_de_la_lib" à la ligne de commande, ou en rentrant son nom à l'endroit adéquat si vous utilisez une interface graphique comme celle de StormC.

Attention, si le fichier s'appelle par exemple "socket.lib", il faut taper "-lsocket" sans le ".lib". GCC ainsi que vbcc PowerUP/MorphOS utilisent la notation "libsocket.a", mais ça ne change rien : il faut également taper "-lsocket".

Le répertoire "proto"

Dans ce répertoire, des fichiers comme "proto/amigaguide.h" qui incluent eux-mêmes :
  • Le fichier de prototypes du répertoire "clib".
  • Le fichier d'inlines ou de pragmas qui correspond au compilateur utilisé (ou rien si une bibliothèque stub doit être utilisée).
Vous ne devriez jamais inclure directement les pragmas ou inlines dans vos sources. De même, à l'exception de certains fichiers (comme clib/alib_protos.h qui contient les prototypes de l'amiga.lib), vous ne devriez jamais y inclure directement les fichiers clib.

Utilisez les fichiers du répertoire "proto" au lieu d'inclure explicitement les fichiers clib/pragmas/inlines de votre compilateur ; de cette façon, vos sources seront compilables avec tous les compilateurs sans aucune modification (et en plus, ça fait deux fois moins de choses à taper).

Par exemple, ne tapez pas ça :

#include <clib/amigaguide_protos.h>

-> c'est mal

#include <inline/amigaguide_protos.h>

-> c'est maaal

Mais au contraire tapez ça :

#include <proto/amigaguide.h>

Notez que les protos fournis dans les fichiers d'en-tête officiels d'AmigaOS (dans le NDK 3.9 et sur les CD Developer) n'incluent pas les clib, pour une raison qui m'échappe. Mais peu importe : ils ne sont jamais utilisés ; votre compilateur est normalement livré avec ses propres protos pour toutes les bibliothèques du système d'exploitation.

L'amiga.lib

L'amiga.lib est une bibliothèque de liens à double emploi. Elle contient d'une part des fonctions utilitaires comme DoMethod(), HookEntry() ou RangeRand() et, d'autre part, des bouchons pour toutes les fonctions du système d'exploitation, voire celles de bibliothèques externes selon votre compilateur.

C'est pourquoi, même s'il vous manque le pragma ou l'inline pour une fonction donnée du système d'exploitation, vous pourrez quand même l'utiliser grâce au bouchon présent dans l'amiga.lib (en général, cette bibliothèque est liée par défaut dans tout exécutable par votre compilateur).

Pour utiliser des fonctions de l'amiga.lib dans un programme, vous devez inclure son clib :

#include 

Ceci n'est pas nécessaire si vous n'avez besoin que des bouchons et pas des fonctions utilitaires.

Les FD, SFD et fd2pragma

Maintenant que vous avez vu la composition de tous ces fichiers, vous devez vous dire que ça va prendre du temps pour tous les taper à la main. Heureusement, il existe des outils pour les générer automatiquement. Ces outils utilisent généralement les fichiers FD comme point de départ. Les fichiers SFD sont apparus au public assez récemment dans le NDK 3.9 et permettent eux-mêmes de générer des FD, clib et autres fichiers.

Voici un petit bout d'un fichier FD :

LockAmigaGuideBase(handle)(a0)
UnlockAmigaGuideBase(key)(d0)
##private
amigaguidePrivate2()()
##public
OpenAmigaGuideA(nag,*)(a0/a1)

Ce fichier contient les informations nécessaires pour que le compilateur sache comment appeler une fonction : son adresse par rapport à la base de la bibliothèque et les registres utilisés.

Il existe notamment "fd2inline" pour générer des inlines pour GCC à partir des FD, mais le plus puissant (et le seul que j'utilise) s'appelle "fd2pragma" et est disponible sur Aminet. Contrairement à ce que son nom pourrait laisser croire, il permet non seulement de générer des pragmas à partir de FD, mais également le contraire, ainsi que des inlines, bibliothèques stub, etc., et ce pour tous les compilateurs et systèmes (AmigaOS 68k, WarpOS, PowerUP, MorphOS - désolé, il manque Amithlon).

Voici quelques exemples :

Pour générer un fichier "proto" qui marche avec tous les compilateurs :

fd2pragma FD:intuition_lib.fd SPECIAL 35 TO INCLUDE:proto/

(notez que fd2pragma suppose que les pragmas se trouvent dans le répertoire "pragma" (sans "s") lorsqu'il crée les protos).

Pour générer un fichier de pragmas qui marche avec tous les compilateurs :

fd2pragma FD:intuition_lib.fd TO INCLUDE:pragma/

Pour générer une bibliothèque stub WarpOS pour vbcc :

fd2pragma FD:intuition_lib.fd CLIB INCLUDE:clib/intuition_protos.h SPECIAL 73 TO VLIBWOS:

Ces exemples utilisent l'intuition.library, mais vous n'aurez normalement jamais à générer des fichiers pour une bibliothèque du système d'exploitation : tous les compilateurs sont livrés avec les fichiers nécessaires. En revanche, vous aurez peut-être besoin de créer des fichiers pour utiliser certaines bibliothèques disponibles sur Aminet ou ailleurs.

Je ne peux pas mentionner toutes les possibilités de fd2pragma ici, et vous laisse donc consulter sa documentation AmigaGuide. La partie "Beginner" contient des exemples pour générer des inlines/pragmas pour tous les compilateurs, et la partie "Useful example calls" en présente d'autres. Regardez la section "The important options" pour la liste des "Special" pour chaque compilateur. C'est en changeant cette valeur que vous choisirez quel fichier fd2pragma va générer.

Je vous conseille de toute façon de lire la documentation consciencieusement (attention, certaines parties sont plus à jour que d'autres).

La fin du début

Ainsi se termine cet article. J'espère que les exemples de fichiers inlines et pragmas ne vous ont pas trop rebuté ; ils ne sont là que pour votre culture personnelle ;-). L'intérêt d'une bonne installation des fichiers d'en-tête est justement de pouvoir faire abstraction des différents mécanismes mis en oeuvre par les compilateurs, et de se concentrer sur l'important : l'utilisation des bibliothèques et la programmation !


[Retour en haut] / [Retour aux articles]