Obligement - L'Amiga au maximum

Mercredi 20 septembre 2017 - 07:46  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

 · Accueil
 · A Propos
 · Articles
 · Galeries
 · Glossaire
 · Hit Parade
 · Liens
 · Liste jeux Amiga
 · Quizz
 · Téléchargements
 · Trucs et astuces


Articles

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

 · Articles in english
 · Articles in other languages


Twitter

Suivez-nous sur Twitter




Liens

 · Sites de téléchargements
 · Associations
 · Pages Personnelles
 · Moteurs de recherche
 · Pages de liens
 · Constructeurs matériels
 · Matériel
 · Autres sites de matériel
 · Réparateurs
 · Revendeurs
 · Presse et médias
 · Programmation
 · Développeurs logiciels
 · Logiciels
 · Développeurs de jeux
 · Jeux
 · Autres sites de jeux
 · Scène démo
 · Divers
 · Informatique générale


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


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


Partenaires

Annuaire Amiga

Amedia Computer

Relec

Hit Parade


Contact

David Brunet

Courriel

 


Programmation : Les objets partagés sur AmigaOS 4 - présentation et utilisation
(Article écrit par Mathias Parnaudeau et extrait 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 au dépend 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 
#include 
#include 

#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]