02 programación c++ al completo

96
Programación C++ Adolfo J. Millán 1.4.0a1 GNU Make §1 Sinopsis El compilador GNU cpp dispone de su correspondiente utilidad Make para la construcción de proyectos; ya sean ejecutables o librerías de cualquier tipo. Seguramente esta versión de Make es de las que cuentan con mejor y más extensa documentación sobre su funcionamiento. El manual correspondiente está disponible en la sección de manuales online de la organización GNU www.gnu.org . Aconsejo consultarlo aunque se esté utilizando otro compilador, dado que en realidad las versiones de Make de las distintas plataformas son muy parecidas, si no idénticas, y sus enseñanzas le resultarán de gran ayuda. Por supuesto, para escribir un makefile, es necesario conocer las opciones del compilador, enlazador y cualquier otra utilidad que sea utilzada con él. En nuestro caso, la documentación sobre los compiladores GNU gcc y demás utilidades está igualmente disponible en la sección de manuales de la citada organización ( www.gnu.org ). Nota: para la redacción del presente capítulo he utilizado los siguientes: Manual GNU Gcc: "Using the GNU Compiler Collection" For GCC Version 4.1.1. Manual GNU Make: "The GNU Make Manual" for GNU make version 3.81. Edition 0.70, last updated 1 April 2006. Manual Enlazador GNU: "Using ld The GNU linker" version 2 January 1994 Manual Utilidades Binarias (binutils GNU): "Preliminary documentation for the GNU binary utilities. version 2.12" Esta página no pretende ser un sustituto de los manuales citados, solo una breve introducción en la que destacaremos sus características principales y algún ejemplo sencillo de uso. Advirtamos también, que al objeto de que puedan ser reproducidos por la mayor cantidad de lectores posible, los ejemplos incluidos en esta sección se suponen realizados bajo Windows32 utilizando la versión 3.9 de MinGW incluida en la versión 4.9.9.2 del entorno de desarrollo Dev-C++ ( CompiladoresC ) [5 ].

Upload: ferbuifo

Post on 27-Oct-2015

52 views

Category:

Documents


0 download

TRANSCRIPT

Programacin C++Adolfo J. Milln1.4.0a1 GNU Make1 SinopsisEl compilador GNU cpp dispone de su correspondiente utilidadMakepara la construccin de proyectos; ya sean ejecutables o libreras de cualquier tipo. Seguramente esta versin deMakees de las que cuentan con mejor y ms extensa documentacin sobre su funcionamiento. El manual correspondiente est disponible en la seccin de manuales online de la organizacin GNUwww.gnu.org. Aconsejo consultarlo aunque se est utilizando otro compilador, dado que en realidad las versiones de Make de las distintas plataformas son muy parecidas, si no idnticas, y sus enseanzas le resultarn de gran ayuda. Por supuesto, para escribir un makefile, es necesario conocer las opciones del compilador, enlazador y cualquier otra utilidad que sea utilzada con l. En nuestro caso, la documentacin sobre los compiladores GNU gcc y dems utilidades est igualmente disponible en la seccin de manuales de la citada organizacin (www.gnu.org).Nota: para la redaccin del presente captulo he utilizado los siguientes:Manual GNU Gcc: "Using the GNU Compiler Collection" For GCC Version 4.1.1.Manual GNU Make: "The GNU Make Manual" for GNU make version 3.81. Edition 0.70, last updated 1 April 2006.Manual Enlazador GNU: "Using ld The GNU linker" version 2 January 1994Manual Utilidades Binarias (binutils GNU): "Preliminary documentation for the GNU binary utilities. version 2.12"

Esta pginano pretende ser un sustituto de los manuales citados, solo una breve introduccin en la que destacaremos sus caractersticas principales y algn ejemplo sencillo de uso. Advirtamos tambin, que al objeto de que puedan ser reproducidos por la mayor cantidad de lectores posible, los ejemplos incluidos en esta seccin se suponen realizados bajo Windows32 utilizando la versin 3.9 de MinGW incluida en la versin 4.9.9.2 del entorno de desarrollo Dev-C++ (CompiladoresC) [5].Aunque las herramientas y entornos GNU son asociados generalmente con el mundo Unix/Linux, debemos recordar que existen versiones para las plataformas ms comunes (prcticamente todas las imaginables), incluyendo por supuesto las de Microsoft. Respecto a estas ltimas, existen herramientas GNU que permiten la construccin de aplicaciones C/C++ para las distintas versiones de Windows. En concreto, existen dos que merecen ser consideradas: nos referimos aCygwinyMinGWque se sustentan en filosofas muy distintas para conseguir sus objetivos.Cygwin consiste en una capa ("layer") de software, que permite que aplicaciones que han sido desarrollados para Unix/Linux, puedan ser compiladas y ejecutadas en Windows. Su principal ventaja es que permite trasladar el enorme arsenal de herramientas Unix/Linux de cdigo abierto a estos entornos [1]. Por su parte, MinGW hace honor a su nombre, acrnimo de "Minimalist GNU for Windows", en el sentido de que incluye las herramientas mnimas para construir ejecutables en Windows. En este caso, las aplicaciones deben ser escritas para Windows, de forma anloga a como se hara en cualquier otra plataforma nativa de estos sistemas. Por ejemplo, para los compiladores Visual C++ de MS o C++ Builder de Borland-Imprise.En realidad MinGW consiste bsicamente en una versin del compilador GNU gcc para Windows, que incluye el compilador propiamente dicho, el enlazador y el depurador (GDB). As como una coleccin de ficheros de cabecera, de "makefiles" y ficheros "scripts". Para que estos ltimos puedan ser ejecutados en Windows utilizando una sintaxis POSIX [2], existe una utilidad especial denominada MSYS (Minimal SYStem); que remeda el shell de Linux/Unix, incluyendo un intrprete de comandos ("Command Line Interpreter" CLI) y un conjunto mnimo de las herramientas del shell de Unix/Linux. Por ejemplo,touch;cat;grep;mount;tail;xargs, etc. (esta utilidad ya viene incluida por defecto en la plataforma Dev-C++).2GNU Make en la prcticaLos principios de funcionamiento los explicaremos mediante un ejemplo, en el que construimos una pequea aplicacin C++ compuesta por tres ficheros:main.cpp;string.cppystring.h. Como puede verse, dos ficheros fuente y uno de cabecera.Para nuestro propsito, utilizaremos un makefile al que denominaremosmake.my, con el siguiente diseo:# Project: una clase string

CPP = g++.exe # el compilador GNU C++OBJ = main.o string.oLINKOBJ = main.o string.oLIBS = -L"C:/DEV-CPP/lib"CXXINCS = -I"C:/DEV-CPP/lib/gcc/mingw32/3.4.2/include" \ -I"C:/DEV-CPP/include/c++/3.4.2/backward" \ -I"C:/DEV-CPP/include/c++/3.4.2/mingw32" \ -I"C:/DEV-CPP/include/c++/3.4.2" -I"C:/DEV-CPP/include"BIN = string.exeCXXFLAGS = $(CXXINCS) -fno-elide-constructors

.PHONY: clean

all: string.exe

clean: ${RM} $(OBJ) $(BIN)

$(BIN): $(OBJ) $(CPP) $(LINKOBJ) -o "string.exe" $(LIBS)

main.o: main.cpp $(CPP) -c main.cpp -o main.o $(CXXFLAGS)

string.o: string.cpp $(CPP) -c string.cpp -o string.o $(CXXFLAGS)3 InvocacinSuponemos que la utilidadmake.exe, junto con el resto de binarios MinGW, est en el directorioC:\Dev-Cpp\bin, y que los tres ficheros de nuestro proyecto se encuentran enD:\LearnC. Utilizando una ventana DOS de Windows, nos situamos en el directorio de trabajo (donde residen los fuentes):C:\Windows>D:D:\>cd LearnCD:\LearnC>A continuacin establecemos el camino de bsqueda ("Path"), de forma que nuestras rdenes encuentren los binarios correspondientes:D:\LearnC>set PATH=C:\Dev-Cpp\bin;%path%Hecho esto, ya podemos invocarMakecon el comando:make -f makefile.mySuponiendo que los ficheros de la aplicacin son correctos, despus de un instante, se obtiene la respuesta a nuestra orden:g++.exe -c main.cpp -o main.o -I"C:/DEV-CPP/lib/gcc/mingw32/3.4.2/include" -I"C:/DEV-CPP/include/c++/3.4.2/backward" -I"C:/DEV-CPP/include/c++/3.4.2/mingw32" -I"C:/DEV-CPP/include/c++/3.4.2" -I"C:/DEV-CPP/include" -fno-elide-constructorsg++.exe -c string.cpp -o string.o -I"C:/DEV-CPP/lib/gcc/mingw32/3.4.2/include"-I"C:/DEV-CPP/include/c++/3.4.2/backward" -I"C:/DEV-CPP/include/c++/3.4.2/mingw32" -I"C:/DEV-CPP/include/c++/3.4.2" -I"C:/DEV-CPP/include" -fno-elide-constructorsg++.exe main.o string.o -o "string.exe" -L"C:/DEV-CPP/lib"Adems del ejecutablestring.exe, en nuestro directorio de trabajo aparecen los ficherosmain.oystring.o, que han sido necesarios para la construccin del primero.Es significativo que si repetimos la orden anterior sin realizar absolutamente ninguna modificacin en los ficheros del proyecto, obtendramos una respuesta distinta:Nothing to be done for `all'.La razn es que, una vez construido el ejecutable y todos los ficheros intermedios necesarios,Makeencuentra que todas las dependencias son correctas y no es necesario hacer nada ms. Observe quealles el primertargetdel makefile; es justamente lo que Make intenta hacer en ausencia de alguna otra indicacin al respecto (algngoalespecfico en la invocacin1.4.0a). Sin embargo, mediante la opcin-B("Build"), es posible ordenar a Make que reconstruya el proyecto con todos sus ficheros intermedios aunque no se haya efectuado ningn cambio:make -B -f makefile.my

Como puede verse, GNU Make puede ser invocada con distintas opciones; en este caso, mediante la opcin-f, le hemos indicado que utilice nuestro scriptmake.my, en lugar del fichero por defecto (por defecto Make intenta usar los ficherosGNUmakefile,makefile, yMakefile, sin ningn sufijo y en ese orden). En caso contrario, si no existe ninguno de los ficheros citados en nuestro directorio y no se le indica ninguna opcin,Makeresponde con un mensaje de error:*** No targets specified and no makefile found. Stop.La opcin-vmuestra la versin de Make utilizada:D:\LearnC>make -vGNU Make 3.80Copyright (C) 2002 Free Software Foundation, Inc.This is free software; see the source for copying conditions.There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR APARTICULAR PURPOSE.Tambin podemos solicitar una relacin de las principales opciones. Para ello puede usarse la opcin-h("help")make -hen nuestro caso, obtenemos la siguiente salida [3]:Usage: C:\DEV-CPP\BIN\MAKE.EXE [options] [target] ...Options: -b, -m Ignored for compatibility. -B, --always-make Unconditionally make all targets. -C DIRECTORY, --directory=DIRECTORY Change to DIRECTORY before doing anything. -d Print lots of debugging information. --debug[=FLAGS] Print various types of debugging information. -e, --environment-overrides Environment variables override makefiles. -f FILE, --file=FILE, --makefile=FILE Read FILE as a makefile. -h, --help Print this message and exit. -i, --ignore-errors Ignore errors from commands. -I DIRECTORY, --include-dir=DIRECTORY Search DIRECTORY for included makefiles. -j [N], --jobs[=N] Allow N jobs at once; infinite jobs with no arg. -k, --keep-going Keep going when some targets can't be made. -l [N], --load-average[=N], --max-load[=N] Don't start multiple jobs unless load is below N. -n, --just-print, --dry-run, --recon Don't actually run any commands; just print them. -o FILE, --old-file=FILE, --assume-old=FILE Consider FILE to be very old and don't remake it. -p, --print-data-base Print make's internal database. -q, --question Run no commands; exit status says if up to date. -r, --no-builtin-rules Disable the built-in implicit rules. -R, --no-builtin-variables Disable the built-in variable settings. -s, --silent, --quiet Don't echo commands. -S, --no-keep-going, --stop Turns off -k. -t, --touch Touch targets instead of remaking them. -v, --version Print the version number of make and exit. -w, --print-directory Print the current directory. --no-print-directory Turn off -w, even if it was turned on implicitly. -W FILE, --what-if=FILE, --new-file=FILE, --assume-new=FILE Consider FILE to be infinitely new. --warn-undefined-variables Warn when an undefined variable is referenced.3.1 Probar sin arriesgarGNU Make permite comprobaciones del tipo "que tal si...". La panoplia de opciones es bastante amplia; aqu solo indicaremos alguna de ellas (consulte la seccin 9.3 del manual, "Instead of Executing the Commands", para ms informacin al respecto).Por ejemplo, la opcin-nmuestra exactamente las mismas salidas que en una invocacin normal (que comandos son invocados), pero sin que tales invocaciones ocurran realmente, de forma que no se produce ningn resultado. En nuestro caso, una invocacin del tipomake -n -f makefile.myproducira exactamente las salidas sealadas en el epgrafe anterior pero sin que se realizara ninguna accin.

Mediante la opcin-W nombre-fichero, es posible ordenar a Make que se comporte "como si" alguno de los ficheros involucrados en el makefiletuviese un "timestamp" con la fecha actual aunque en realidad no sea as. Por ejemplo, si en el caso anterior, despus de haber realizado una compilacin completa queremos simular que el ficherostrin.otiene la fecha actual, y por tanto es posterior a la destring.exe, ejecutamos el comandomake -W string.o -f makefile.zatAnte esta suposicin, Make interpreta que debe volver a enlazar los objetos para obtener una versin actualizada del ejecutable, y por tanto, ejecutar el comando de la lnea 22. El ejecutable es reconstruido y se obtiene la siguiente respuesta.g++.exe main.o string.o -o "string.exe" -L"C:/DEV-CPP/lib"Combinando las opciones anteriores es posible comprobar "qu pasara", pero sin que efectivamente se realice la reconstruccin del ejecutable:make -n -W string.o -f makefile.zat4 Radiografa de un makefile GNUA continuacin desgranamos el significado de las distintas lneas del scriptmake.myreseado antes.4.1 ComentariosLa primera y tercera lneas contienen comentarios:# Project: una clase string

CPP = g++.exe # el compilador GNU C++Cualquier contenido a continuacin del smbolo ampersand (#) es un comentario y no es tenido en cuenta por Make.4.2 MacrosLas lneas 3 a 12 inclusive contienen macros (1.4.0a)CPP = g++.exe # el compilador GNU C++OBJ = main.o string.oLINKOBJ = main.o string.oLIBS = -L"C:/DEV-CPP/lib"CXXINCS = -I"C:/DEV-CPP/lib/gcc/mingw32/3.4.2/include" \ -I"C:/DEV-CPP/include/c++/3.4.2/backward" \ -I"C:/DEV-CPP/include/c++/3.4.2/mingw32" \ -I"C:/DEV-CPP/include/c++/3.4.2" -I"C:/DEV-CPP/include"BIN = string.exeCXXFLAGS = $(CXXINCS) -fno-elide-constructorsPosteriormente, cuando estas macros aparecen en las lneas de comando, son sustituidas automticamente por su contenido. Por ejemplo, el comando de la lnea 19: ${RM} $(OBJ) $(BIN)ser transformado en:rm -f main.o string.o string.exeAl llegar aqu es conveniente recordar lo indicado en la pgina anterior respecto a las macros predefinidas (1.4.0a), donde sealbamos que GNU Make dispone, entre otras, de la macroRMpredefinida comoRM = rm -fas que la utilizamos en el comando de la lnea 19 sin haberla declarado antes. Observe que no estamos invocando ninguna opcin del shell de windows (command.com), sino el ejecutablerm.exe; un mdulo de MinGW que remeda el comando del mismo nombre del shell de Unix/Linux. Evidentemente el resultado que se pretende es borrar los ficheros resultantes de operaciones anteriores si los hubiere.Nota: es posible obtener una relacin de las macros y reglas implcitas predefinidas en GNU Make, invocndolo con la opcin-p, pero como la respuesta es bastante extensa, si est utilizando la versin MinGW para Windows, es mejor enviar la salida a un fichero auxiliar que puede ser posteriormente inspeccionado con cualquier editor de texto plano. Por ejemplo:make -p > macros.txt

Observe tambin que las lneas 7 a 10 constituyen una sola macro (la opcin-Iindica al compilador los directorios que debe explorar para encontrar los ficheros de cabecera). Lo mismo que ocurre con la sintaxis en los fuentes C++, tambin aqu es posible sealar la continuacin de una sentencia en la lnea siguiente colocando una barra invertida ( \ ) al final de la lnea.La macroCXXFLAGSde la lnea 12:CXXFLAGS = $(CXXINCS) -fno-elide-constructorscontiene todas las directivas que se pasarn al compilador para obtener los ficherosmain.oystring.o(lneas 25 y 28). Como puede verse, adems de las direcciones de los ficheros de cabecera ya mencionadas, incluimos la directiva-fno-elide-constructors, que es especfica de este proyecto. Se refiere a que el Estandar C++ permite que una implementacin omita crear objetos temporales que solo son utilizados para inicializar otros objetos del mismo tipo. Esta opcin ordena al compilador a deshabilitar esta optimizacin, forzndolo a invocar al constructor-copia en todos los casos (4.11.2d4). De forma anloga podramos haber incluido cualquier otra opcin de compilacin que fuese necesaria para nuestro proyecto (estn detalladas en el manual del compilador).Es digno de mencin que, aunque es lcito utilizar cualquier nombre para las etiquetas de las macros, es regla de buena prctica utilizar dentro de lo posible, los que ya estn predefinidos en Make con el mismo propsito (recordar lo sealado en la pgina anterior al tratar de las reglas implcitas y de las macros predefinidas1.4.0a). Esto permite utilizar las reglas implcitas y hacer nuestro texto ms legible para otros programadores. En nuestro caso,CXXFLAGSes una etiqueta que es utilizada por Make en dos de sus macros implcitas [4]. Son las siguientes:LINK.cc = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)COMPILE.cc = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -cA su vez, estas macros intervienen en las siguientes reglas y macros predefinidas:LINK.C = $(LINK.cc)LINK.cpp = $(LINK.cc)

%: %.cc # commands to execute (built-in): $(LINK.cc) $^ $(LOADLIBES) $(LDLIBS) -o $@

.cc: # Not a target. $(LINK.cc) $^ $(LOADLIBES) $(LDLIBS) -o $@

COMPILE.cpp = $(COMPILE.cc)COMPILE.C = $(COMPILE.cc)

%.o: %.cc # commands to execute (built-in): $(COMPILE.cc) $(OUTPUT_OPTION) $ 0x551 /* ... */#endif#if defined(__GNUC__) && __GNUC__ >= 3 /* ... */#endif

__CDECL__1Este valor es el indicado solo si se ha establecido que la convencin de llamada escdecl; (4.4.6a) en otro caso es indefinido.

_CHAR_UNSIGNED1Por defecto indica que el tipocharesunsigned char(2.2.1) La opcin de compilacin-Kindefine esta macro.

__CODEGUARD__Este valor est definido solo si se utiliza alguna de las opciones CodeGuard del compilador.

__CONSOLE__Cuando est definida, esta macro indica que el programa es una aplicacin de consola.

_CPPUNWIND1Este valor permite "stack unwinding" (1.6); por defecto la opcin est activada; para desactivarla hay que utilizar la opcin-xd-del compilador.

__cplusplus1Definido solo si est en modo C++.

__DATE__cadena literalContiene la fecha en que el proceso empez en el fichero actual.

__DLL__1Definido solo si se ha utilizado la opcin-WDdel compilador (generar un .DLL ejecutable [1]; lo mismo que la opcin-tWD).

__FILE__cadena literalNombre del fichero que se est ejecutando.

__FLAT__1Definido solo si se ha compilado para el modelo de uso de memoria "plano" de 32-bit (32-bit flat memory model).

__FUNC__cadena literalNombre de la funcin que se est ejecutando actualmente (ver ejemplo).Nota: el estndar C99 utiliza la constante__func__. Adems del anterior el compilador GNU g++ tambin reconoce el identificador__FUNCTION__para este menester, aunque se recomienda utilizar el primero. Este compilador tambin utiliza la constante__PRETTY_FUNCTION__, que proporciona la declaracin (signature) de la funcin. Por ejemplo, siendo el mtodofoode una claseCdefinido como:

int foo (int x) { return x*x }

el identificador__FUNCTION__contieneC::foo, mientras que__PRETTY_FUNCTION__contienevoid C::foo(int)

__LINE__decimalNmero de lnea del fichero fuente que se est ejecutando.

_M_IX861El valor por defecto es 300 (cdigo compatible con el procesador 80386), pero puede cambiarse a los valores 400 o 500 mediante la opcin /4 o /5 del compilador (1.4.3).

__MSDOS__1Constante entera.

__MT__1Definido solo si se ha utilizado la opcin-tWMdel compilador; indica que se generar cdigo 32-bit multi-hebra (igual que-WM)

__PASCAL__1Definido solo si se utiliza la convencin Pascal de llamada (4.4.6a)

__STDC__1Definido solo si de ha utilizado la opcin -A del compilador (utilizar las palabras clave y extensiones ANSI)

__TCPLUSPLUS__0x0550Nmero de versin

__TEMPLATES__1Significa que se soportan los "templates" (4.12)

__TIME__cadena literalIndica el instante de comienzo de ejecucin del fichero actual.

__TLS__1Almacenamiento local para las habras de ejecucin (siempre 1 en C++Builder)

__TURBOC__0x0550Versin actual. Puede ser modificado en futuras versiones del compilador.

_WCHAR_T1Definido solo para programas C++ (C++Builder puede compilar tambin como C); sirve para indicar quewchar_tes un tipo definido intrnsecamente (2.2.1a1)

_WCHAR_T_DEFINED1Igual que el anterior.

_WindowsDefinido para cdigo exclusivamente Windows

__WIN32__1Definido para aplicaciones de interfaz grfica y de consola.

Nota:__DATE__,__FILE__,__ FUNC__,__LINE__,__STDC__y__TIME__no pueden ser redefinidas o indefinidas (#undef).Por su parte,__DATE__,__FILE__,__ LINE__,__STDC__,__TIME__y__TIMESTAMP__son constantes manifiestas del Estndar ANSI C, por lo que es frecuente que estn presentes tambin en los compiladores C++ (estn presentes en el compilador MS Visual C++ 6.0, aunque la ltima, que proporciona la fecha y hora de la ltima modificacin del fuente actual en forma de cadena literal, no est definida en el compilador de Borland).Ejemplo de utilizacin de la constante manifiesta__FUNC__#include

int main() { printf("Esta ejecutando la funcion %s\n", __FUNC__); return 0;}Salida:Esta ejecutando la funcion mainLa constante manifiesta__FUNC__tambin puede ser utilizada en funciones miembro:#include class UNAclase { public: void UNmetodo(void) { cout cd ..D:\LearnC\planets>make -f makefile2.gnuLa respuesta es la creacin del ejecutableplanets.exey del fichero-objetomain.o. Como cabra esperar, la ejecucin del primero produce la siguiente salida:Primer planeta: MercurioSegundo planeta: VenusTercer planeta: TierraPresione cualquier tecla para continuar . . .3.2 Construir la aplicacin con Borland C++ 5.5 MakePara construir la aplicacin que utiliza nuestra librera esttica, mediante el Make de Borland, utilizamos un makefilemakefile2.borcon el siguiente diseo:# Makefile2.bor construir la aplicacin planets.exe (Borland C++ 5.5.1)

LIBS = -LE:\BorlandCPP\Lib \ -LD:\LearnC\planets\libsCXXFLAGS = -IE:\BorlandCPP\Include

all: planets.exe

planets.exe: main.cpp bcc32 -eplanets.exe $(CXXFLAGS) $(LIBS) -WC -P -Q main.cpp planets.LIB

# -P Perform C++ compile regardless of source extension# -Q Extended compiler error information (Default = OFF)# -WC Console aplicationLa nica particularidad es que hemos optado por construir la aplicacin en mediante un solo comando, de forma que el compilador Borlandgcc32.exe, se encarga de invocar sucesivamente los mdulos correspondientes. Observe que en la lnea de comando indicamos que debe incluirse la libreraplanets.LIB. A su vez, mediante la macroLIBS, sealamos las direcciones donde deben buscarse las libreras necesarias.La invocacin es anloga a la anterior:D:\LearnC\planets\libs>cd ..D:\LearnC\planets>make -f makefile2.borEn esta ocasin, el resultado incluye el ficheromain.objadems del ejecutableplanets.exe.

1.4.4b2 Libreras dinmicas1 PresentacinAntes de conocer los pormenores de la construccin y uso de unalibrera dinmica(DLL) en un programa C++, es conveniente tener una perspectiva general del mecanismo que rige su funcionamiento.Como se indic en la introduccin (1.4.4b), una librera es simplemente un trozo de cdigo que contiene recursos preconstridos; recursos que pueden ser utilizados en un ejecutable. Sin embargo, si nos fijamos un poco, vemos que esta definicin es un tanto ambigua, y puede encajar en objetos quenoson realmente libreras. En realidad, la utilizacin de recursos preconstruidos por parte de un ejecutable puede realizarse de tres formas que podramos resumir del siguiente modo: Utilizacin de libreras estticas. Es el mtodo tradicional.Como hemos sealado, son las clsicas colecciones de ficheros objeto.obj(compilados),que en el momento de la construccin de la aplicacin, son incluidos por el "Linker" en el propio ejecutable(1.4.4b1). Utilizacin de libreras dinmicas. En esta modalidad, los recursos ocupan un fichero independiente del ejecutable, que puede ser utilizado por cualquier aplicacin que lo necesite. En algn momento, durante la carga del ejecutable, o posteriormente, en run-time, el ejecutable deber integrar este bloque de cdigo en su propio espacio, de forma que pueda acceder a los recursos contenidos en l. Utilizacin de programas externos. Es tambin un recurso utilizado desde siempre en informtica. Un ejecutable puede llamar a ejecucin a otro mediante mecanismos de varios tipos. El ejecutable llamado proporciona alguna funcionalidad antes de su terminacin, y dispone de su propio espacio de ejecucin independiente del programa que lo invoc.Nota:respecto a la utilizacin de programas externos "versus" libreras dinmicas, hay que tener en cuenta que las plataformas Windows disponen de un espacio de memoria protegida para cada proceso o programa que es iniciado por el Sistema, lo que es oneroso en trmino de recursos, y origina una sobrecarga similar a la que suponen los procesos involucrados en la invocacin de funciones (4.4.6b). Por contra, las libreras dinmicas no necesitan su propio espacio, y corren en el espacio del proceso que las invoca, lo que es mucho ms rpido y ligero en trmino de recursos.

Las DLLs son trozos de cdigo capaz de realizar determinadas operaciones, cuya "funcionalidad" puede ser utilizada desde otros ejecutables, y como puede verse, ocupan una posicin intermedia (diramos que una solucin de compromiso) entre las posiciones extremas antes citadas.Con laslibreras estticascomparten la caracterstica de que es un trozo de cdigo que acaba siendo incluido en el espacio del ejecutable que las utiliza [1]. A su vez, comparten con losprogramas externosla caracterstica de que constituyen ficheros distintos y fsicamente independientes del ejecutable que los utiliza.Antes de seguir adelante, debemos puntualizar un extremo que es importante para comprender el funcionamiento de las DLLs.En realidad, la DLLnoes cargada en el espaciode memoriadel ejecutable, sino que tiene su propio espacio. Lo que ocurre es que este espacio es accesible desde el ejecutable, y est "mapeado" en l. Es decir, en el ejecutable existe un cierto "mapa" de cmo est distribuida esa zona de memoria; dnde estn sus objetos utilizables desde el exterior (exportables1.4.4b2a). Como veremos a continuacin, existen dos formas de incluir esta informacin en el ejecutable. Adems, el hecho de que la DLL disponga de su propio espacio (code segment), tiene una importante ventaja adicional: si dos o ms procesos que se estn ejecutando simultneamente en el Sistema necesitan de la misma DLL,nonecesita ser cargada dos veces en memoria. Basta que ambos tengan acceso a ella y cierto conocimiento de su estructura interna. Por esta razn, en los entornos Unix/Linux son conocidas como libreras compartidas [5].Nota:esta utilizacin del mismo cdigo por varias aplicaciones es posible porque, como se ha indicado [1], los objetos creados por la DLL no pertenecen a esta, sino al programa usuario. En otras palabras: se comparte el cdigo pero no los datos.

En realidad lo que caracteriza a una DLL es la forma en que es trada a ejecucin; no directamente desde el shell del Sistema como un ejecutable.exenormal, sino desde otro ejecutable (que puede ser incluso otra DLL), de forma parecida a como se invoca una funcin (una especie de funcin externa al programa). Por esta razn no disponen de una funcinmain(4.4.4) o de un mdulo de inicio en el sentido clsico (ver ejemplo1.4.4b2a).Al llegar aqu, es pertinente una observacin para los que han programado para entornos como MS-DOS y se adentran en el territorio de la programacin C++ con libreras dinmicas. Por ejemplo aplicaciones para MS Windows.Algunos enlazadores para DOS [3] permiten que determinadas porciones del ejecutable se siten en ficheros independientes (generalmente con terminacin .OVL), los denominados "overlays". Estos overlays son trados a memoria (cargados) automticamente segn convenga, de forma que salvo contadsimas excepciones, su funcionamiento es totalmente transparente para el programador. Por su parte, las libreras dinmicas permiten tambin que partes del ejecutable se alojen en ficheros independientes. Sin embargo, su comportamiento es mucho (muchsimo) menos flexible que su contrapartida DOS. La razn es que durante la fase de enlazado de la librera dinmica, la tabla de smbolos del que ser su ejecutable anfitrin no es accesible (ni siquiera conocido), de forma que la nica informacin que puede ser intercambiada con el exterior por el cdigo de la librera, es la que se recibe a travs de los parmetros de sus funciones y los valores devueltos por estas [7]. El resultado es que, a todos los efectos, su funcionamiento se parece ms a la invocacin de un programa externo, que una vez ejecutado, devuelve el control al programa inicial.El resultado es que si desde una DLL necesitamos utilizar una funcionalidad existente en el cuerpo del programa (una funcin o clase), no podemos accederla a menos que dicha funcin sea tambin incluida en una DLL independiente. Naturalmente esto exige que la separacin de partes del programa en DLLs se realice despus de un estudio minucioso de las funcionalidades que sern utilizadas desde cada mdulo.Como nota complementaria, debemos aadir que en este, como en muchos otros aspectos, los entornos Unix son mucho ms flexibles, ya que permiten la existencia de libreras compartidas de enlazado dinmico bidireccional automtico.2 UtilizacinDe lo dicho anteriormente se desprende que la utilizacin de los recursos contenidos en una DLL requiere dos condiciones:a.-Cargar en memoriael contenido de la DLL utilizando un espacio accesible desde el ejecutable que la utiliza. Esto puede efectuarse de dos formas:a1.- En el mismo momento de la carga inicial del programa.a2.- En el momento en que se necesite alguno de sus recursos (en runtime).b.- Conocer la topografa interna de ese trozo de cdigo para poder acceder a sus objetos.

2a1En el primer caso (a1), las DLLs requeridas por el ejecutable .EXE son cargadas, y sus objetos inicializados por el mdulo de inicio como cualquier otro mdulo del programa. Es decir, que sern inicializadas antes que comience la ejecucin demain. Cuando la aplicacin es cargada por el SO, este mira en el fichero .EXE para ver que DLLs se necesitan, y se encarga de cargarlas tambin.Veremos que este tipo de utilizacin, denominadaenlazado estticooimplcito(librera dinmica enlazada estticamente), es con diferencia la ms usual (1.4.4b2b).

2a2En el caso a2,la librera es cargada enruntimecuando la aplicacin lo necesita.Esta forma de uso se denominaenlazado dinmicooexplcito(librera dinmica enlazada dinmicamente). Para realizar la carga, el programador dispone de algunas funciones de la API de Windows que se encargan de realizar la tarea cuando l lo decide (de ah que se denomine enlazado explcito).

Cualquiera que sea la forma de carga elegida, implcita o explcita, el orden de bsqueda seguido por el Sistema para localizar el fichero (.dll) a cargar, es siempre el mismo: En el directorio que contiene el ejecutable (fichero .EXE)Fig. 1

Fig. 2

El directorio actual de la aplicacin [4]. El directorio de sistema de Windows El directorio de Windows Los directorios incluidos en la variable de entornoPATHdel Sistema.Si en unacarga implcitael Sistema no encuentra el fichero .DLL en ninguno de los sitios anteriores, se muestra un mensaje de error y la aplicacin no puede ejecutarse (fig. 1).En caso de que fracase la carga del fichero durante lacarga explcita, si el Sistema devuelve un error, es potestad del programador decidir que hacer. La figura 2 es un ejemplo tomado de una aplicacin real cuando no aparece la .DLL requerida [6].El orden de carga mencionado es el que podramos llamar "clsico"; de las versiones de Windows anteriores a XP SP1. A partir de esta, el orden se modific, de forma que la bsqueda no comienza en el directorio que contiene el ejecutable, sino en los directorios de Windows. La razn est relacionada con la seguridadhttp://msdn.microsoft.com/. Incluimos el prrafo ms significativo:"DLL Search Order Has Changed

No longer is the current directory searched first when loading DLLs! This change was also made in Windows XP SP1. The default behavior now is to look in all the system locations first, then the current directory, and finally any user-defined paths. This will have an impact on your code if you install a DLL in the application's directory because Windows Server 2003 no longer loads the 'local' DLL if a DLL of the same name is in the system directory. A common example is if an application won't run with a specific version of a DLL, an older version is installed that does work in the application directory. This scenario will fail in Windows Server 2003.

The reason this change was made was to mitigate some kinds of trojaning attacks. An attacker may be able to sneak a bad DLL into your application directory or a directory that has files associated with your application. The DLL search order change removes this attack vector."

2bEs evidente, que una vez cargado el cdigo de la DLL, el programa anfitrin necesita conocer las direcciones de los recursos contenidos en esa zona de memoria para poder acceder a ellos. El procedimiento es distinto segn el mtodo de carga utilizado:En el caso delibrera dinmica enlazada estticamente, se construye una librera tradicional (.LIB) de un tipo especial denominado librera de importacin, que es enlazada estticamente con el ejecutable (formando parte de l). La librera de importacin no contiene cdigo, en realidad es un ndice o tabla de dos columnas. En la primera estn los nombres de las funciones exportables de las DLLs; la segunda est vaca, pero cuando las libreras son cargadas en memoria durante el proceso de carga del ejecutable, el programa cargador ya puede conocer las direcciones de estos recursos, y completa la segunda columna de la tabla con las direcciones adecuadas. De esta forma, el ejecutable puede acceder a los recursos de la DLL con solo conocer los nombres adecuados.En el caso delibrera dinmica enlazada dinmicamente, una vez realizada la carga mediante las funciones correspondientes, la API del Sistema dispone de una funcin especficaGetProcAddress(), que permite obtener punteros a las funciones de la DLL que deban utilizarse.Es necesario mencionar que para obtener las direcciones de los recursos dentro del bloque de cdigo de la DLL, tanto el programa cargador como la funcinGetProcAddressde la API, utilizan a su vez una tabla que acompaa a cualquier librera dinmica, latabla de entrada("entry table"1.4.4b2a).3Tabla de inicioCuando se compila cualquier mdulo, en el objeto resultante existe un segmento denominado_INIT_que contiene una referencia ("Init entry") al constructor de cada objeto global que deba ser inicializado, as como un orden de prioridad. Ms tarde, cuando el enlazador construye un ejecutable, estas entradas se agrupan en una tabla, latabla de inicio("Init table") que contiene ordenadamente todas las entradas de los constructores de los objetos que existen en los mdulos que componen el programa. Finalmente, esta tabla es utilizada por el mdulo de inicio cuando el programa es iniciado.En el caso de que este ejecutable sea una librera de enlazado dinmico, el orden de estas entradas en la tabla depende de dos factores:su prioridad, y el orden en que se encuentren los mdulos-objeto en la orden de enlazado. Por ejemplo, si la orden de enlazado incluye tres objetosA.o,B.oyC.o, cada uno de los cuales tiene tres objetos globales cuyos constructores tienen entradas en el segmento_INIT_de su mdulo con la misma prioridad (supongamos que 0x20), al construir la librera, puesto que sus prioridades son idnticas, el orden en que sern inicializados dichos objetos depender del orden de los mdulosA,ByCen la orden de enlazado. Cambiando este orden puede alterarse el orden en que se invocan los constructores de los objetos correspondientes.Las libreras dinmicasenlazadas estticamentea un ejecutable, son inicializadas junto con el resto de mdulos del programa, por el mdulo de inicio (1.5) del ejecutable antes que comience la ejecucin demain(oWinMain). Esto supone que cualquier directiva#pragma startup(4.9.10i) existente en los mdulos .OBJ que componen la librera ser ejecutada, y que todas sus variables estticas, sern inicializadas segn el orden precedente.En el caso de que la DLL tengaenlazado dinmico, la inicializacin solo se realiza cuando es cargado el mdulo (.DLL).

4Recordarque para usar las funciones contenidas en una librera (esttica o dinmica) se necesitan tres condiciones: Un prototipo que permita conocer el nombre del fichero que compone la librera, su localizacin, parmetros y tipo de retorno de la funcin de librera que queramos utilizar (esto es lo normal para utilizar cualquier funcin4.4.1). En el caso de libreras que contienen clases predefinidas, esta condicin se sustituye por el conocimiento de la interfaz de la clase. Disponer de los tipos de datos que pasarn como argumentos (tambin normal para cualquier funcin). En el caso de funciones, poder utilizar la convencin de llamada que corresponda a la librera en cuestin. Es decir, que el enlazador C++ utilizado permita usar la convencin de llamada adecuada, de forma que estos mdulos externos puedan ser llamados a ejecucin desde nuestro programa [2]

1.4.4b2a Construir una DLL1 SinopsisEn este epgrafe tratamos los detalles necesarios para construir unalibrera dinmica; un tipo especial de cdigo ejecutable cuyos recursos pueden ser utilizados desde otros ejecutables. Entre los usuarios pueden incluirse quizs el propio Sistema Operativo (caso de Windows por ejemplo) u otras libreras. Aunque hemos sealado que tales libreras pueden tener cualquier terminacin (1.4.4b), aqu las denominaremosDLLs, apelativo por el que son ms conocidas.Nota: recordar que el Estndar C++ no indica nada respecto a estas libreras, ya que las particularidades del enlazado dinmico dependen del SO (de la plataforma) y poco que ver con el lenguaje en que hayan sido programadas. En particular, las DLLs son especficas de los SOs de Microsoft, aunque por supuesto, otros SOs utilizan tambin libreras dinmicas.2Construccin de una DLLCuando se construye un fuente que ser compilado para producir una DLL, los objetos (funciones y clases) que deban ser accesibles desde otros ejecutables, se denominanexportables, tambincallbackssi son funciones, en atencin a una denominacin muy usual en la literatura inglesa ("callback functions" [3]). Esta circunstancia debe ser conocida por el compilador, por lo que es necesario especificar qu recursos se declaran "exportables"; adems debe instruirse al "linker" para que genere una librera dinmica en vez de un ejecutable normal. En el caso de BC++, esto ltimo se consigue con las opciones de compilacin-WD/-tWDy-WR/-tWR.Ver ejemplos.Nota: al tratar de la utilizacin de libreras dinmicas, veremos que de forma simtrica a lo sealado, desde la ptica del ejecutable que utiliza la librera, estos recursos se denominanimportables, y como tales deben tambin ser sealados al compilador.

El enlazador MinGW dispone de dos opciones:--no-undefinedy--enable-runtime-pseudo-reloc, que permiten despreocuparse de la necesidad de declarar exportables o importables los atributos de los objetos cuando se crean o utilizan libreras dinmicas. La razn es que su presencia hace que todas las funciones sean automticamente exportadas/importadas por defecto.En los compiladores para la plataforma Windows existen varias formas para declarar una funcin o recurso como exportable, pero aqu nos ceiremos a dos de las ms simples y directas, los especificadores_exportydllexport.

Adems delos fuentes de la librera, en determinados casos, la creacin de una DLL exige la existencia de dos ficheros auxiliares: unalibrera de importacin(1.4.4b2c) y unfichero de definicin.def("definition file") al que ya nos hemos referido (1.4.4a). La primera es una librera esttica clsica (.libo.a) que sirve como ndice o diccionario de la dinmica. El segundo es un fichero ASCII [6]. En caso de ser necesarios, la creacin de estos ficheros auxiliares se realiza generalmente en el mismo momento en que se crea la librera. Sin embargo, en determinadas circunstancias, especialmente cuando se dispone de una DLL construida de la que no se tienen los fuentes, la creacin exige de herramientas auxiliares.La necesidad de tales ficheros depende del compilador y de las circunstancias. La documentacin de Microsoft seala que generalmente, la librera de importacin es necesaria para usar la librera con enlazado esttico, pero no para enlazado dinmico (explcito).En cambio, la documentacin de MinGW seala: "la librera de importacin es necesaria si (y solo si) la DLL debe ser utilizada por un compilador distinto de la coleccin de herramientas MinGW, ya que estas son perfectamente capaces de enlazar con sus DLLs sin necesidad de ningn recurso auxiliar".Nota:en ocasiones, cuando el objeto descrito no es una DLL normal, sino un control ActiveX, un servidor OLE, o un servidor COM, la librera no se denomina "de importacin".En su lugar se utiliza el trminolibrera de tipos(1.4.4b2d).2.1Tabla de entradasCualquiera que sea la forma utilizada, los recursos declarados exportables son incluidos por el enlazador en una tabla especial contenida en la DLL, que se denominatabla de exportacin("export table") otabla de entrada("entry table"). Esta tabla juega aqu un papel similar aldiccionario(1.4.4b) de las libreras estticas (ojo, no confundirla con la librera de importacin citada en el epgrafe anterior).La tabla de exportacin tiene dos tipos de datos importantes (en realidad son dos tablas):losnombrescon que aparecen los recursos [2] y unnmero de orden. Cuando una aplicacin (.exe o librera dinmica) invoca una funcin situada en una librera, el mdulo que realiza la invocacin puede referirse al recurso pornombreo pornmerode orden. Por supuesto la segunda forma es ligeramente ms rpida, ya que no se necesitan comparaciones de cadenas para localizar la entrada.Cuando un recurso es exportado por nmero, la parte de nombres de la tabla no necesita ser residente en la memoria del ejecutable que la utilizar. En cambio, si es exportada por nombres, dicha tabla s necesita ser residente, y ser cargada en memoria cada vez que el mdulo sea cargado [1].Nota:el compilador Borland C++ dispone de la utilidadIMPDEF, que permite conocer las entradas de la tabla de exportacin de una DLL (1.4.4b2c).Como ocurre con muchos otros aspectos de los ejecutables, es posible indicar al enlazador ciertos detalles sobre los nombres, orden con que queramos que aparezcan estos recursos en la mencionada tabla y permanencia de la misma en memoria (1.4.4a).A su vez, MS dispone de una utilidad gratuita denominadaDependency Walker, que permite analizar cualquier mdulo Windows de 32 o 64 bits (.exe, .dll, .sys, .ocx, etc) y construir un organigrama jerrquico con las dependencias existentes entre sus diversos mdulos. Para cada mdulo encontrado, se muestran las funciones exportadas y cuales de ellas son utilizadas por otros mdulos. Otro esquema muestra el mnimo conjunto de ficheros requeridos incluyendo informacin detallada sobre cada uno de ellos. Es una herramienta insustituible para situaciones en que se obtienen errores relacionados con la carga y ejecucin de los distintos mdulos de una aplicacin.http://dependencywalker.com/Es importante recordar, sobre todo si vamos a construir DLLs que sern utilizadas por terceros, que los nombres de los recursos exportados no pueden colisionar con ningn otro nombre utilizado por el programa o por otra DLL del sistema, de forma que debemos asegurarnos que estos nombres sern nicos.2.2 Especificador_exportTanto si se usa el copilador C++ Borland como Visual de MS, los recursos "exportables" pueden ser declarados con los especificadores_exporto__export(son equivalentes).Nota:recordemos que C++ dispone de una palabra clave especfica:export(4.12.1-2) cuyo significado se asemeja al que utilizamos aqu: "indica al compilador que la declaracin ser accesible desde otras unidades de compilacin". Sin embargo, tener en cuenta que_exportyexportno tienen nada que ver entre s.La primera es una particularidad de ciertos compiladores; la segunda es una palabra clave del C++ Estndar.SintaxisSon posibles tres formas, segn que el recurso a exportar sea una clase, funcin o variable normal:__export valor-devuelto nombre-funcion (argumentos); // Ilegal !!valor-devuelto __export nombre-funcion (argumentos);valor-devuelto _export nombre-funcion (argumentos);2.2.1aclass _export nombre-de-clase; 2.2.1btipo-de-dato _export nombre-de-variable; 2.2.1cEjemplos:extern "C" _export double MayorValor(double, double);class _export miClase;double _export db;Nota:si se utiliza el especificador_export, para exportar una funcin, dicha funcin debe ser exportada por nombre en vez de por nmero de orden (2.1).2.3 EspecificadordllexportLos recursos "exportables" pueden ser tambin declarados mediante el especificador__declspec(dllexport) (4.4.1b).SintaxisExisten dos formas:__declspec(dllexport) valor-devuelto funcion (argumentos);2.3.1aclass __declspec(dllexport) nombre-de-clase;2.3.1b__declspec(dllexport) tipo-de-dato nombre-de-variable;2.3.1cEjemplos:extern "C" __declspec(dllexport) double MayorValor(double, double);class __declspec(dllexport) A { /* ... */ };__declspec(dllexport) int x;3Ejemplode construccin de Librera DinmicaPara ilustrar el proceso de creacin de una librera dinmica con un ejemplo concreto, utilizaremos una modificacin de los ficheros utilizados anteriormente para construir una librera esttica (1.4.4.b1). Suponemos que los fuentes y la cabecera que siguen estn situados en el directorioD:\LearnC\planets\dlibs(observe que no existe una funcinmainoWinMainen ninguno de los ficheros).// planets.cpp

#include

bool WINAPI DllMain (HINSTANCE hInst, DWORD dwd, LPVOID lpv ) { return true;}// planet1.cpp

#include

extern "C" __declspec(dllexport) void showMercury () { std::cout set PATH=E:\BORLAN~1\BIN;%path%D:\LearnC\planets\dlibs>make -f makefil.borSi las cosas funcionan como es de suponer, junto con algunos ficheros auxiliares (que pueden ser borrados), se obtienen la librera dinmicaplanetsB.dlly la de importacinplanetsB.lib. Recuerde que junto a estos ltimos, la cabeceraplanets.htambin debe ser distribuida a los usuarios potenciales de la librera.Nota: ver unfichero de definicin(1.4.4a), obtenido a partir del la libreraplanetsB.dllaqu construida (1.4.4b2c).

1.4.4b2b Usar una DLL1 SinopsisEn contra de lo que ocurre en su construccin, que sigue un proceso nico con independencia de como vaya a ser utilizada ms tarde (1.4.4b2a),existen varias formas de utilizar los recursos de una librera dinmica desde otro ejecutable.En el presente captulo se exponen los detalles de su utilizacin, incluyendo ejemplos de construccin de una aplicacin que utiliza los recursos de las DLLs de la pgina anterior.2 GeneralidadesEl acceso desde un ejecutable a un identificador definido en una DLL, como puede ser la invocacin de una funcin o la utilizacin de una clase de librera, se denominaimportary el objeto "importable". La razn de este apelativo es obvia:el programa debe disponer de un mecanismo (cargador) que permita cargar en memoria la DLL, para a continuacin, acceder a dicho recurso que se encuentra fuera del ejecutable (recuerde todos los ejecutables deben ser previamente cargados en memoria). De forma recproca, el hecho de hacer accesibles desde el exterior determinados recursos de una librera se denominaexportar, y dichos objetos se declaranexportables.Evidentemente, adems de ser cargadas, tales libreras deben enlazarse de alguna forma con los ejecutables que utilicen sus recursos.Veremos que existen dos modalidades para este enlazado. De otro lado, tambin resulta evidente que el programa usuario debe tener algn modo de declarar al compilador que determinadas funciones o recursos son "importados", es decir, que estn en libreras dinmicas y por tanto, su acceso es un tanto especial.Nota: existen herramientas que permiten conocer las libreras dinmicas utilizadas por un ejecutable. Por ejemplo, la utilidadtdumpdel compilador BC++.3Declarar un recurso importadoEn el caso de las plataformas BC++, MSVC y GNU MinGW para Windows, la declaracin de que un recurso se encuentra en una librera dinmica, y por tanto es "importado", puede hacerse de dos formas, que como se ver, son simtricas de las utilizadas en la construccin (1.4.4b2a) para declarar que un recurso es exportable.a.- Utilizar el declarador_importb.- Utilizar el declarador_declspec(dllimport)3.1 Especificador_importLos recursos "importados" pueden ser declarados con los especificadores_importo__import(son equivalentes).SintaxisSon posibles tres formas, segn que el recurso a importar sea una funcin, una clase o una variable normal:valor-devuelto _import nombre-funcion (argumentos);3.1.1aclass _import nombre-de-clase; 3.1.1btipo-de-dato _import nombre-de-variable; 3.1.1cEjemplos:extern "C" _import double MayorValor(double, double);class _import miClase;double _import db;3.2EspecificadordllimportLos recursos importados pueden ser tambin declarados mediante el especificador__declspec(dllimport) (4.4.1b).SintaxisExisten dos formas:__declspec(dllimport) valor-devuelto funcion (argumentos);3.2.1a__declspec(dllimport) tipo-de-dato nombre-de-variable;3.2.1bEjemplos:extern "C" __declspec(dllimport) double MayorValor(double, double);__declspec(dllimport) int x;3Tipos de enlazadoAtendiendo a la forma en que se relaciona la DLL con el ejecutable que deba utilizar sus recursos, existen dos formas de enlazado:estticoydinmico, ya citados en el captulo anterior (1.4.4), pero cuyo significado cuando se refiere a libreras dinmicas tiene algunos matices que repasaremos aqu.

3.1DLL enlazada estticamente. Significa que la DLL estar siempre presente (cargada) cuando corra el ejecutable.Para ello, algunos compiladores exigen la utilizacin de una librera esttica auxiliar (.LIB), denominadalibrera de importacin[1], que es enlazada estticamente con el ejecutable.Esta librera auxiliar contiene referencias a la DLL (1.4.4b2c). En otros casos, estas referencias son incluidas por el enlazador en el ejecutable en base a la informacin extrada directamente de la librera.En cualquier caso, el fichero ejecutable contiene las referencias que momentneamente no estn resueltas, pero en cuanto comienza la ejecucin, la DLL es cargada en memoria y las referencias pueden ser resueltas. Las DLLs enlazadas estticamente a un ejecutable .EXE son cargadas e inicializadas por el mdulo de inicio como cualquier otro mdulo del programa (sin que el programador tenga que hacer nada especial al respecto). Es decir, que sern inicializadas antes que comience la ejecucin demain.Nota:no confundir lo anterior "librera dinmica enlazada estticamente" con "librera de enlazado esttico".Esto ltimo significa que se ha enlazado una librera esttica (1.4.4b1), generalmente con extensiones.ao.lib, que contiene recursos (.OBJ) que se han incluido en el ejecutable durante el proceso de enlazado.

3.2DLL enlazada dinmicamentesignifica que su carga se realiza solo en el momento en que es necesitada por el ejecutable.Este tipo de librera es inicializada solo en el momento de la carga, siendo el programador responsable de decidir el momento de carga y eventualmente el de descarga.En el caso de Windows, para la carga pueden utilizarse dos funciones de la API del sistema:LoadLibrary() yLoadLibraryEx(). La segunda permite establecer algunas particularidades sobre la forma en que se realizar la carga.Para la descarga puede utilizarseFreeLibrary(); tienen el siguiente aspecto:HINSTANCE LoadLibrary(LPCTSTR);HINSTANCE LoadLibraryEx(LPCTSTR, HANDLE, DWORD);BOOL FreeLibrary(HMODULE);4Formas de usoSegn lo anterior, son posibles dos posibilidades de uso de una librera dinmica:a.-Librera dinmica (DLL) enlazada estticamente. En ocasiones, mediante unalibrera de importacin.LIB que referencia la DLL. Para esto solo hay que enlazar la mencionada librera de importacin con el resto de las que componen el ejecutable.b.-Librera dinmica (DLL) enlazada dinmicamente. Esto puede hacerse de dos formas:b1.- Enlazando la librera estticamente mediante la librera de importacin (como en el caso anterior), pero utilizando la opcin decarga retrasada(1.4.4b2e).b2.- Utilizando las funciones ya citadas de la API de windows:LoadLibrary() yLoadLibraryEx(). A continuacin, se utilizaGetProcAddress() para obtener punteros individuales a los recursos que deban utilizarse.

Para ilustrar el proceso con ejemplos concretos, construiremos sendos ejecutables que utiliza las libreras dinmicas creadas en la pgina anterior (1.4.4.b2a). Ambas utilizan sendos fuentes situados en el directorioD:\LearnC\planets. La primera versin utiliza carga esttica, es el fuentemainE.cpp; la otra, correspondiente al fuentemainD.cpputiliza carga dinmica. Ambas versiones construirn de dos formas; utilizando el compilador C++ GNU y el de Borland.4.1Utilizar una librera dinmica con carga estticaLa aplicacin consta de un solo ficheromainE.cppcon el siguiente diseo:// mainE.cpp

#include #include

#include "dlibs/planets.h"

int main(int argc, char *argv[]) { showMercury(); showVenus(); showEarth();

system("PAUSE"); return EXIT_SUCCESS;}Observe que el fuente es exactamente anlogo al utilizado para el uso de libreras estticas (1.4.4b1) y que, aparte de la utilizacin del fichero de cabecera correspondiente, nada hace presagiar que utilizaremos una librera dinmica. Recuerde que el ficheroplanets.h, junto con el resto de los utilizados para crear la librera, estn enD:\LearnC\planets\dlibs.

4.1.1Con GNU MakePara construir un ejecutable que utilice la referida librera dinmica con carga esttica, utilizamos un makefilemakefilE.gnusituado en el directorio del fuente anterior:# MakefilE.gnu Uso de planetsG.dll# crear aplicacin planetsE.exe usando librera dinmica con enlazado esttico

LIBS = -L"C:/DEV-CPP/lib"CXXFLAGS = -I"C:/DEV-CPP/lib/gcc/mingw32/3.4.2/include" \ -I"C:/DEV-CPP/include/c++/3.4.2/backward" \ -I"C:/DEV-CPP/include/c++/3.4.2/mingw32" \ -I"C:/DEV-CPP/include/c++/3.4.2" -I"C:/DEV-CPP/include"

planetsE.exe: mainE.o g++ mainE.o -o "planetsE.exe" $(LIBS) dlibs/planetsG.dll

mainE.o: mainE.cpp g++ -c mainE.cpp -o mainE.o $(CXXFLAGS)La ltima regla simplemente obtiene el fichero objetomainE.o, que ser enlazado para obtener el ejecutable. La construccin se realiza en el comando de la primera regla; en ella, a travs de compilador, le indicamos al enlazador que incluya nuestra librera junto con el objeto de la aplicacin.La invocacin de make para la construccin del ejecutable se realiza de forma anloga a la utilizada para la construccin de la librera:D:\LearnC\planets>make -f makefilE.gnuComo resultado se obtiene el objetomainE.oy el ejecutable deseado,planetsE.exe, cuya ejecucin proporciona desde luego las mismas salidas que cuando se utiliz una librera esttica.Primer planeta: MercurioSegundo planeta: VenusTercer planeta: TierraPresione cualquier tecla para continuar . . .

Como se ha sealado, si todo el proceso se ha realizado con las herramientas MinGW, no es necesaria la librera de importacin, pero si no fuese este el caso. Por ejemplo, porque la DLL hubiese sido construida con otro compilador, podramos compilar con la librera de importacinplanets.a, en lugar de con la DLL (la suponemos en el directoriodlibs). Para esto bastara modificar ligeramente la primera regla del makefile anterior que quedara como sigue:planetsE.exe: mainE.o g++ mainE.o -o "planetsE.exe" $(LIBS) dlibs/planets.aNota: en la pgina dedicada a las libreras de importacin, se indica cmo obtener una de estas libreras a partir de una DLL existente (1.4.4b2c).4.1.2Con Borland 5.5 MakePara la construccin de nuestro ejecutable, que usar la librera dinmica creada en la pgina anterior (1.4.4b2a) mediante un enlazado implcito (esttico), utilizamos un makefile,makefilE.bor, situado en el mismo directorio que el fuentemainE.cpp.# MakefilE.bor para Borland C++ 5.5.1# crear aplicacin planetsE.exe usando librera dinmica con enlazado esttico

LIBS = -LE:\BorlandCPP\Lib

all: planetsE.exe

planetsE.exe: mainE.cpp dlibs\planetsB.lib bcc32 -eplanetsE.exe $(LIBS) -WCR -P -Q mainE.cpp dlibs\planetsB.lib

# -P Perform C++ compile regardless of source extension# -Q Extended compiler error information (Default = OFF)# -WCR Console aplicationObserve que, aparte de la indicacin de incluir la libreraplanetsB.liben el ejecutable, en la compilacin no existe ninguna mencin a la librera dinmicaplanetsB.dllque se utilizar en runtime (el nombre de esta DLL est incluida en la informacin aportada por la librera de importacin).La invocacin de make es como siempre:C:\Windows>D:D:\>cd LearnC\planets\D:\LearnC\planets\>set PATH=E:\BORLAN~1\BIN;%path%D:\LearnC\planets\>make -f makefilE.borUna vez construido el ejecutableplanetsE.exe, su ejecucin solo exige de la presencia del propio ejecutable y de la DLL correspondienteplanetsB.dll(la librera de importacinplanetsB.libno es necesaria).4.2Utilizar una librera dinmica con carga dinmicaLa utilizacin de una librera dinmica con carga dinmica (explcita) en nuestra aplicacin, exige ciertas modificaciones en el fuente respecto al diseo utilizado para la carga esttica. El fichero del nuevo fuente sermainD.cppsituado en el mismo directorio que el anterior:D:\LearnC\planets.// mainD.cpp// usar librera dinmica con enlazado dinmico

#include #include #include #include "dlibs/planets.h"

typedef void __stdcall (* FPTR)();

int main(int argc, char *argv[]) { HMODULE dllHandle = LoadLibrary("planetsX.dll"); // cargar librera [2] if (!dllHandle) { std::cout