|
|||||||||||||||||||||||||||||||||||||||||||
|
Développer un logiciel d'envergure pour l'Amiga n'est pas toujours chose évidente. Des erreurs peuvent être commises sans même que le programmeur ne s'en rende compte. Ce petit guide devrait vous permettre de repérer les erreurs les plus fréquentes. Mais d'abord, quelques mots sur la manière de bien tester vos programmes. Il existe dans le domaine public et dans le commerce plusieurs logiciels spécialisés, comme MemWatch, WatchMem, GOMF ou TaskX. Utilisez-les avec circonspection. Testez vos programmes sur plusieurs configurations différentes (mémoire, processeur, extensions...). N'oubliez pas, au cas où votre logiciel est appelé à être diffusé internationalement, que les claviers changent de pays en pays. Ceux qui utilisent le drapeau RAWKEY auront avantage à utiliser la fonction RawKeyConvert() du console.device. Aux États-Unis, le système NTSC ne laisse "que" 200 lignes de résolution verticale, pensez-y ! Audio - friture sur la ligne ! Les données sonores doivent se trouver en mémoire Chip ! Vérifiez les directives de compilation de votre compilateur, ou bien allouez dynamiquement de la mémoire Chip et recopiez-y vos données. Messages d'erreur du CLI Ils sont causés par un appel à exit() avec un paramètre incorrect. Les programmeurs en assembleur doivent placer une valeur valide dans le registre d0. Les codes de retour possibles sont définis dans libraries/dos.h et i. D'autres valeurs (-1 par exemple) provoquent des messages erronés, comme "not an objet module". La fenêtre CLI refuse de se refermer Une fenêtre CLI ne se fermera pas, tant qu'un programme détiendra un "Lock" (verrou) sur son canal d'entrées-sorties ("*"). Si votre programme est exécuté par "RUN >NIL:", la fenêtre pourra être fermée, à moins que votre code n'ouvre explicitement "*". Plantage et corruption de la mémoire Les erreurs d'adresse, de bus, les instructions illégales, sont généralement causées par l'utilisation d'un pointeur non ou mal initialisé, ou déjà libéré (FreeMem, Close...). Il est également possible que vous écrasiez par erreur une zone de données, ou que vous incrémentiez un pointeur utilisé plus tard pour FreeMem ou Close. Testez explicitement toutes les valeurs renvoyées par les fonctions du système. Vérifiez que vous ne provoquiez pas de dépassement de capacité de la pile dans vos fonctions récursives. Un plantage peut également survenir en passant de mauvais arguments à une fonction du système, par exemple SetAPen(3) ou SetAPen(window.3) au lieu de SetAPen(rastport.3). Utilisez les prototypes de votre compilateur ! Plantage après exécution Si un plantage ne survient que lorsque votre programme est lancé depuis le Workbench, c'est certainement parce que vous appelez UnLock() avec l'un des "Locks" du WBStartupMessage. Ou peut-être effectuez-vous une sortie (avec printf() ou autre) sans qu'une fenêtre n'ait été ouverte pas votre Startup-Code). Si le plantage survient aussi bien depuis le Workbench que depuis le CLI, vous libérez sans doute deux fois une zone de mémoire ou bien quelque chose que vous n'aviez pas obtenu. Si votre programme utilise un périphérique logique quelconque, assurez-vous avec CheckIO(), WaitIO() et AbortIO() qu'aucune requête n'est lancée quand vous quittez. Plantage avec d'autres tâches ou les interruptions Si une partie de votre code fonctionne comme sous-tâche (avec une pile différente) ou avec la pile système, vous devez invalider l'option de vérification de la pile de votre compilateur. Si des routines de votre programme doivent être appelées par le système, assurez-vous de choisir le modèle de données et de code large avant de compiler. Plantage avec les fenêtres Faites attention à ne pas fermer votre fenêtre dans une boucle avec GetMsg() : le prochain GetMsg() utiliserait un pointeur sur un MsgPort invalide. Utilisez ModifyIDCMP(NULL) avec prudence, surtout si vous partagez un même UserPort entre plusieurs fenêtres (ModifyIDCMP(NULL) libère le MsgPort associé à la fenêtre). Enfin, soyez sûr de bien enlever les menus de votre fenêtre avec ClearMenuStrip() avant de la fermer. Plantage (seulement sur 68020/68030) Ceci peut être dû à l'utilisation des 8 bits de poids fort des adresses, à du code auto-modifié, à l'utilisation de l'instruction MOVE TO SR, privilégiée sur ces processeurs (utilisez plutôt GetCC() d'exec.library), à l'utilisation d'une pile erronée lors d'interruptions... Plantage (seulement avec anciennes ROM) Ceci survient principalement lors de l'utilisation de fonctions de bibliothèques, avec un numéro de version plus haut que celui dont dispose la machine. Vérifiez bien les résultats d'OpenLibrary(). Il est également interdit de sauter directement à des adresses en ROM ! Plantage sur les machines sans mémoire Fast Un appel à AllocMem() avec le drapeau MEMF_FAST positionné échouera sur des machines ne disposant que de mémoire Chip. Si vous n'avez pas besoin de mémoire Chip, utilisez MEMF_PUBLIC : si de la mémoire Fast est disponible. Le système vous en attribuera en priorité. Plantage sur les machines avec mémoire Fast Les données et les tampons mémoire destinés aux circuits spécialisés doivent se trouver en mémoire Chip : ceci est valable pour les plans de bits, les échantillons sonores, le tampon mémoire pour le trackdisk, les sprites, les BOB, les images, les gadgets, etc. Utilisez les drapeaux de votre compilateur ou de votre éditeur de liens pour être sûr de leur chargement en mémoire Chip, ou bien allouez-en dynamiquement et recopiez-y (ou chargez-y) vos données. Plantage sur les machines avec l'ECS Ceci est dû à un accès à la zone des registres matériels, à une adresse non définie ou à l'utilisation de bits non définis dans l'ancien jeu de composants (mettez les bits indéfinis à 0 à l'écriture et masquez-les par AND à la lecture). Une icône de disquette ne disparaît pas Ce problème survient lorsqu'un ou plusieurs "Locks" sur des fichiers de la disquette ne sont pas libérés, ce qui se traduit également pas une perte de deux octets de mémoire par "Lock". Perte de mémoire D'abord, vérifiez que votre programme n'occasionne pas une "perte de mémoire" : notez le montant de mémoire disponible (affiché dans la barre d titre de l'écran du Workbench), exécutez votre programme, testez toutes ses fonctions puis quittez. Si la mémoire disponible est différente de ce qu'elle était, vous avez certainement oublié de désallouer ou fermer quelque chose. Si vous avez chargé le Workbench avec l'option "-debug" de la commande LoadWB, choisissez l'option "flushlibs" du menu invisible, à droite du menu "Special" (cette fonction tente de fermer toutes les bibliothèques, polices et tous les périphériques logiques, etc.). Si la mémoire disponible après ça est toujours différente, vérifiez bien votre source, surtout sur les points cités ci-dessous. Sinon vérifiez quelle bibliothèque, police ou quel périphérique logique vous avez oublié de fermer. Vérifiez que tous les appels à des fonctions du type open, alloc, get, ou lock sont bien suivis du close, free, delete ou unlock correspondant. Si vous utilisez ScrollRaster() sur une fenêtre de type SUPERBITMAP sans fournir de TmpRas, la fonction en allouera un pour vous, mais ne le libérera pas. Perte de mémoire (CLI seulement) Attention au Ctrl-C ! Si votre compilateur possède une fonction de traitement automatique du Ctrl-C, votre code de sortie ne sera pas appelé. Inhibez le Ctrl-C de votre compilateur et gérez-le vous-même. Perte de mémoire (Workbench seulement) Typiquement, ceci est dû à l'échec du Workbench à libérer un programme avec UnLoadSeg(). Utilisez bien exit(n) et non Exit(n), qui ignorerait la fin de votre Startup-Code et donc le ReplyMsg() qui indique au Workbench de libérer votre programme. De plus, l'architecture multitâche de l'Amiga oblige à utiliser Forbid() avant ce ReplyMsg(). Problèmes avec les menus Un plantage dû à un menu est la plupart du temps causé par une mauvaise gestion des messages dont le code est MENUNULL. Assurez-vous également de bien gérer la sélection multiple grâce au champ NextSelect. De plus, ne libérez pas la mémoire d'un MenuItem allouée dynamiquement, tant que le menu est attaché à la fenêtre. Ralentissement du système Ceci est dû à des boucles infinies (utilisez Wait() partout où c'est possible plutôt qu'une boucle sur GetMsg(), notamment pour le port IDCMP d'une fenêtre), à une priorité trop élevée de votre programme ou d'une sous-tâche à des Forbid() ou Disable() de trop longue durée... Données du trackdisk.device non transférées Les données de la disquette sont lues par le DMA et décodées par le Blitter. De fait, elles doivent être logées en mémoire Chip.
|