una reglamento que publicas publica proyectos para organiza normas niños ideas hay escolar como bibliotecas biblioteca c++ c windows visual-c++

c++ - reglamento - ¿Cómo funciona la biblioteca de importación? Detalles?



reglamento de biblioteca escolar (4)

Sé que esto puede parecer bastante básico para geeks. Pero quiero dejarlo absolutamente claro.

Cuando quiero usar una DLL de Win32, generalmente solo llamo a las API como LoadLibrary () y GetProcAdderss (). Pero recientemente, estoy desarrollando con DirectX9 y necesito agregar archivos d3d9.lib , d3dx9.lib , etc.

He escuchado suficiente que LIB es para enlaces estáticos y DLL para enlaces dinámicos.

Entonces mi comprensión actual es que LIB contiene la implementación de los métodos y está estáticamente enlazado en el tiempo de enlace como parte del archivo EXE final. Mientras que DLL se carga dinámicamente en tiempo de ejecución y no es parte del archivo EXE final.

Pero a veces, hay algunos archivos LIB que vienen con los archivos DLL, así que:

  • ¿Para qué son estos archivos LIB?
  • ¿Cómo logran lo que están destinados?
  • ¿Hay alguna herramienta que me permita inspeccionar las partes internas de estos archivos LIB?

Actualización 1

Después de revisar wikipedia, recuerdo que estos archivos LIB se llaman biblioteca de importación . Pero me pregunto cómo funciona con mi aplicación principal y los archivos DLL que se cargan dinámicamente.

Actualización 2

Tal como dijo RBerteig, hay un código auxiliar en los archivos LIB que nacieron con los archivos DLL. Entonces la secuencia de llamada debería ser así:

Mi aplicación principal -> stub en la LIB -> DLL de destino real

Entonces, ¿qué información debería contenerse en estas LIBs? Podría pensar en lo siguiente:

  • El archivo LIB debe contener la ruta completa de la DLL correspondiente; Entonces, el tiempo de ejecución podría cargar la DLL.
  • La dirección relativa (¿o el desplazamiento del archivo?) Del punto de entrada de cada método de exportación de DLL debe codificarse en el código auxiliar; Por lo tanto, se podrían realizar llamadas correctas de saltos / métodos.

Estoy en lo cierto en esto? ¿Hay algo más?

BTW: ¿Hay alguna herramienta que pueda inspeccionar una biblioteca de importación? Si puedo verlo, no habrá más dudas.



Estos archivos de biblioteca de importación .LIB se utilizan en la siguiente propiedad del proyecto, Linker->Input->Additional Dependencies , al Linker->Input->Additional Dependencies un conjunto de dll que necesitan información adicional en tiempo de enlace que es suministrada por los archivos .LIB de la biblioteca de importación. En el siguiente ejemplo para no obtener errores del enlazador, necesito hacer referencia a dll''s A, B, C y D a través de sus archivos lib. (tenga en cuenta que el vinculador para encontrar estos archivos puede necesitar incluir su ruta de implementación en Linker->General->Additional Library Directories contrario obtendrá un error de compilación al no poder encontrar ninguno de los archivos lib proporcionados).

Si su solución está creando todas las bibliotecas dinámicas, es posible que haya podido evitar esta especificación de dependencia explícita confiando en cambio en los indicadores de referencia expuestos en el cuadro de diálogo Common Properties->Framework and References . Estos indicadores parecen hacer automáticamente el enlace en su nombre utilizando los archivos * .lib.

Sin embargo, esto es como dice Common Properties, que no es de configuración o plataforma específica. Si necesita admitir un escenario de compilación mixta como en nuestra aplicación, tuvimos una configuración de compilación para generar una compilación estática y una configuración especial que construyó una compilación limitada de un subconjunto de ensamblados que se implementaron como bibliotecas dinámicas. Utilicé los indicadores Use Library Dependency Inputs y Link Library Dependencies establecidos en true en varios casos para que las cosas se construyeran y luego me diera cuenta para simplificar las cosas, pero al presentar mi código a las compilaciones estáticas introduje un montón de advertencias de enlaces y se construyó increíblemente lento para las construcciones estáticas. Terminé presentando un montón de este tipo de advertencias ...

warning LNK4006: "bool __cdecl XXX::YYY() already defined in CoreLibrary.lib(JSource.obj); second definition ignored D.lib(JSource.obj)

Y terminé usando la especificación manual de Additional Dependencies para satisfacer al enlazador de las compilaciones dinámicas, mientras mantenía contentos a los constructores estáticos al no usar una propiedad común que los ralentizaba. Cuando despliego la compilación del subconjunto dinámico, solo despliego los archivos dll, ya que estos archivos lib solo se usan en tiempo de enlace, no en tiempo de ejecución.


Hay tres tipos de bibliotecas: bibliotecas estáticas, compartidas y cargadas dinámicamente.

Las bibliotecas estáticas están vinculadas con el código en la fase de enlace, por lo que están realmente en el ejecutable, a diferencia de la biblioteca compartida, que solo tiene stubs (símbolos) para buscar en el archivo de biblioteca compartida, que se carga en tiempo de ejecución antes del la función principal se llama.

Los cargados dinámicamente son muy parecidos a las bibliotecas compartidas, excepto que se cargan cuando y si surge la necesidad del código que usted ha escrito.


La vinculación a un archivo DLL puede ocurrir implícitamente en el momento del enlace de compilación , o explícitamente en tiempo de ejecución. De cualquier manera, la DLL termina cargada en el espacio de memoria de procesos, y todos sus puntos de entrada exportados están disponibles para la aplicación.

Si se usa explícitamente en tiempo de ejecución, utilice LoadLibrary() y GetProcAddress() para cargar manualmente la DLL y obtener punteros a las funciones que necesita llamar.

Si se vincula implícitamente cuando se genera el programa, los stubs para cada exportación DLL utilizada por el programa se vinculan al programa desde una biblioteca de importación, y esos resguardos se actualizan cuando el EXE y el DLL se cargan cuando se inicia el proceso. (Sí, simplifiqué más que un poco aquí ...)

Esos talones deben provenir de algún lugar, y en la cadena de herramientas de Microsoft provienen de una forma especial de archivo .LIB llamada biblioteca de importación . El .LIB requerido generalmente se genera al mismo tiempo que el DLL, y contiene un stub para cada función exportada desde el DLL.

Confusamente, una versión estática de la misma biblioteca también se enviaría como un archivo .LIB. No hay una manera trivial de diferenciarlos, excepto que los LIBs que son bibliotecas de importación para DLL generalmente serán más pequeños (a menudo mucho más pequeños) que la LIB estática correspondiente.

Si utiliza la cadena de herramientas GCC, por cierto, no necesita bibliotecas de importación para que coincidan con sus archivos DLL. La versión del enlazador Gnu portado a Windows comprende DLL directamente, y puede sintetizar casi todos los stubs necesarios sobre la marcha.

Actualizar

Si no puede resistirse a saber dónde están realmente todos los aspectos prácticos y qué está sucediendo realmente, siempre hay algo en MSDN que puede ayudar. El artículo de Matt Pietrek Una mirada a fondo en el formato de archivo ejecutable portátil de Win32 es una descripción general muy completa del formato del archivo EXE y cómo se carga y se ejecuta. Incluso se ha actualizado para cubrir .NET y más, ya que apareció originalmente en MSDN Magazine ca. 2002.

Además, puede ser útil saber cómo saber exactamente qué archivos DLL utiliza un programa. La herramienta para eso es Dependency Walker, aka depends.exe. Se incluye una versión de este con Visual Studio, pero la última versión está disponible desde su autor en http://www.dependencywalker.com/ . Puede identificar todas las DLL que se especificaron en el momento del enlace (carga temprana y carga de retraso) y también puede ejecutar el programa y observar si hay DLL adicionales que cargue en tiempo de ejecución.

Actualización 2

He reformulado parte del texto anterior para aclararlo en la relectura y para usar los términos de los enlaces de arte implícitos y explícitos para mantener la coherencia con MSDN.

Entonces, tenemos tres formas en que las funciones de la biblioteca pueden estar disponibles para ser utilizadas por un programa. La siguiente pregunta obvia es: "¿Cómo elijo el camino?"

La vinculación estática es la forma en que la mayor parte del programa está vinculado. Todos los archivos de objeto se enumeran y el vinculador los recopila juntos en el archivo EXE. En el camino, el enlazador se ocupa de tareas menores como arreglar referencias a símbolos globales para que los módulos puedan llamar a las funciones de los demás. Las bibliotecas también se pueden vincular estáticamente. Los archivos objeto que componen la biblioteca son recopilados por un bibliotecario en un archivo .LIB que el vinculador busca módulos que contienen símbolos que son necesarios. Uno de los efectos de los enlaces estáticos es que solo los módulos de la biblioteca que utiliza el programa están vinculados a él; otros módulos son ignorados. Por ejemplo, la biblioteca matemática C tradicional incluye muchas funciones de trigonometría. Pero si establece un enlace y utiliza cos() , no obtendrá una copia del código para sin() o tan() menos que también haya llamado a esas funciones. Para grandes bibliotecas con un amplio conjunto de características, esta inclusión selectiva de módulos es importante. En muchas plataformas, como los sistemas integrados, el tamaño total del código disponible para su uso en la biblioteca puede ser grande en comparación con el espacio disponible para almacenar un ejecutable en el dispositivo. Sin una inclusión selectiva, sería más difícil administrar los detalles de la construcción de programas para esas plataformas.

Sin embargo, tener una copia de la misma biblioteca en cada programa en ejecución crea una carga en un sistema que normalmente ejecuta muchos procesos. Con el tipo correcto de sistema de memoria virtual, las páginas de memoria que tienen contenido idéntico solo necesitan existir una vez en el sistema, pero pueden ser utilizadas por muchos procesos. Esto crea un beneficio para aumentar las posibilidades de que las páginas que contienen el código sean probablemente idénticas a algunas páginas en tantos procesos en ejecución como sea posible. Pero, si los programas enlazan estáticamente a la biblioteca de tiempo de ejecución, cada uno tiene una combinación diferente de funciones, cada una presentada en ese mapa de memoria de procesos en diferentes ubicaciones, y no hay muchas páginas de códigos compartibles a menos que sea un programa que por sí solo ejecutar en más de proceso. Entonces, la idea de una DLL ganó otra gran ventaja.

Una DLL para una biblioteca contiene todas sus funciones, lista para ser utilizada por cualquier programa cliente. Si muchos programas cargan esa DLL, todos pueden compartir sus páginas de códigos. Todos ganan. (Bueno, hasta que actualice una DLL con una nueva versión, pero eso no es parte de esta historia. Google DLL Infierno para ese lado del cuento).

Por lo tanto, la primera gran elección al planificar un nuevo proyecto es entre vinculación dinámica y estática. Con el enlace estático, tiene menos archivos para instalar y es inmune a que terceros actualicen un archivo DLL que usa. Sin embargo, su programa es más grande y no es tan buen ciudadano del ecosistema de Windows. Con el enlace dinámico, tiene más archivos para instalar, es posible que tenga problemas con un tercero para actualizar un archivo DLL que usa, pero en general está siendo más amigable con otros procesos en el sistema.

Una gran ventaja de una DLL es que se puede cargar y usar sin volver a compilar ni volver a vincular el programa principal. Esto puede permitir que un proveedor de biblioteca de terceros (por ejemplo, Microsoft y el C runtime) solucione un error en su biblioteca y lo distribuya. Una vez que un usuario final instala la DLL actualizada, obtiene de inmediato el beneficio de esa corrección de errores en todos los programas que usan esa DLL. (A menos que rompa cosas. Ver DLL Hell).

La otra ventaja proviene de la distinción entre carga implícita y explícita. Si va al esfuerzo extra de la carga explícita, entonces la DLL podría no haber existido cuando el programa fue escrito y publicado. Esto permite mecanismos de extensión que pueden descubrir y cargar complementos, por ejemplo.