FxLibC: La bibliothèque standard C pour les calculatrices
Posté le 22/10/2020 17:39
Salut à toi jeune développeur !
FxLibC est une bibliothèque standard C basé sur l'interface que propose GLIBC, la "vrai" bibliothèque standard.
Alors, je sais, ce n'est pas la première fois qu'une telle initiative est prise mais j'ai de bonnes raisons de le faire :
L'OS de Casio n'est pas adapté pour oser faire un portage de la Glibc original car trop de mécanismes sont manquants et la plupart des abstractions fournies par Casio sont, au mieux, bancales. C'est pourquoi j'ai décidé de refaire une librairie de 0 qui permettra de tirer toute la puissance des OS et permettra d'avoir une interface commune pour les OS Casio monochrome/couleur et des noyaux custom comme Vhex.
Pour l'instant, c'est juste un "proof of concept" où la lib peut être compilée, installée et désinstallée en fonction de l'OS et du format* mais en matière de fonctionnalité, il n'y pas grand-chose d'incroyable, seules quelques fonctions basiques y sont implémenté. Je continuerai de l'améliorer au fur et à mesure de mes expérimentations / projets qui, je l'espère, arriverons bientôt.
Pour pas oublier, voici le lien vers le dépôt Git :
> Lien vers le dépôt Gitea, Vhex-Kernel-Core/fxlibc <
Mes prévisions pour la bibliothèque :
Changement de la gestion des versions
C'est une des choses que je n'ai jamais vraiment regardées mais je vois de plus en plus d'intérêt à avoir une gestion des versions correctes si on veut avoir quelque chose de maintenable dans le temps. Actuellement, la version est obtenable uniquement avec
make version et elle est mise a la main dans le makefile. J'avais pensé a une gestion automatique des versions basées sur le git: je cherche le dernier commit avec un tag (tag qui contiendra le major.minor (ex: 2.6)) et le nombre de commit après le tag indique la version des patchs. Mais je ne sais pas s’il y a moyen plus simple et plus "automatisant"(?)
Abstraction de Bfile (l'interface mise en place par Casio pour gérer les fichiers)
Comme je vais devoir implémenter les "appels système"
open(), lseek(), close(), etc ; Je me suis dit que j'aurais tout intérêt à faire une vraie abstraction de Bfile car elle apporte trop de contrainte (par exemple, on doit spécifier la taille du fichier qu'on veut créer, il y a quelque subtilité avec l'écriture, c'est lent, ...) Donc j'hésite entre :
1) faire juste des wrappers autour des appels système Bfile: le plus simple mais on aura la plupart des contraintes imposées par le Bfile.
2) faire une plus grosse abstraction sur le Bfile: mais ça implique de "monter" le système de fichier au début du programme, potentiellement plus rapide mais on n'échappera pas aux limitations de création et d'écriture dans un fichier).
3) embarquer un système de fichiers custom en RAM et enregistré les informations uniquement quand l'addins retourne au menu : mais ça pose beaucoup de problèmes organisationnel et architectural car je trouve qu'un FS n'a pas sa place dans une bibliothèque standard. Est-ce qu'il faudrait faire un projet à part ? Si oui alors : comment on relit les deux projets ensemble sans que ce sois infernal pour les développeurs ? Sur quel type de format on part ? Comment l'installer proprement en RAM et où ? Comment et quand installer le FS ? Comment on y accède si le système est isolé de la librairie ?
Personnellement je suis plus pour la 3ᵉ options car elle permettra d'avoir un vrai abstraction sur le FS de Casio et on pourrait implémenter beaucoup plus de fonctions pour la manipulation et la sécurité des fichiers (en plus de gagner en performance(?)) mais ça pose beaucoup de problèmes. À méditer.
Abstraction de la gestion de la mémoire
Est-ce qu'on continue d'utiliser des wrappers autour des appels système pour la gestion de la mémoire (malloc, calloc, free, ...) ? Ou est-ce qu'il faudrait mieux refaire cette partie dans la lib ? Actuellement, j'utilise l'ABI de Casio et Vhex pour la gestion de la mémoire car du côté de Casio c'est flou et du côté de Vhex je n'ai pas le choix car l'entièreté de l'environnement (processus, kernel, FS, ...) est en RAM et je n'ai pas le MMU à disposition. Donc est-ce que ça vaut vraiment le coup d'implementer un tas custom, sachant qu'on aura surement rien de commun entre les différents OS ?
Écriture de la documentation
C'est une des parties cruciales si on veut avoir quelque chose d'utilisable et d'améliorable, seulement je ne sais encore sur quel médium faire la documentation : sur le wiki, faire un topic, générer une documentation HTML / PDF ? D'ailleurs, ça me fait penser, es-ce que la v5 de planet-casio améliore cette partie ? J'entends par là, est-ce qu'il y aura un moyen de synchroniser la bible, le wiki du Gitea et le topic en même temps ? Ça pourrait être extrêmement intéressant de centraliser les projets ainsi que leurs documentations / topics.
Support des librairies dynamique pour Vhex
C'est une des fonctionnalités cruciale pour Vhex car la version 2.0 repose entièrement sur le mécanisme de pouvoir relocaliser / charger des fonctions à la volée. Mais malheureusement, GCC semble ignorer les flags pour la génération des bibliothèques (pourtant on peut créer des exécutables en PIE !). Bref, j'avais envoyé
un mail à GCC pour avoir des informations mais je n'ai toujours pas eu de réponse.
Optimisation des fonctions
Hé oui, l'intérêt d'avoir une lib complètement indépendante des OS et communautaire, c'est qu'on va pouvoir optimiser la plupart des fonctions basique ! Attention toute fois, s’il vous prend l'envie de participer, évitez d'écrire du code utilisant des modules hardware pouvant générer des interruptions (comme le DMA et le SPU) a moins d'être absolument certain que le système d'exploitation est capable de les gérer. Mais n'oubliez pas que le but de la lib est d'être la plus indépendante possible vis-a-vis des OS pour faciliter son portage.
Actuellement, rien n'est optimisé et rien n'est garantie de fonctionner comme il est décrit dans la norme POSIX ou dans la documentation de la glibc mais à l'avenir, j'espère pouvoir les respecter le plus fidèlement possible.
D'ailleurs, si vous voulez participer au projet n'hésitez pas ! J'ai besoin de pas mal de retour pour que la bibliothèque puisse être un jour utilisable par d'autre personnes que moi
Citer : Posté le 23/10/2020 20:06 | #
Le projet de rêve ! Pour clarifier, mon but est d'ajouter une target gint et de contribuer aux fonctions génériques.
Wow la glibc, la "vraie", carrément. On en a fusillé pour moins que ça. x) Plus sérieusement c'est très très gros, je te conseille pas de viser l'API de la glibc (y'a plein d'alternatives plus tranquiles).
Le README ne précise pas vraiment comment choisir l'ABI, je suggère de l'ajouter vu que tu listes les ABIs (?). Note aussi que tu as un "You can absolutely not build gint with your system compiler!" dans le README, tu as oublié de remplacer le "gint".
Niveau configuration, je suppose qu'il faudra compter quelques options ? Notamment comme tu le mentionnes il y a moyen de faire memcpy() avec des techniques spécifiques au noyau. Notamment entre la XRAM et la YRAM le plus rapide est de loin d'utiliser le DSP, mais ce n'est possible que s'il est allumé. On peut faire une détection au runtime (le plus fiable) ou ajouter un flag de compilation ? Qu'en penses-tu ?
Pour ce qui est de BFile, ma préférence serait une variante de la version 3 où on fait un cache disque en RAM sans réimplémenter un système de fichiers complet.
Pour le tas, dans tous les cas on ne peut pas allouer dans la zone gérée par l'OS avec autre chose que le malloc/free de l'OS donc on sera bien obligés de les garder. Ce qui ne nous empêche pas d'avoir une version custom s'il y a des zones en plus.
Si c'est une libc, il ne devrait pas y avoir besoin de doc pour les utilisateurs : c'est le standard et rien de plus. La doc "interne" peut déjà être dans le code en premier lieu.
Citer : Posté le 23/10/2020 20:46 | #
ca à l'air super pour dev
Citer : Posté le 23/10/2020 22:27 | #
Je sais éperdument que ce n'est pas possible de faire un portage ou une copie de la glibc, disons juste que je vais essayer d'implémenter une libc alakon en respectant le plus possible l'interface de la glibc. (C'est vrai que ça fait très kikoolol de dire "je vais refaire la GLIBC, la vrai !" mais bon, je suis mauvais en explication xD)
Tu es trop inspirant c'est pour ça, je vais corriger ça quand j'aurais le temps <3
Actuellement, on peut seulement choisir l'ABI qu'on veut (a savoir --support-casio-abi-fx9860g, --support-casio-abi-fxcg50 et --support-vhex), le but étant de pouvoir implémenter les fonctions les plus optimisées possibles pour tel ou tel système d'exploitation. Je ne pense pas mettre de configuration pour activer tel ou tel feature (exemple le DSP) car ça casserait le principe. Mais si tu as mieux je suis preneur !
Bien, c'était déjà implémenté dans Vhex (en partie, il me manque l'écriture !), je pourrais porter ça rapidement (il faut vraiment que je trouve du temps décidément) !
C'est ce que je me disais. Pour les zones en plus tu penses auxquelles ? XRAM / YRAM (PRAM à la limite mais ce n'est pas dans le rôle que tu voulais pour lui dans gint(?)) ? Donc je suis pour laisser cette partie de côté le temps d'avoir un truc documenté et utilisable.
Merci mais pour l'instant ça reste très brouillon !
Citer : Posté le 23/10/2020 22:47 | #
Quel principe ? Parce que si on peut pas décider correctement si le DSP est accessible ou non, on laisse passer de la performance et pour moi c'est vraiment dommage. Dans le cas spécifique du DSP on peut toujours inspecter SR mais toutes les situations ne sont pas aussi faciles. Par exemple, le DMA c'est pas gagné.
Je ne dis pas qu'il faut avoir un paramètre de configure pour activer ou non le DSP, mais peut-être au moins une variable interne « DSP supporté par l'OS pour lequel on compile » avec un peu de logique de configure pour l'activer ou non selon chaque OS.
Et je cache pas que si tu veux utiliser le bon memcpy() aussi dans le noyau ça se complique beaucoup parce que les modules sont pas forcément allumés ni initialisés et donc les optis pas toujours correctes... j'ai toujours plus ou moins réussi à éviter ça dans gint mais c'est jamais garanti.
Si on veut partager du code là-dessus attends-toi à refactorer pas mal de choses sur l'allocation de la mémoire... ^^"
Tu peux laisser l'utilisateur le droit de créer des arènes où il veut. Et si tu veux la jouer glibc, tu es bien obligé. Soit dit en passant, le tas de l'OS ne fournit pas du tout les interfaces de la glibc donc tu passes à côté de mallinfo(3), malloc_hook(3), malloc_stats(3), malloc_trim(3) et j'en passe pas mal (une bonne dizaine d'après man -k malloc).
Premier aperçu de ce que ça donne la glibc, si jamais... x)
Ajouté le 02/12/2020 à 14:27 :
Aaaaaye → https://github.com/Paquity/vxLibc #GitHubNotifications
Citer : Posté le 07/05/2021 19:15 | #
Comme on en a parlé récemment, voilà une proposition pour s'organiser.
Il y a 4 types de code différents dont on a parlé jusque-là :
Et la grande question c'est : qu'est-ce qu'on mettrait bien dans la libc, comment, et pourquoi.
Pour la plupart de ces choses, il n'y a pas mille façons de l'implémenter. Le strtok() c'est direct. Le memcpy() hors DMA c'est direct. Le signal() c'est direct (un sous-dossier arch par cible). Le memcpy() par DMA c'est direct aussi, s'il y a une fonction du noyau pour le faire on l'appelle, sinon on ne l'utilise pas (presque comme un sous-dossier arch sauf qu'on change pas de fichier à la limite).
Le plus subtil c'est l'abstraction BFile. Mais quand on y réfléchit, cette abstraction ne peut pas directement donner fread(), fwrite(), etc ; parce que Vhex a un système de fichiers beaucoup plus grand que BFile avec des périphériques et des ioctl, et gint pour l'instant n'a rien mais ferait bien des choses en RAM. Il est nécessaire que fread(), fwrite() etc. utilisent les bonnes fonctions noyau (read(), write(), etc), et du coup l'abstraction BFile va plutôt servir à implémenter ces fonctions noyau dans les cas où les fichiers manipulés sont dans la mémoire de stockage ou la carte SD.
Du coup mon plan ce serait de faire un truc comme ça :
L'avantage c'est qu'on peut commencer à coder rapidement sur les parties indépendantes. Perso j'aurais besoin de la libc pure pour tenter de compiler libstdc++ et c'est plus simple pour moi s'il y a moins de dépendances envers les autres parties
Citer : Posté le 07/05/2021 21:46 | #
Je suis on ne peut plus d'accord avec la séparation des niveaux de code que tu viens d'énoncer, mais j'ai encore du mal à voir l'architecture du dépôt. Ton plan est globalement celui que j'avais en tête donc je suis partant
Pour ce qui est de l'abstraction en tant que telle, j'ai une bonne idée de comment on pourrait s'y prendre, mais je doute qu'on ait la même vision sur cette partie. On verra plus tard, ce n'est pas le plus urgent.
Sinon oui, la séparation est nécessaire, mais ça soulève beaucoup de question :
Est-ce qu'on propose des primitives monolithiques qui couvre la carte SD et la flash ?
Est-ce qu'on propose des primitives distinctes pour chaque mémoire de stockage ? (on se retrouvera à implémenter bfile si on part là-dessus)
À quel point on abstrait Bfile ?
D'ailleurs, ça me fait penser qu'il faut trouver un moyen de configurer la compilation pour permettre d'utiliser uniquement les syscalls pour être "natif a Casio" ou d'utiliser des primitives "custom" pour interagir avec la mémoire de stockage (basiquement en ce moment, j'essaie de re-implémenter des primitives pour Fugue, j'aimerais bien les proposer une fois stable, mais je ne veux pas les imposer).
Citer : Posté le 07/05/2021 22:09 | #
Oui ce n'est que l'idée générale, pour le dépôt tout n'est pas encore clair c'est sûr.
Je ne vois pas trop de raison de séparer dans l'abstraction BFile, puisque c'est les mêmes fonctions à appeler : faire les deux ensemble ne coûtera pas plus cher en quantité de code, donc oui perso je ferais les deux en même temps.
On peut aussi imaginer une autre lib à côté pour implémenter l'accès manuel sans BFile, si c'est bien ce que tu voulais dire. Ce serait le mieux pour tester probablement, parce que tant que ce que tu as découvert n'est pas codé et facile d'accès on ne risque pas trop de le tester, hors c'est avec du test massif que la stabilité sera acquise.
On peut simplement se mettre d'accord sur une interface raisonnable qui marche pour Vhex et qui marche pour gint. À mon avis ça donnerait open/read/write/close normalement sauf que open a besoin de la taille et que write ne marche pas pareil dans les modèles où la ROM ne peut pas changer les 0 en 1. J'imagine abstraire les chemins de fichiers avec de l'UTF-8 (enfin) et les fonctions de recherche. Mais par exemple je n'imagine pas intégrer le fait d'écrire les fichiers dans la RAM et de flush vers BFile plus tard, parce que la bonne façon de le faire dépend trop de l'OS ciblé à mon avis.
Citer : Posté le 07/05/2021 23:48 | #
C'est parfait, j'avais besoin d'une libc
Citer : Posté le 07/05/2021 23:50 | #
Il y a un port de newlib par Memallox, mais je ne sais jamais trop à quel point il marche. En principe il marche, mais je me souviens de quelques crashs.
Citer : Posté le 08/05/2021 19:47 | # | Fichier joint
Bon, je crois que j'ai foiré un truc
Citer : Posté le 08/05/2021 19:51 | #
Ouais c'est chiant ça. Tu peux faire LANG=C ../configure etc.
En gros ce problème c'est parce que le script essaie de détecter le chemin d'installation de GCC à partir de la sortie de sh-elf-gcc --print-search-dirs. Le chemin est prefixé de "install:" et du coup le script tente de supprimer ce préfixe. Cependant, ton OS est en français, donc c'est « installés: » à la place, et du coup ça ne marche pas. Mettre LANG=C force les messages en anglais.
Récemment j'ai trouvé que sh-elf-gcc --print-file-name=. donne le même dossier sans le problème du préfixe, donc on pourra modifier ça.
Citer : Posté le 15/05/2021 20:29 | #
Sinon, comment j'utilise la libc sur un projet gint (j'utilise makefile pour info)
Citer : Posté le 15/05/2021 20:43 | #
Pour l'instant pas parce qu'il n'y a rien de codé ! On s'est vu avec Yatis Dimanche dernier pour choisir le chemin, et j'ai codé une appli de test, et là j'ai quelques commits avec des bases, mais pour l'instant c'est superficiel. Il faudra un peu de patience !
Citer : Posté le 26/08/2021 11:28 | #
j'arrive pas a installer! gintctl ne trouve pas le -lc
Citer : Posté le 26/08/2021 11:32 | #
C'est étonnant parce que Fxlibc soit être installé pour que gint compile. Comme tu as réussi à installer gint, ça devrait être bon (?)
Je suppose que tu l'as installé, genre à peu près comme ça ?
Citer : Posté le 26/08/2021 11:59 | #
oui mais ça donne :
/home/pierre/opt/sh-elf-2.32-9.2.0/lib/gcc/sh3eb-elf/9.2.0/../../../../sh3eb-elf/bin/ld: cannot find -lc
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/gintctl.dir/build.make:897 : gintctl] Erreur 1
make[1]: *** [CMakeFiles/Makefile2:95 : CMakeFiles/gintctl.dir/all] Erreur 2
make: *** [Makefile:103 : all] Erreur 2
l'installation donne libc.a mais pas lc.a ou liblc.a
Citer : Posté le 26/08/2021 13:08 | #
libc.a est le bon nom de fichier, dans -lc le -l c'est l'option pour dire qu'on veut utiliser une bibliothèque et c en est le nom. Le fichier correspondant est donc libc.a.
Tu peux voir tout de suite si le bon fichier existe :
S'il n'existe pas alors la lib n'est pas correctement installée ; s'il existe alors il y a un problème plus bizarre avec gintctl ou le fxSDK.
Merci de ta patience dans tous les cas
Citer : Posté le 26/08/2021 13:48 | #
ah, la lib est dans dans un sous dossier "lib" de lib, je vais le sortir de la
EDIT: ca marche
Citer : Posté le 26/08/2021 13:51 | #
Va comprendre pourquoi, normalement quand tu compiles pour gint elle doit s'installer tout seule hors de lib, c'est programmé comme ça.
Je trouverai un moyen de clarifier les instructions pour que ce soit plus simple, merci des retours.
Ajouté le 23/11/2021 à 18:52 :
Okay, quelques bonnes nouvelles. À la demande de KikooDX j'ai commencé à bosser sur une interface standard pour BFile (ie. les fonctions standard genre fopen() etc. pour la mémoire de stockage).
Historiquement c'était soit la merde soit carrément impossible parce que le système de fichiers n'était pas assez puissant. Mais avec la Graph 35+E II et la Graph 90+E (en fait la Prizm je pense, mais je peux pas vérifier) il a changé vers quelque de chose de beaucoup plus lent mais aussi beaucoup plus fonctionnel.
Ça veut dire qu'on va enfin pouvoir faire tranquillement ce qu'on veut, par exemple ouvrir un fichier en écriture sans spécifier sa taille, écrire un nombre impair d'octets sans réfléchir, et probablement plus.
Je suis déjà en train de coder l'API Unix (open(), read(), write(), etc) et ça se passe pas trop mal (sur la Graph 90+E pour l'instant).
Perso, je préfère un fs lent mais fonctionnel. J'achète ce changement et une fois dans la libc je pense que je me servirai beaucoup plus du système de fichiers !
Citer : Posté le 23/11/2021 19:52 | #
Je suis déjà en train de coder l'API Unix (open(), read(), write(), etc) et ça se passe pas trop mal (sur la Graph 90+E pour l'instant).
Perso, je préfère un fs lent mais fonctionnel. J'achète ce changement et une fois dans la libc je pense que je me servirai beaucoup plus du système de fichiers !
J'achète !!! Dis nous quand tu as un truc qui te parait suffisamment fonctionnel pour faire un "push" de version.
Je suis preneur aussi d'un fprintf/fscanf perso ;-)
Je sais j'abuse :-)