Obligement - L'Amiga au maximum

Vendredi 29 mars 2024 - 01:22  

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 : Les objets partagés sur AmigaOS 4 - présentation et utilisation
(Article écrit par Mathias Parnaudeau et extrait de www.gurumed.net - juillet 2009)


Jusqu'à présent, les dépendances d'un programme étaient connues en tant que bibliothèques statiques (.a) ou partagées (.library). Après les systèmes Unix, AmigaOS 4 introduit un nouveau type nommé "objets partagées" (ou "shared objects", de suffixe .so) dont des détails techniques se trouvent sur la page des Frieden. Cet article se propose de présenter les objets partagés et de montrer comment les utiliser et les générer, en se servant d'un cas concret, SDL_ttf.

Nature d'un objet partagé

Un programme ou une bibliothèque contient du code et des données qui occupent des zones distinctes en mémoire. Le code est en lecture seule et donc plusieurs processus pourraient utiliser le code présent en un seul endroit. C'est le cas des bibliothèques partagées sauf que leur création implique de faire très attention au niveau des données, elles n'acceptent pas de variables globales qui pourraient être utilisées par plusieurs programmes sans dommages. Les objets partagés proposent un format capable de partager le code et d'allouer une zone de données pour chacun des programmes utilisant un objet. A l'heure actuelle, le code n'est pas encore partagé.

Mise en place

Mon but était d'utiliser les objets partagés pour compiler PointRider (lecteur de fichiers PowerPoint) dont les dépendances sont : SDL, SDL_image et SDL_ttf. La dernière n'étant disponible qu'en bibliothèque statique, je me suis dit qu'elle serait parfaite pour s'exercer. Elle est de plus très simple et après avoir téléchargé l'archive sur la page du projet SDL_ttf, il n'y a qu'un seul fichier à compiler. La complexité repose dans la bibliothèque freetype dont elle dépend.

Création d'un objet partagé

En théorie, un objet partagé possède les avantages d'une ".library" à l'exécution et ceux d'une bibliothèque statique à la création, qui est la partie la plus simple. Pour créer une bibliothèque statique, on faisait :

gcc -O2 -I/SDK/Local/newlib/include/SDL -c SDL_ttf.c
ar ru libSDL_ttf.a SDL_ttf.o

Pour un objet partagé, la procédure est très proche, la compilation tout d'abord :

gcc -O2 -I/SDK/Local/newlib/include/SDL -fPIC -c SDL_ttf.c

Attention, les majuscules dans l'argument "-fPIC" ont leur importance, ne saisissez pas "-fpic".

Pour la création de l'objet final, l'option "-shared" est obligatoire. Il faut également indiquer tous les objets à "linker" donc les fichiers ".o" mais dans notre cas, il faut également mentionner "-lfreetype". Je ne l'avais pas fait dans un premier temps et c'est la catastrophe assurée car sinon toute référence à l'objet freetype est perdue. Comme on traite d'objets partagés, gcc va chercher libfreetype.so et comme elle se trouve par défaut dans SOBJS: dans AmigaOS 4, nous ajoutons ce chemin de recherche à ligne de commande (au format Unix) :

gcc -L/SOBJS/ -shared -o libSDL_ttf.so SDL_ttf.o -lfreetype

Que faire quand on a obtenu ce fichier ? Un utilisateur qui voudra lancer un programme qui le requiert aura dû le placer au préalable dans le répertoire système SOBJS:.

Utilisation pratique

Le problème est que lorsqu'on veut compiler un programme qui utilise des objets partagés, il n'a que faire de SOBJS:, le compilateur considère ses propres chemins dans lesquels il s'attend à trouver les bibliothèques, comme "SDK:newlib/lib" ou "SDK:Local/newlib/lib" puisque newlib est désormais la libc choisie par défaut dans AmigaOS 4.1 aux dépens de clib2 précédemment.

Pour utiliser un objet partagé, il faut que ses dépendances en soient aussi. Par exemple, si un programme requiert libSDL_ttf qui repose sur libfreetype, alors si libSDL_ttf est un objet partagé, libfreetype doit l'être aussi.

Basiquement, pour dire au compilateur d'utiliser des objets partagés au lieu de bibliothèques statiques, il faut indiquer l'argument "-use-dynld" au niveau de l'édition de liens. Cette option signifie "dynamic load" ou "chargement dynamique" car c'est à l'exécution du programme que l'objet est chargé et que les liens sont établis.

Voici un exemple de code utilisant SDL_ttf :

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "SDL.h"
#include "SDL_ttf.h"
#include "SDL_syswm.h"

int main( int argc, char* argv[] )
{
	SDL_Surface* screen;
	SDL_Event event;
	int ttf_init;

	int ask_exit = 0;
	TTF_Font *default_font = NULL;
	int font_size;
	char font_path[256];

	SDL_Color color = {255,0,0};
	SDL_Surface *text_surface;
	SDL_Rect rect;

	/* Initialize SDL and its TTF module */

	SDL_Init(SDL_INIT_VIDEO);
	ttf_init = TTF_Init();
	if (ttf_init == -1){
		printf("TTF_Init: %s\n", TTF_GetError());
	
	}

	/* Get a font that we know it is available in the system */

	strcpy(font_path, "SYS:TTFonts/Vera.ttf");
	strcpy(font_path, "SYS:Fonts/_TrueType/Vera.ttf");
	font_size = 48;

	printf("TTF_WasInit = %d\n", TTF_WasInit());

	default_font = TTF_OpenFont(font_path, font_size);
	
	if (!default_font){
		printf("Error : can't find font [%s], error = %s\n", font_path, TTF_GetError());
		return 1;
	}

	/* Open a surface and render the text */

	screen = SDL_SetVideoMode(640, 480, 0, 0);

	SDL_WM_SetCaption("This example uses libSDL_ttf.so", "example"); // 2nd arg is for icon name

	text_surface = TTF_RenderText_Solid(default_font, "Amiga rulez !", color);
	if (text_surface){
		rect.x = 20;
		rect.y = 20;
		rect.w = screen->w - 20;
		rect.h = text_surface->h;
		SDL_BlitSurface(text_surface, NULL, screen, &rect);
		SDL_FreeSurface(text_surface);
	}else{
		// Red rectangle to show that an error happened
		rect.x = 20;
		rect.y = 20;
		rect.w = screen->w - 40;
		rect.h = 80;
		SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format, 255, 0, 0));
				
		printf("Can't render the solid text, error = %s\n", TTF_GetError());
	}

	SDL_UpdateRect(screen, 0, 0, 0, 0);

	/* Event loop */
		
	while (!ask_exit)
	{
		/* Look for an event */
		if (SDL_WaitEvent(&event)) {
			/* An event was found */
			switch (event.type) {
				case SDL_QUIT:
					/* Close button clicked */
					ask_exit = 1;
					break;
				case SDL_KEYDOWN:
					switch ((int)event.key.keysym.sym) {
						case SDLK_ESCAPE:
							ask_exit = 1;
							break;
					}
					break;
			}
		}
	}

	/* Close the font and SDL */

	if (default_font){
		TTF_CloseFont(default_font);
	}
	TTF_Quit();
	SDL_Quit();

	return 0;
}

Pour le compiler :

gcc -Wall -L/SOBJS -ISDK:Local/newlib/include/SDL -ISDK:Local/common/include/SDL
-Wl,--verbose -use-dynld -o example example.c -lSDL-1.2 -lSDL_ttf -lfreetype -lz

Attention, si dans ses chemins de recherche, le compilateur trouve une version statique de la bibliothèque à lier, il s'en contentera et la choisira avant de tomber sur l'objet partagé qui serait dans un chemin additionnel, comme SOBJS:. C'est pourquoi il nécessaire dans ce cas de créer un lien, depuis SDK:Local/newlib/lib :

makelink FROM libSDL_ttf.so TO SOBJS:libSDL_ttf.so SOFT

Si l'option commençant par "-Wl" ne vous est pas familière, sachez que c'est une méthode pour passer des paramètres à l'éditeur de lien. "--verbose" est ici pour l'exemple, il est probable que vous ne gardiez pas cette option, gêné par le flot d'informations. Dans d'autres exemples ici ou là, vous trouverez certainement "-Wl,-rpath,/SDK/Local/newlib/lib". Cela ajoute un chemin pour chercher les objets partagés dans un répertoire additionnel à l'exécution du programme, le "r" dans "rpath" signifiant "runtime". Personnellement, je déconseille cet usage, les utilisateurs n'ont pas forcément le SDK installé.

La réduction de la taille de l'exécutable est visible mais ce n'est pas une méthode sûre pour vérifier l'utilisation prévue des objets partagés. La commande suivante permet d'avoir les idées plus claires :

readelf -d example

Ce qui donne :

Dynamic section at offset 0xc78 contains 20 entries:
  Tag        Type                         Name/Value
 0x00000001 (NEEDED)                     Shared library: [libSDL-1.2.so]
 0x00000001 (NEEDED)                     Shared library: [libSDL_ttf.so]
 0x00000001 (NEEDED)                     Shared library: [libfreetype.so]
 0x00000001 (NEEDED)                     Shared library: [libz.so]
 0x00000001 (NEEDED)                     Shared library: [libgcc.so]
 0x00000001 (NEEDED)                     Shared library: [libc.so]
 0x00000004 (HASH)                       0x10000e8
 0x00000005 (STRTAB)                     0x10003a0
 0x00000006 (SYMTAB)                     0x10001b0
 0x0000000a (STRSZ)                      423 (bytes)
 0x0000000b (SYMENT)                     16 (bytes)
 0x00000015 (DEBUG)                      0x0
 0x00000003 (PLTGOT)                     0x1010d70
 0x00000002 (PLTRELSZ)                   228 (bytes)
 0x00000014 (PLTREL)                     RELA
 0x00000017 (JMPREL)                     0x1000560
 0x00000007 (RELA)                       0x1000548
 0x00000008 (RELASZ)                     252 (bytes)
 0x00000009 (RELAENT)                    12 (bytes)
 0x00000000 (NULL)                       0x0

On constate avec les lignes de type "NEEDED" que toutes les dépendances sont des objets partagés, comme prévu.

Les contreparties

Les objets partagés présents dans le système ne contiennent pas leur numéro de version, c'est ennuyeux pour le suivi. Il y a ensuite des fichiers qui n'ont pas le même nom et pour lesquels il faut créer des liens symboliques. Par exemple, l'objet SDL se nomme "libSDL-1.2.so" mais un lien "libSDL.so" existe pour les programmes qui chercheraient l'objet sous ce nom. Et quand une nouvelle version sortira, le lien pourra par exemple pointer sur "libSDL-1.3.so".

Comme nous le disions au début, pour l'instant chaque programme charge le code et les données de ses objets partagés : le partage n'est pour l'instant pas effectif.

L'avantage tient dans le fait que le portage de bibliothèques, venant de Linux par exemple, est facilité. Et comme les bibliothèques statiques, il n'y a pas besoin de les ouvrir et de les fermer.

A noter que si un programme ne trouve pas un objet dont il a besoin, le système ouvre une fenêtre en indiquant quel objet manque puis un message "file is not executable" sera affiché dans une console.


[Retour en haut] / [Retour aux articles]