Les membres ayant 30 points peuvent parler sur les canaux annonces, projets et hs du chat.
La shoutbox n'est pas chargée par défaut pour des raisons de performances. Cliquez pour charger.

Forum Casio - Vos tutoriels et astuces


Index du Forum » Vos tutoriels et astuces » Faites des libs statiques, bon sang !
Cakeisalie5 En ligne Ancien administrateur Points: 1896 Défis: 11 Message

Faites des libs statiques, bon sang !

Posté le 23/05/2016 10:49


Ce tutoriel est spécifique au développement sous Linux.
Sérieusement les gars ? Windows comme plateforme de développement ?!


La majorité des gens ici (puisque pas mal développent encore sous Windows) qui développent des "librairies" C n'en développent en réalité pas, je pensais en faire un topic, et le voici.


Compilation

La première chose que vous devriez avoir appris sur les langages de programmation, c'est la distinction entre les langages compilés et les langages interprétés... mais je reviens dessus pour m'assurer que c'est bien clair.

Imaginez que vous avez un livre en japonais et que vous ne comprenez que le français. Pour le traduire, vous avez plusieurs possibilités :
- séparer l'étape de traduction (compilation) et l'étape de lecture (exécution), ainsi une fois traduit le livre peut être lu autant de fois qu'il le faut et rapidement, en oubliant qu'il fallait qu'il soit traduit ;
- traduire à la volée, ce qui implique que vous devez traduire le livre en français à chaque fois que vous le lisez (à l'aide d'un traducteur, un interpréteur).

Pour le code, c'est la même chose : l'ordinateur ne lit que du code machine (le français), et vous codez dans un langage autre (le japonais peut ici représenter le C, le C++, ...). Donc la compilation, c'est l'art de transformer du texte organisé en du code machine.


Fichiers objet

À savoir, tout ce que je vais dire à partir de là concerne le format ELF. Ce format, que vous utilisez sans doute déjà sans le savoir, est un format qui peut se décliner en plusieurs types de fichiers : des fichiers objets (repositionnables), des exécutables, et d'autres choses hors-sujet.

Le format ELF, c'est plus ou moins des symboles (avec une table de correspondance symboles/adresse dans le fichier) et des références à des symboles externes (qui ne sont pas dans le fichier), du code machine et des données brutes, organisés dans des sections.

Prenons du code C comme exemple :

// Prototypes
int fonction2();

// Globales
int globale5 = 12346;

int fonction1(void)
{
    // les variables non-statiques ne génèrent pas de symbole
    int variable8 = 44;

    return (fonction2() + globale5 + variable8);
}


Ici, le fichier objet (une fois que GCC sera passé) contiendra deux symboles : _globale5 et _fonction1, et une référence à un symbole : _fonction2 (puisque celle-ci est utilisée dans fonction1). (oui, il faut savoir que le compilateur C ajoute un underscore devant tous les noms de fonctions/globales/variables statiques).

Une question qui peut vous venir à l'esprit, c'est "mais du coup, les globales et les fonctions donnent la même chose dans le fichier objet, comment on sait que ce sont des globales et des constantes ?". Cette question est hors de la portée de ce tutoriel, mais elle est intéressante, et pour répondre à celle-ci, vous devrez comprendre au moins un assembleur (du coup, si vous êtes là, j'imagine que ce sera davantage l'assembleur SuperH).


Link

Le linker, c'est le logiciel qui va prendre des fichiers objets et des libs statiques (on va en parler après) et qui va mélanger tout ça ensemble pour en faire un exécutable.

Si vous faites un exécutable avec simplement le fichier objet présent ci-dessus, il va vous produire une erreur du genre "Le symbole _fonction2 requis n'a pas été trouvé", il faut donc lui fournir un autre fichier objet avec le symbole _fonction2 dedans.

Par ailleurs, une fois que l'exécutable est créé, on n'a plus besoin de la table des symboles ou de la table des sections. Mais sachez que le fichier en .elf que le tutoriel de Lephenixnoir vous fait générer comporte encore cette table des symboles et des sections, rien ne vous empêche d'aller voir pour vérifier avec sh3eb-elf-nm.


Bibliothèques statiques

(oui, on dit une bibliothèque, puisqu'on emprunte des objets dans des bibliothèques (et non une librairie), ou une "lib", pour faire référence au terme anglais)

Une bibliothèque statique est tout bêtement une archive (un fichier avec plein de fichiers dedans, comme les fichiers ZIP ou TAR) de fichiers objet.

On pourrait dire "oui mais du coup, au lieu de linker la lib, autant prendre ses fichiers objet et linker avec, non ?", et non, parce que la grande particularité des libs statiques, c'est que les fichiers objets qu'elle contient sont facultatifs.

Reprenons le link. Lors de l'opération de link, tout ce qui est dans les fichiers objets que vous lui passerez directement sera mis dans l'exécutable. Seulement, il va manquer pas mal de symboles, comme au hasard, _memcpy ou _ML_vram_address -- eh bien, pour trouver ces symboles manquants, le linker va parcourir tous les fichiers objet présents dans les libs statiques linkées et prendre ceux où se trouvent les symboles qu'il manque à l'exécutable.

On peut donc voir les libs statiques comme des collections de symboles, donc des collections de fonctions (et éventuellement de constantes et autres données brutes) qui ne seront peut-être pas toutes ajoutées à l'exécutable d'un projet les utilisant.


Comment créer une lib statique ?

Faire une lib statique, ce n'est pas sorcier, il suffit de :
- compiler les fichiers source de la lib en fichiers objet ;
- créer une archive avec tous les fichiers objet ;
- éventuellement, créer un index des fichiers objet présents dans l'archive et de leurs symboles pour faciliter le job du linker.

Attention cependant : n'oubliez pas que le linker va inclure non pas des fonctions, mais des fichiers objet. Si vous mettez toutes les fonctions de la lib dans un fichier source et que, du coup, vous ne faites qu'un seul fichier objet, ce fichier objet sera inclus dans l'exécutable finale dès que l'un des symboles présents dedans sera requis. Divisez bien vos fonctions en fichiers, l'idéal étant une fonction par fichier, mais il y a des cas particuliers : imaginons qu'une fonction soit appelée par une seule autre fonction, et qu'elle ne soit pas prévue pour être appelée par l'utilisateur, alors il faut la mettre dans le fichier source de cette autre fonction et même en faire une fonction statique (disponible uniquement depuis le fichier).

Par exemple, pour créer la libmonochrome, son Makefile va faire :

sh3eb-elf-gcc -c -o obj/ML_vram_address.o src/ML_vram_address.c -I ./include -Wall -Wextra
sh3eb-elf-gcc -c -o obj/ML_clear_vram.o src/ML_clear_vram.c -I ./include -Wall -Wextra
...
sh3eb-elf-ar rc libmonochrome.a ./obj/ML_vram_address.o ./obj/ML_clear_vram.o ...
sh3eb-elf-ranlib libmonochrome.a



Gérer un projet de lib statique

Faire un simple projet pour créer la lib, c'est bien, mais penser à l'utilisateur, c'est mieux. Un projet de lib statique propose généralement trois étapes :
- la configuration : on donne (ou laisse par défaut) les dossiers d'installation des fichiers header, des fichiers lib, ...
- la création : créer la lib (avec les commandes données ci-dessus, par exemple) ;
- l'installation : installer les fichiers prêts à l'emploi sur la machine.

Avec la libmonochrome par exemple, pour créer la lib puis l'installer, on réalise trois commandes :
./configure --prefix=~/opt/sh3eb-elf
make
make install


Je vous conseille vraiment de garder ça aussi simple que ça pour l'utilisateur qui va se servir de votre lib derrière.


Libs déjà créées/portées

- libfx (1.0) : lib du SDK, originale par CASIO
- libinput (2.0, topic dédié) : manipulation avancée du clavier, originale par Ninestars.
- libmonochrome (1.1, topic dédié) : originale par PierrotLL, y a-t-il encore besoin de la présenter ?
- librtc (0.3, topic dédié) : manipulation du temps à l'aide de la Real-Time Clock.

(peut-être qu'un jour, quelqu'un trouvera le moyen d'en faire des packages pour les principales distributions utilisées par les membres, à savoir Arch/Manjaro et des Debian-based ?)



Hackcell Hors ligne Maître du Puzzle Points: 1524 Défis: 11 Message

Citer : Posté le 23/05/2016 13:42 | #


Du coup gint pourrait occuper moins de place, non?
Cakeisalie5 En ligne Ancien administrateur Points: 1896 Défis: 11 Message

Citer : Posté le 23/05/2016 13:45 | #


gint a un statut un peu particulier à cause de son interrupt handler (et du linker script qu'il impose).

M'enfin, j'ai cru comprendre que c'était réglé, donc à voir.

Promotion ordinaire sur les inscriptions sur Planète Casio : en ce moment, c'est gratuit !

Mon blogBesoin d'utilitaires de transfert vers et depuis la calculatrice sous GNU/Linux ?
Dark storm Hors ligne Labélisateur Points: 11631 Défis: 176 Message

Citer : Posté le 23/05/2016 14:43 | #


Oui, si tu n'utilise pas toutes les fonctions de gint, tu n'aura pas à tout trimballer. Après il faut savoir que le gestionnaire d'interruption et les fonctions essentielles (getkey, dessin, etc.) sont celles qui prennent le plus de place.
Mais dans tout les cas, c'est développé de manière propre, faut pas s'en faire pour ça
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
Hackcell Hors ligne Maître du Puzzle Points: 1524 Défis: 11 Message

Citer : Posté le 23/05/2016 19:50 | #


Étant donné que c'est léphé qui d'en occupe je ne m'inquiète pas pour ça, c'est juste que j'avais mal compris et que je pensai que quand il disait que ça prenais de la place qu'il voulait dire que ça compilait tout gint.
-florian66- Hors ligne Ancien rédacteur Points: 2383 Défis: 20 Message

Citer : Posté le 23/05/2016 20:22 | #


Si je comprends bien, ça permet de séparer les fonctions et le compilo ne choisi que celle dont il a besoin et ne compile pas toute les fonctions ?
In Arch, I trust ! And you ?
Dark storm Hors ligne Labélisateur Points: 11631 Défis: 176 Message

Citer : Posté le 23/05/2016 20:27 | #


En soit, GCC le fait déjà. Il n'ajoute à l'écécutable que les fonctions qui sont utilisées. Vous pouvez faire le test, là dessus il est bon. Par contre, c'est le compilo d'Hitachi qui est moins performant. Donc ça prend pas forcément moins de place, c'est juste que c'est en effet un chouille plus propre.
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
Cakeisalie5 En ligne Ancien administrateur Points: 1896 Défis: 11 Message

Citer : Posté le 23/05/2016 20:32 | #


Attention à la nuance : le linker va prendre les fichiers objets contenant les fonctions que le programme utilise. Une lib statique n'est pas fait pour être suffisante, elle permet juste de proposer des fonctions à l'utilisateur. (par exemple, la libc, contenant entre autres printf, malloc, etc)

(un fichier source donne exactement un fichier objet, donc s'il y a plusieurs fonctions dans un fichier source, et que lors du link, le linker se rend compte que le programme utilisateur reprend une des fonctions du fichier objet, il va prendre tout le fichier objet)

Promotion ordinaire sur les inscriptions sur Planète Casio : en ce moment, c'est gratuit !

Mon blogBesoin d'utilitaires de transfert vers et depuis la calculatrice sous GNU/Linux ?
Dark storm Hors ligne Labélisateur Points: 11631 Défis: 176 Message

Citer : Posté le 23/05/2016 22:26 | #


Ce que je dis juste au dessus, c'est que si tu compile la bibliothèque depuis son .c (comme ce qui est fait actuellement), GCC n'ajoute au binaire que le code des fonctions qu'il utilise. Ce qui n'est pas le cas des .a compilés depuis un unique .c, on est d'accord.
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
Lephenixnoir En ligne Administrateur Points: 24145 Défis: 170 Message

Citer : Posté le 27/05/2016 21:21 | #


De toute façon gint est une lib statique, par essence. Si vous n'utilisez pas du tout un module, vous n'inclurez pas toute la lib. Mais en fait, vous devrez utiliser tous les modules. À moins que vous ne puissiez vous passer de dessiner à l'écran, d'afficher du texte ou d'utiliser le clavier.

L'interrupt handler n'est qu'un module comme un autre, excepté que vous ne pouvez pas linker sans. Le linker script définit un point d'entrée dont les dépendances incluent le gestionnaire.

Le tuto est pas mauvais, mais je pense qu'on peut faire un peu plus clair : peut-être en étant un peu plus factuel. Tu ne devrais pas insister sur le lien entre la répartition des fonctions dans les fichiers et la manière dont le compilateur lie les objets ?
Mon graphe (24 Mars): (gint#27 ; (Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; ...) || (shoutbox v5 ; v5)
Cakeisalie5 En ligne Ancien administrateur Points: 1896 Défis: 11 Message

Citer : Posté le 28/05/2016 02:01 | #


J'ai refait le tutoriel en détaillant un peu plus tout ce qui est ELF etc du coup.

Promotion ordinaire sur les inscriptions sur Planète Casio : en ce moment, c'est gratuit !

Mon blogBesoin d'utilitaires de transfert vers et depuis la calculatrice sous GNU/Linux ?
Lephenixnoir En ligne Administrateur Points: 24145 Défis: 170 Message

Citer : Posté le 28/05/2016 14:01 | #


C'est plus clair et plus joli je trouve !
Pense à utiliser [ justify ] aussi
Mon graphe (24 Mars): (gint#27 ; (Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; ...) || (shoutbox v5 ; v5)
Nemhardy Hors ligne Grand maître des Traits d'Esprit Points: 1242 Défis: 54 Message

Citer : Posté le 18/12/2016 13:32 | #


Ça vaudrait peut-être le coup de passer ce sujet dans la liste des tutoriels utiles non ?
Ça m'évitera d'avoir à endurer le fait d'aller sur le profil de Cake à chaque fois pour le retrouver.
Dark storm Hors ligne Labélisateur Points: 11631 Défis: 176 Message

Citer : Posté le 18/12/2016 22:07 | #


Fait
Finir est souvent bien plus difficile que commencer. — Jack Beauregard

LienAjouter une imageAjouter une vidéoAjouter un lien vers un profilAjouter du codeCiterAjouter un spoiler(texte affichable/masquable par un clic)Ajouter une barre de progressionItaliqueGrasSoulignéAfficher du texte barréCentréJustifiéPlus petitPlus grandPlus de smileys !
Cliquez pour épingler Cliquez pour détacher Cliquez pour fermer
Alignement de l'image: Redimensionnement de l'image (en pixel):
Afficher la liste des membres
:bow: :cool: :good: :love: ^^
:omg: :fusil: :aie: :argh: :mdr:
:boulet2: :thx: :champ: :whistle: :bounce:
valider
 :)  ;)  :D  :p
 :lol:  8)  :(  :@
 0_0  :oops:  :grr:  :E
 :O  :sry:  :mmm:  :waza:
 :'(  :here:  ^^  >:)

Σ π θ ± α β γ δ Δ σ λ
Veuillez donner la réponse en chiffre
Vous devez activer le Javascript dans votre navigateur pour pouvoir valider ce formulaire.

Si vous n'avez pas volontairement désactivé cette fonctionnalité de votre navigateur, il s'agit probablement d'un bug : contactez l'équipe de Planète Casio.

Planète Casio v4.3 © créé par Neuronix et Muelsaco 2004 - 2024 | Il y a 102 connectés | Nous contacter | Qui sommes-nous ? | Licences et remerciements

Planète Casio est un site communautaire non affilié à Casio. Toute reproduction de Planète Casio, même partielle, est interdite.
Les programmes et autres publications présentes sur Planète Casio restent la propriété de leurs auteurs et peuvent être soumis à des licences ou copyrights.
CASIO est une marque déposée par CASIO Computer Co., Ltd