Sei sulla pagina 1di 30

Tema: VI.

Bibliotecas: creacion y uso


Herramientas Avanzadas para el Desarrollo de Aplicaciones
Departamento de Lenguajes y Sistemas Inform
aticos
Universidad de Alicante

Curso 2012-2013 , Copyleft 2011-2013 .


Reproduccion permitida bajo los terminos de la licencia de
documentaci
on libre GNU.

1 / 26

Contenido
1

Que es una biblioteca?

Porque distribuir algo en formato binario?

Ejemplo sencillo

C
odigo ejemplo monoltico

Creacion de una biblioteca

Como generamos una biblioteca de enlace estatico?

Como enlazamos con una biblioteca de enlace estatico?

Como generamos una biblioteca de enlace dinamico?

Como enlazamos con una biblioteca de enlace dinamico?

10

Aplicaciones u
tiles para archivos .o, .a y .so

11

C
omo crear y usar una biblioteca en Vala

12

El codigo de ejemplo en Vala


2 / 26

Que es una biblioteca?

De manera muy resumida podemos decir que una biblioteca1 es un

compendio de recursos: subprogramas, clases, datos, etc. . .


Cuando distribumos estos recursos dentro de una biblioteca estamos

favoreciendo su uso y reutilizaci


on.
Motivo?: En el caso de c
odigo fuente no es necesario recompilar ya

que este se distribuye dentro de la biblioteca en forma binaria, ya


compilado; hasta ahora solo sabamos redistribuirlo en forma de
codigo fuente.
Para emplear una biblioteca hemos de enlazar nuestro c
odigo con

dicha biblioteca, de esta forma tenemos acceso a su contenido.

A lo largo del tema emplearemos el termino biblioteca en lugar de librera


por ser el primero m
as apropiado.
3 / 26

Porque distribuir algo en formato binario?

Por varios motivos:


Si para usarlo debe estar en formato binario le evitamos al usuario del

mismo tener que compilarlo.


En ocasiones el proceso de compilaci
on y obtencion de una biblioteca

es costoso y puede que no sea sencillo.


En el caso de las bibliotecas de enlace din
amico tenemos la ventaja de

poder cambiarlas para solucionar problemas sin necesidad de


recompilar.

4 / 26

Ejemplo sencillo I
Veamos en qu
e consiste una biblioteca con un ejemplo. . .
Para ello partimos de un c
odigo monoltico donde el programa

principal y las funciones que usa estan en un u


nico archivo.
Se trata de una aplicaci
on que implementa un sencillo algoritmo de

compresion/descompresi
on sobre cadenas.
Invocado de esta forma:
comp-decomp -c ccccaassssssssaaaaaaa

produce esta salida:


Compresion de ccccaassssssssaaaaaaa(21) es 4caa8s7a(8)

Partiendo del mismo c


odigo vamos a crear tres versiones de la

aplicacion: monoltica, enlazada con una con una biblioteca estatica y


enlazada con una biblioteca dinamica.

5 / 26

Ejemplo sencillo II

Monol
tica

libcomp-decomp.a

libcomp-decomp.so

Enlace est
atico

Enlace din
amico

comp-decomp.c

comp.h

comp.c

decomp.h

decomp.c

6 / 26

Ejemplo sencillo II

Monol
tica

libcomp-decomp.a

libcomp-decomp.so

Enlace est
atico

Enlace din
amico

comp-decomp.c

comp.h

comp.c

decomp.h

decomp.c

6 / 26

Ejemplo sencillo II

Monol
tica

libcomp-decomp.a

libcomp-decomp.so

Enlace est
atico

Enlace din
amico

comp-decomp.c

comp.h

comp.c

decomp.h

decomp.c

6 / 26

Ejemplo sencillo II

Monol
tica

libcomp-decomp.a

libcomp-decomp.so

Enlace est
atico

Enlace din
amico

comp-decomp.c

comp.h

comp.c

decomp.h

decomp.c

6 / 26

Ejemplo sencillo II

Monol
tica

libcomp-decomp.a

libcomp-decomp.so

Enlace est
atico

Enlace din
amico

comp-decomp.c

comp.h

comp.c

decomp.h

decomp.c

6 / 26

Codigo ejemplo monoltico I (comp-decomp.c)

1
3
5
7

#i n c l u d e <s t d i o . h>
#i n c l u d e <s t d l i b . h>
#i n c l u d e <s t r i n g . h>
/ D e v u e l v e e l numero de c a r a c t e r e s i g u a l e s a l p r i m e r o de s /
s t a t i c i n t c a r a c t e r e s i g u a l e s ( char s ) {
int l = 0;
i n t cont = 1;

9
i f ( s == NULL) r e t u r n 0 ;
11
l = strlen (s) ;
i f ( l < 2)
return l ;
else {
int i = 1;
w h i l e ( s [ 0 ] == s [ i ++])
c o n t ++;
return cont ;
}

13
15
17
19
21

7 / 26

Codigo ejemplo monoltico II (comp-decomp.c)


1
3

/* Devuelve en cs la cadena comprimida de s . */


void comprime ( char * s , char * cs ) {
int l = cont = i = 0;
char num [5] , * s2 ;

5
if ( s == NULL )

return ;

7
l = strlen ( s ) ;
if ( l < 3) strcat ( cs , s ) ;
else {
int csl = 0;
cont = c a r a c t e r e s _ i g u a l e s ( s ) ;
if ( cont > 2) {
sprintf ( num , " %d " , cont ) ;
strcat ( cs , num ) ;
csl = strlen ( cs ) ;
cs [ csl ++] = s [0];
cs [ csl ] = \0 ;
} else {
csl = strlen ( cs ) ;
for ( i = 0; i < cont ; i ++)
cs [ csl ++] = s [0];
cs [ csl ] = \0 ;
}

9
11
13
15
17
19
21
23
25

s2 = & s [ cont ];
comprime ( s2 , cs ) ;

27
}

29

8 / 26

Codigo ejemplo monoltico III (comp-decomp.c)


1
3
5
7
9

/* Devuelve en s la cadena descomprimida de cs . */


void descomprime ( char * cs , char * s ) {
/* por hacer */
strcat (s , cs ) ;
}
int main ( int argc , char * argv [])
{
char c [100];

11

if ( argc != 3) {
printf ( " Uso : comp - decomp [ - c | - d ] cadena \ n " ) ;
return 1;
} else {
if ( ( strcmp ( argv [1] , " -c " ) != 0) && ( strcmp ( argv [1] , " -d " ) != 0) ) {
printf ( " Uso : comp - decomp [ - c | - d ] cadena \ n " ) ;
return 2;
}
}
if ( strcmp ( argv [1] , " -c " ) == 0) {
c [0] = \0 ;
comprime ( argv [2] , c ) ;
printf ( " Compresion de \" %s\"( %d ) es \" %s\"( %d ) \ n " , argv [2] , strlen ( argv [2]) , c ,
strlen ( c ) ) ;
}
if ( strcmp ( argv [1] , " -d " ) == 0) {
c [0] = \0 ;
descomprime ( argv [2] , c ) ;
printf ( " Descompresion de \" %s\"( %d ) es \" %s\"( %d ) \ n " , argv [2] , strlen ( argv [2]) ,
c , strlen ( c ) ) ;
}
return 0;

13
15
17
19
21
23
25
27
29
31

9 / 26

Creacion de una biblioteca


Para crear una biblioteca de enlace din
amico o estatico primero

necesitamos dividir el c
odigo anterior.
Colocaremos en uno o varios archivos las funciones y/o estructuras de

datos que proporcionan la funcionalidad principal.


Dejaremos fuera de estos archivos el c
odigo que haca de programa

principal, el cual estara en otro archivo que se limitara a hacer de


consumidor del codigo de la biblioteca.
En nuestro caso la divisi
on en archivos nos proporciona los siguientes:
comp.h y comp.c Contienen el c
odigo relacionado con la funcion de

compresi
on.
decomp.h y decomp.c Contienen el c
odigo relacionado con la funcion

de descompresi
on.
comp-decomp-driver.c Es el programa principal en el cual se

analizan los argumentos con el que lo hemos llamado y se llama a la


funci
on correspondiente.
10 / 26

comp.h y comp.c I

/* comp . h */

void comprime ( char * s , char * cs ) ;

/* comp . c */

# include < stdio .h >


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

5
7
9

/* Es privada , la biblioteca no la exporta . ( modificador static ) */


static int c a r a c t e r e s _ i gu a l e s ( char * s ) {
int l = 0 , cont = 1;

11

if ( s == NULL ) return 0;
l = strlen ( s ) ;
if ( l < 2) return l ;
else {
int i = 1;
while ( s [0] == s [ i ++]) cont ++;
return cont ;
}

13
15
17
19

11 / 26

comp.h y comp.c II
1

/* comp . c */

void comprime ( char * s , char * cs ) {


int l = cont = i = 0;
char num [5] , * s2 ;

5
7

if ( s == NULL ) return ;

l = strlen ( s ) ;
if ( l < 3) strcat ( cs , s ) ;
else {
int csl = 0;
cont = c a r a c t e r e s _ i g u a l e s ( s ) ;
if ( cont > 2) {
sprintf ( num , " %d " , cont ) ;

11
13
15
17

strcat ( cs , num ) ;
csl = strlen ( cs ) ;
cs [ csl ++] = s [0];
cs [ csl ] = \0 ;
} else {
csl = strlen ( cs ) ;
for ( i = 0; i < cont ; i ++) cs [ csl ++] = s [0];
cs [ csl ] = \0 ;
}
s2 = & s [ cont ];
comprime ( s2 , cs ) ;

19
21
23
25
27
}

29

12 / 26

decomp.h y decomp.c

/* decomp . h */

void descomprime ( char * s , char * cs ) ;

/* decomp . c */

# include < string .h >

/* Devuelve en s la cadena descomprimida de cs .


*/
void descomprime ( char * cs , char * s ) {
/* por hacer */
strcat (s , cs ) ;
}

7
9

13 / 26

comp-decomp-driver.c
1
3

/* comp - decomp - driver . c -- Es el programa princiapal . */


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

5
7
9
11

# include " comp . h "


# include " decomp . h "
int main ( int argc , char * argv [])
{
char c [100];

13

if ( argc != 3) {
printf ( " Uso : comp - decomp [ - c | - d ] cadena \ n " ) ;
return 1;
} else
if ( ( strcmp ( argv [1] , " -c " ) != 0) &&
( strcmp ( argv [1] , " -d " ) != 0) )
{
printf ( " Uso : comp - decomp [ - c | - d ] cadena \ n " ) ;
return 2;
}
if ( strcmp ( argv [1] , " -c " ) == 0) {
c [0] = \0 ;
comprime ( argv [2] , c ) ;
printf ( " Compresion de \" %s\"( %d ) es \" %s\"( %d ) \ n " , argv [2] , strlen ( argv [2]) , c ,
strlen ( c ) ) ;
}
if ( strcmp ( argv [1] , " -d " ) == 0) {
c [0] = \0 ;
descomprime ( argv [2] , c ) ;
printf ( " Descompresion de \" %s\"( %d ) es \" %s\"( %d ) \ n " , argv [2] , strlen ( argv [2]) ,
c , strlen ( c ) ) ;
}
return 0;

15
17
19
21
23
25
27
29
31
33
}

14 / 26

Como generamos una biblioteca de enlace estatico?


Compilamos los archivos que la componen por separado. De cada uno

obtenemos su .o.
Con la aplicaci
on ar -similar a tar- creamos el archivo biblioteca

con extension .a -a de archivo- as:


ar crs libcomp-decomp.a comp.o decomp.o
Donde la cadena crs representa las opciones con las que lo

llamamos:
c Crea el archivo con nombre: libcomp-decomp.a
r Reemplaza -si ya existiera- en el archivo .a cada uno
de los archivos que se especifican a continuacion.
s Crea un ndice en el archivo .a para que sea mas
rapido acceder a los archivos que contiene.

15 / 26

Como enlazamos con una biblioteca de enlace estatico? I

Podemos hacerlo de varias maneras:


Especificando su ruta completa, igual que si fuera un archivo .o:

/ruta/hasta/fichero.a.
Adicionalmente, si su nombre sigue este convenio: libnombre-bib.a, el

enlazador lo reconoce y se puede poner de este modo en la lnea de


enlace: -lnombre-bib .
El enlazador es una aplicaci
on distinta al compilador, es independiente

del lenguaje de programaci


on empleado. Tradicionalmente en s.o. de
la familia UNIX este programa se llama ld.

16 / 26

Como enlazamos con una biblioteca de enlace estatico? II

2
4

# ######################
# Biblioteca estatica #
# #######################################################
comp - decomp - estatico : comp - decomp - driver . o libcomp - decomp . a
$ ( CC ) - static comp - decomp - driver . o -L . - lcomp - decomp -o comp - decomp - estatico

6
8
10

comp - decomp - driver . o : comp - decomp - driver . c


$ ( CC ) -c $ ( CFLAGS ) comp - decomp - driver . c
libcomp - decomp . a : comp . o decomp . o
$ ( AR ) crs libcomp - decomp . a comp . o decomp . o

12
14
16

comp . o : comp . c
$ ( CC ) -c $ ( CFLAGS ) comp . c
decomp . o : decomp . c
$ ( CC ) -c $ ( CFLAGS ) decomp . c

17 / 26

Como generamos una biblioteca de enlace dinamico?

Al igual que antes compilamos los archivos que la componen por

separado. De cada uno obtenemos su .o pero hemos de usar la


opcion -fpic. pic: Position Independent Code.
Las bibliotecas de enlace din
amico usan la extension .so en s.o. de

la familia UNIX. Son equivalentes a las DLL de Windows.


Para generarlas no necesitamos de ningun programa nuevo como

antes, basta con el propio enlazador suministrandole la opcion


-shared:
gcc -shared -o libcomp-decomp.so comp-pic.o decomp-pic.o

18 / 26

Como enlazamos con una biblioteca de enlace dinamico?

1
3
5
7

# #################################
# Bibliotecea de enlace dinamico #
# ################################################################
comp - decomp - dinamico : comp - decomp - driverdin . o libcomp - decomp . so
$ ( CC ) comp - decomp - driverdin . o -L . - lcomp - decomp -o comp - decomp - dinamico
comp - decomp - driverdin . o : comp - decomp - driverdin . c
$ ( CC ) - fpic -c $ ( CFLAGS ) comp - decomp - driverdin . c

9
11
13

libcomp - decomp . so : comp - pic . o decomp - pic . o


$ ( CC ) - shared -o libcomp - decomp . so comp - pic . o decomp - pic . o
comp - pic . o : comp . c
$ ( CC ) -c -o comp - pic . o - fpic $ ( CFLAGS ) comp . c

15
17

decomp - pic . o : decomp . c


$ ( CC ) -c -o decomp - pic . o - fpic $ ( CFLAGS ) decomp . c

19 / 26

Aplicaciones utiles para archivos .o, .a y .so I

Son aplicaciones que nos permiten extraer informaci


on de este tipo de
archivos o incluso modificarlos de cierto manera:
nm Lista los smbolos dentro de un archivo binario. Ademas nos
da cierta informaci
on sobre cada uno de ellos.
ranlib Crea el ndice en una biblioteca hecha con ar, es decir,
tiene la misma funci
on que la opci
on s de ar.
strip Elimina determinados smbolos del archivo binario con el fin
de reducir su tama
no.

20 / 26

Aplicaciones utiles para archivos .o, .a y .so II

Veamos la salida que produce nm sobre la biblioteca de enlace estatico


que hemos creado previamente:
1

Ejecutamos libcomp - decomp . a

comp . o :
0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 t c a r a c t e r e s _ i g u a l e s
0 0 0 0 0 0 0 0 0 0 0 0 0 0 78 T comprime
U sprintf
U strcat
U strlen

5
7
9
11

decomp . o :
0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 T descomprime
U strcat

21 / 26

Aplicaciones utiles para archivos .o, .a y .so III


Qu
e efecto tiene strip en nuestros archivos binarios?
B
asicamente el tama
no final de los mismos, compara:

antes ls -l libcomp-decomp.a = 3838 bytes


despues strip libcomp-decom.a,
ls -l libcomp-decomp.a = 2536 bytes
En general puedes emplear strip con cualquier archivo binario

generado en el proceso de compilaci


on/enlace, incluso con un
ejecutable final:
antes ls -l comp-decomp = 8658 bytes
despues strip comp-decom,
ls -l comp-decomp = 6008 bytes
Despu
es de conocer strip que crees que son los targets Debug y

Release de VisualStudio?
22 / 26

Aplicaciones utiles para archivos .o, .a y .so IV

En el caso de archivos ejecutables enlazados din


amicamente con

alguna biblioteca, la orden ldd es especialmente u


til.
Nos informa de con qu
e bibliotecas esta enlazada de forma dinamica

nuestra aplicacion y si falta alguna; ademas nos indica la ruta hasta


donde esta cada una de ellas en el sistema de ficheros:
2
4

l d d compdecomp
l i n u x v d s o . s o . 1 => ( 0 x 0 0 0 0 7 f f f a 5 7 f f 0 0 0 )
l i b c . s o . 6 => / l i b / x 8 6 6 4l i n u x gnu / l i b c . s o . 6 ( 0 x 0 0 0 0 7 f 3 8 c 1 b 4 6 0 0 0 )
l i b c o m pdecomp . s o => n o t f o u n d
/ l i b 6 4 / l dl i n u x x86 64. s o . 2 ( 0 x 0 0 0 0 7 f 3 8 c 1 e f 6 0 0 0 )

23 / 26

Como crear y usar una biblioteca en Vala

Separamos el c
odigo siguiendo los mismos criterios que en el ejemplo

en C.
Para generar la biblioteca empleamos una orden como esta:
valac --library=comp-decomp -H comp-decomp.h comp.vala -X -fPIC -X -shared -o libcomp-decomp.so

Mientras que para enlazar con ella usaremos una orden como esta

otra:
valac comp-decomp.vapi comp-decomp-driver.vala -X libcomp-decomp.so -X -I. -o comp-decomp-driver

Los ficheros .vapi son para Vala similares a los .h para C.

24 / 26

El codigo de ejemplo en Vala I


1
3
5

/* comp . vala */
namespace CompDecomp {
private int c a r a c t e r e s _ i g u a l e s ( string s ) {
int l = 0;
int cont = 1;

l = s . length ;
if ( l < 2) return l ;
else {
int i = 1;
while ( s [0] == s [ i ++]) cont ++;
return cont ;
}

9
11
13
}

15
public void comprime ( string s , ref string cs ) {
int l = 0 , cont = 0;
string num , s2 ;

17
19

l = s . length ;
if ( l < 3) cs += s ;
else {
cont = c a r a c t e r e s _ i g u a l e s ( s ) ;
if ( cont > 2) {
num = cont . to_string () ;
cs += num ; cs += s [0]. to_string () ;
} else { cs += string . nfill ( cont , s [0]) ; }
s2 = s [ cont : s . length ];
comprime ( s2 , ref cs ) ;
}

21
23
25
27
29
31

}
}

25 / 26

El codigo de ejemplo en Vala II

2
4
6
8
10
12
14
16
18

/* comp - decomp - driver . vala */


using CompDecomp ;
int main ( string [] args ) {
if ( args . length != 3) {
stdout . printf ( " Uso : comp - decomp [ - c | - d ] cadena \ n " ) ;
return 1;
} else if ( ( args [1] != " -c " ) && args [1] != " -d " ) ) {
stdout . printf ( " Uso : comp - decomp [ - c | - d ] cadena \ n " ) ;
return 2;
}
if ( args [1] == " -c " ) {
string c = " " ;
comprime ( args [2] , ref c ) ;
stdout . printf ( " Compresion de \" %s\"( %d ) es \" %s\"( %d ) \ n " ,
args [2] , args [2]. length ,
c,
c . length ) ;
}

20

return 0;
}

26 / 26

Potrebbero piacerti anche