Disponible la nueva versión "donationware" 7.3 de OrganiZATOR
Descubre un nuevo concepto en el manejo de la información.
La mejor ayuda para sobrevivir en la moderna jungla de datos la tienes aquí.

Curso C++

[Home]  [Inicio]  [Índice]


1.4.4b2c  Librería de importación

§1  Sinopsis

Las librerías de importación son librerías estáticas de terminación clásica .lib o .a, que no contienen código objeto, solo tablas. Cada entrada contiene el nombre de una DLL y la dirección de un recurso exportable dentro de la DLL. Por ejemplo, una función dllexport de la librería. Generalmente estas direcciones están en forma de números.

Nota: los compiladores C/C++ pensados para escribir aplicaciones que correrán en la plataforma Win32 incorporan algunas de estas librerías con las direcciones de los recursos de la API de Windows (que está constituida por un conjunto de DLLs). Entre las más frecuentes de estas librerías de importación están: IMPORT32.LIBKERNEL32.LIBUSER32.LIB, y GDI32.LIB.


Estas librerías se enlazan estáticamente con la aplicación que debe utilizar los recursos de la DLL, de forma que el cargador del ejecutable (que debe cargar también las librerías) puede resolver las invocaciones a los recursos contenidos en ellas.  El juego es como sigue: supongamos tres funciones func1(); utilA() y utilB(); la primera está en la librería dinámica LibF.dll, las otras dos en LibU.dll. Supongamos que deseamos construir una aplicación, Apli.exe, que debe utilizar dichas funciones. A su vez, los fuentes de la aplicación están en los ficheros Main.cpp y Utils.cpp.

Una forma de proceder sería construir una librería de importación, digamos Mi.LIB, con información sobre la localización de las tres funciones externas. Una vez construida, la librería se enlazaría junto con el resto de los módulos para conseguir un ejecutable. Por ejemplo, con el compilador de BC++ podría utilizarse el siguiente comando [1]:

BCC32 -IC:\BCPP\Include -LC:\BCPP\Lib Main.CPP Utils.CPP Mi.LIB -eApli


La construcción de una librería de importación como Mi.LIB puede hacerse de varias formas.  La más simple es crearla en el momento de crear la librería, pero también puede ser creada posteriormente a partir de la DLL (cuando no se dispone de los fuentes) mediante herramientas especiales. Por ejemplo, en Borland C++, mediante una utilidad denominada implib , y en GNU mediante la utilidad dlltool, que suele estar incluida junto con las "binutils" del compilador .

§2  Utilidad impdef

El compilador Borland C++ dispone de la utilidad IMPDEF que permite obtener un fichero .DEF de definición a partir de una librería .DLL; este fichero contiene una sección EXPORTS con los nombres de todos los recursos exportables de la librería.

Nota:  El nombre de esta utilidad es acrónimo de "Import Definition", ya que se trata de un manejador de ficheros de definición .DEF.

§2.1  Sintaxis

IMPDEF FicheroDestino.DEF NombreLibreria.DLL

§2.2  Comentario

Esta orden crea un fichero de definición de nombre FicheroDestino.DEF a partir del fichero NombreLibreria.DLL. El fichero .DEF tiene el siguiente aspecto:

LIBRARY NombreLibreria
DESCRIPTION 'Descripcion'
EXPORTS
  Nombre_de_funcion_exportable @Ordinal
  .
  .
  .
  Nombre_de_funcion_exportable @Ordinal

Con el significado siguiente:

  NombreLibreria es el nombre que aparece en la variable NAME de la sección de cabecera de la librería analizada (ver Fichero de definición 1.4.4a).

  Descripcion es el valor de la sección DESCRIPTION si la librería DLL fue enlazada utilizando un fichero de definición .DEF que incluía una sentencia DESCRIPTION.

  Nombre_de_funcion_exportable  Es el nombre de cada función exportable de la librería analizada.

  Ordinal es un entero que expresa el orden de dicha función.

La utilidad acepta los siguientes comandos de ejecución:

-a Añade un guión bajo '_'  al nombre de las funciones declaradas cdecl para compatibilidad con las librerías de Microsoft.
-h Añade algunas indicaciones extra
§2.3 Ejemplo:

Para aplicar la utilidad IMPDEF a la librería planetsB.dll construida en el ejemplo §3.2 de la página anterior ( 1.4.4b2a), se utilizaría el siguiente comando:

IMPDEF planetsB.DEF palentsB.DLL

Obteniéndose un fichero planetsB.DEF con el siguiente contenido:

LIBRARY PLANETSB.DLL

EXPORTS
    ___CPPdebugHook             @4   ; ___CPPdebugHook
    _showEarth                  @3   ; _showEarth
    _showMercury                @1   ; _showMercury
    _showVenus                  @2   ; _showVenus

§3  Utilidad implib

El compilador Borland C++ dispone de la utilidad IMPLIB que permite crear librerías de importación a partir de una o varias DLLs y/o ficheros de definición .DEF ( 1.4.4a).

§3.1  Sintaxis

 IMPLIB Opciones LibName [ DefFiles... | DLLs... ] [@ResponseFile] 


  Opciones es una lista de uno o más comandos opcionales, que pueden ser los siguientes:

-a Añade un guión bajo '_'  al nombre de las funciones declaradas cdecl ( 4.4.6a) para compatibilidad con las librerías de Microsoft.
-c Avisos para los símbolos sensibles a mayúsculas/minúsculas ("Case sensitive")
-f Forzar importación por nombre
-w No indicar mensajes de aviso

  LibName es el nombre de la librería de importación que se creará.

  DefFiles es una lista de uno o varios ficheros de definición .DEF ralativos a la/s librerías utilizadas.

  DLLs es una lista de una o varias librerías dinámicas cuya librería de importación se pretende crear (no tienen que ser necesariamente de terminación .DLL, pueden ser .EXE, .DRV, etc).

  ResponseFile es una lista de respuesta ("Response file"). Se trata de un fichero de texto plano (ASCII) que contiene una lista de los ficheros .DEF y DLLs que se quieren procesar. Puede ser útil cuando esta lista es muy numerosa, de forma que no es necesario escribir una línea de comando muy larga. Los nombres de ficheros de la lista deben ir separados por espacios o nueva línea NL (ASCII 10 2.2.1a).

En la línea de comando el nombre de la lista de respuesta debe ir precedido del carácter arroba '@'.  Por ejemplo:

 IMPLIB -w LibPrincipal.LIB @ResFiPr.txt 

§3.2 Ejemplo:

Para obtener la librería de importación planetsB.lib a partir de la DLL planetsB.dll construida en el ejemplo de construcción de una librería dinámica con Borland C++ 5.5 Make ( 1.4.4b2a), se utilizó el comando:

    implib -c planetsB.lib planetsB.dll

§4 Utilidad dlltool

Esta utilidad acompaña a las "binutils" del compilador GNU gcc. Es utilizada para crear los ficheros necesarios para construir y usar DLLs. La utilidad solo se incluye en los paquetes destinados a soportar DLLs (los destinados a correr en las plataformas Windows de MS).  En lo que sigue, nos referimos a dlltool.exe, la versión que acompaña al compilador GNU c++ de MinGW (ver recuadro en 1.4.0a1).

La utilidad dlltool puede ser utilizada de muchas formas; a continuación incluimos un ejemplo de la más usual: cuando tenemos una librería estática somelib.dll de la que no son accesibles los fuentes y que se resiste a compilar con alguna de nuestras aplicaciones que la necesita (quizás por estar construida con un compilador distinto del que utilizamos -el mencionado GNU c++ de MinGW para Windows-).  En estos casos la solución puede consistir en compilar nuestra aplicación "con" ("against" en la literatura inglesa) una librería de importación somelib.a construida a partir de la mencionada DLL con ayuda de dlltool.

Para abreviar la exposición, utilizaremos las librerías y aplicaciones de ejemplos anteriores. En concreto, los incluidos en los capítulos "Construir una DLL" ( 1.4.4b2a) y "Usar una DLL" ( 1.4.4b2b).  Como resumen, recordemos que se construyó una DLL con dos compiladores: GNU c++ y BC++  (Borland C++ 5.5).  A continuación se construyó una aplicación que utiliza las citadas librerías. La aplicación se construye también con ambos compiladores y en sus dos versiones de enlazado para cada caso, implícito y explícito.

El resumen de ficheros obtenidos es el siguiente:

Fichero Compilador tamaño Bytes Descripción
planetsG.dll GNU gcc 483.328 Librería dinámica
planetsB.dll Borland C++ 8.192 Librería dinámica
planetsE.exe GNU gcc 16.384 Usa planetsG.dll con enlazado implícito 
planetsD.exe GNU gcc 479.232 Usa planetsG.dll con enlazado explícito
planetsE.exe Borland C++ 8.192 Usa planetsB.dll con enlazado implícito
planetsD.exe Borland C++ 8.192 Usa planetsB.dll con enlazado explícito

Suponemos que no disponemos de la versión GNU de la librería (planetsG.dll) y necesitamos utilizar la versión BC++ disponible (planetsB.dll) para construir un ejecutable que usará enlazado explícito con la citada librería. Para ello, modificamos convenientemente el makefile makefilE.gnu ( 1.4.4b2b):

# MakefilE.gnu (modificado) Uso de librería Borland planetsB.dll
# crear aplicación planetsE.exe usando librería dinámica con enlazado estático

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/planetsB.dll

mainE.o: mainE.cpp
     g++ -c mainE.cpp -o mainE.o $(CXXFLAGS)

La invocación de este makefile produce los siguientes errores:

mainE.o(.text+0x2b):mainE.cpp: undefined reference to `_imp__showMercury'
mainE.o(.text+0x32):mainE.cpp: undefined reference to `_imp__showVenus'
mainE.o(.text+0x39):mainE.cpp: undefined reference to `_imp__showEarth'

lo que indica que la versión "tal cual" de la DLL no se entiende bién con nuestro compilador GNU g++. Para resolver el problema, crearemos una librería de importación planetsB.a a partir de planetsB.dll y compilaremos con ella. El makefile a utilizar será idéntico al anterior, pero modificando adecuadamente el comando de la primera regla:

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

Para construir la librería con dlltool, primero construimos un fichero de definición planets.def relacionando en su apartado EXPORTS los identificadores que nos dieron error en la compilación anterior:

LIBRARY PLANETSB.DLL
EXPORTS
showMercury
showVenus
showEarth

A continuación invocamos dlltool con el siguiente comando:

dlltool -U -d planets.def -l planetsB.a

El resultado es la librería solicitada planetsB.a, con lo que ya podemos invocarse el makefile para obtener la aplicación planetsE.exe que funciona con la librería planetsB.dll de Borland.

Nota: el tamaño del ejecutable es de 20.480 bytes frente a los 16.384 del obtenido utilizando la DLL de GNU. 

  • Ver detalles adicionales en   www.mingw.org
  •  En el manual de las binutils GNU puede encontrarse la información oficial sobre la utilidad dlltool, que acompaña a los binarios de la dististribución MinGW.

  Inicio.


[1]  Suponemos que las librerías del compilador están en el directorio C:\BCPP\Lib\, y los ficheros de cabecera en C:\BCPP\Include\.

[2]  La librería de importación puede ser sustituida en todo o en parte, por la sección IMPORTS de un fichero de definición ("module definition file").