Difference between revisions of "shared library/es"

From Lazarus wiki
Jump to navigationJump to search
Line 54: Line 54:
 
   El problema con las bibliotecas es por lo general que son iniciadas en su conjunto. ESto puede llevar a problemas con unidades conectadas que modifican el comportamiento de la RTL (cwstrings, cmem, controladores FV, etc.)
 
   El problema con las bibliotecas es por lo general que son iniciadas en su conjunto. ESto puede llevar a problemas con unidades conectadas que modifican el comportamiento de la RTL (cwstrings, cmem, controladores FV, etc.)
  
   Para librerías independientes con copias de la RTL, esta tiene que ser iniciada, y así mismo debe serlo la sección de iniciación de la librerías.
+
   Para librerías independientes con copias de la RTL, esta tiene que ser iniciada, y así mismo debe serlo la sección de iniciación de la librería.
  
 
   Hay, al menos, dos opciones para esto:
 
   Hay, al menos, dos opciones para esto:

Revision as of 01:24, 9 September 2008

Deutsch (de) English (en) español (es) 한국어 (ko) русский (ru)

   (El término librería compartida se refiere tanto a .so como a .dll, a no ser que se diga explícitamente "librería compartida de unix" o "dll")

   Hoy día hay una gran cantidad de informes de error sobre las librerías compartidas. Sin embargo, que yo sepa, no hay una verdadera documentación acerca de cómo las librerías compartidas trabajan conjuntamente con FPC. Trataremos de como trabajan las librerías compartidas, cómo deberían hacerlo, y de cómo se hace esto con Delphi.

   En principio esto es un bosquejo, de cómo se hace en Delphi, ya que trataremos de hacerlo lo más compatible y multiplataforma que sea posible. Todo lo expuesto está sacado de mi cabeza y de páginas "web". Si deseas más detalle o detallar más exactamente los términos de este trabajo, está invitado a ello.

  Soy un completo desconocedor de Kylix, así que si conoces cómo se implementa en Kylix cierta funcionalidad, no dudes en añadirlo.

Delphi

   Delphi, hasta donde conozco, tiene tres (o cuatro) formas de enlace dinámico.

  1. crear un librería compartida independiente, compilar una librería sin seleccionar paquetes de tiempo de ejecución ("runtime packages").
    • Esto implica que la Librería de Tiempo de Ejecución (RTL) será enlazada en la librería compartida
    • El controlador de memoria está aislado. La utilización de tipos automáticos para comunicarse con ella no será posible.
    • No se podrán usar clases. El programa y la librería tienen copias distintas de la Tabla de Métodos Virtuales (VMT). (¡¿e.g. operadores IS y AS?!)
  2. crear un librería compartida independiente (compilar una librería (unit library) sin seleccionar paquetes de tiempo de ejecución ("runtime packages"), pero usando la unidad sharemem
    • La RTL será enlazada en la librería compartida
    • El controlador de memoria estará en modo compatible COM. Esto permitirá a otros componentes/programas, funcionado en este mismo modo realizar llamadas a funciones usando tipos automáticos (no importa lo que se devuelve al COM manejado)
    • Reseñar la lentitud del manejador COM de memoria. Esta vía es poco recomendable, a no ser que se quiera a toda costa COM o que los "COMponentes" sean más importantes que que la velocidad de ejecución.
    • No se podrán usar clases. El programa y la librería tienen copias distintas de la VMT.
  3. Library packages Estas son librerías compartidas para las cuales todas las dependencias a nivel pascal son conocidas (que unidades lo contienen y que dependencias existen), y son tratadas como si fuesen parte del programa principal que residen en una DLL.
    • La RTL es un paquete separado (una DLL) y el progrma principal y los otros paquetes hacen uso de la misma. Todo esto implica que únicamente hay una copia de cada unidad en el sistema.
    • Esto también significa que hay sólo un administrador de memoria (al menos para el pograma principal y los paquetes que utiliza. Las librerías compartidas que no son paquetes pueden utilizar su propia copia de la RTL y su manejador de memoria)
    • un paquete sólo puede depender de unidades de su propio paquete o de otros paquetes.
    • como las unidades no se duplican existe una única copia de cada VMT, haciendo transparente la utilización de las clases
    • Es probable que los paquetes también puedan cambiar a "memoria compartida", lo que lo hace compatible con otros sistemas que utilizan "memoria compartida". Hay que buscar la manera de iniciar la memoria compartida lo antes posible (¿Cómo lo hace Delphi? probablemente intentando pasar una cadena creada en una sección de iniciación de un paquete a otra librería compartida, que no es un paquete, que usa memoria compartida) T.B.D.

   Además de lo anterior Delphi es capaz de producir dll que contienen componentes ActiveX. T.B.D.

   Las cuestiones sobre librerías de paquetes se han trasladado al tema paquetes para no liar el debate.

Detalles de Sharemem

   Como ya se ha dicho, sharemem cambia el gestor de memoria a global. Bajo Windows este es el controlador COM, que yo sepa. En *nix un controlador de memoria similar no existe (La arquitectura de componentes de Gnome y KDE puede que hagan algo similar), pero no tengo garantías sobre esto.

   Uno podría simplemente tener todos los programas usando "cmem", lo que podría ser un "nivel 0" de todo lo que se ejecuta en este proceso

   Se menciona esto explícitamente porque, podría ser necesario imponer un orden propio de inicio (independiente de la iniciación de las librerías compartidas por el SO) para permitir al programa principal iniciar adecuadamente las unidades después de la iniciación de la RTL (unidad del sistema), pero antes que otras librerías, v.gr. un controlador de memoria diferente.

Duplicación de la VMT

   El principal problema de la duplicación de la VMT es el soporte para el parámetro IS y simular métodos de TObject y TClass como si fuesen heredados. Esto está resuelto únicamente para paquetes, es decir, para los otros tipos mencionados, el operador IS no funciona en el cruce librería/binario.

   En discusiones anteriores sobre paquetes, hubo cierta confusión sobre esta cuestión. La gente asume que los paquetes de alguna manera aprovechan la VMT de la RTL desde el programa principal. Sin embargo, estoy bastante seguro de que este no es el caso, al menos en Delphi, ya que cuando se utilizan paquetes, la RTL es también un paquete. Y cada dependencia de una unidad en un paquete deben estar en el mismo paquete o en un paquete del que dependa. Esto significa que únicamente hay una copia de una unidad, y de la VMT en ella declarada, en el programa conjunto (el programa principal + sus paquetes)

La RTL y las secciones de iniciación y terminación

   (la explicación sobre el orden de iniciación de las unidades en los paquetes ha sido movida a la página de paquetes).

   El problema con las bibliotecas es por lo general que son iniciadas en su conjunto. ESto puede llevar a problemas con unidades conectadas que modifican el comportamiento de la RTL (cwstrings, cmem, controladores FV, etc.)

   Para librerías independientes con copias de la RTL, esta tiene que ser iniciada, y así mismo debe serlo la sección de iniciación de la librería.

   Hay, al menos, dos opciones para esto:

  • Usar (v.gr. en plataformas ELF) las secciones .init y .fini del ABI o mecanismos similares de otros formatos binarios.
  • Dejar las secciones .init y .fini vacías, y fuerce el orden de iniciación con secciones propias de inicio y fin. Las secciones ELF de inico y fin simplemente apuntan a los iniciadores (y terminadores) reales.

   Métodos mixtos son posibles, v.gr. iniciar las librería independientes con secciones de inicio y utilizar las secciones definidas por nosotros mismos con los paquetes.

Shared Exe Memory manager

Lars says: regarding a single memory manager for BPL style packages: what about using the executable and exporting its memory manager? I have had problems trying to use CMEM but have successfully shared the same memory manager using SetMemoryManager/GetMemoryManager tricks.

See http://www.freepascal.org/contrib/delete.php3?ID=543 for an example of sharing memory between exe and dll without using CMEM. Powtils CGI library also uses this trick for dynpwu.pas so that ansistrings can be used without any sharemem or cmem unit. The memory manager is exported from the executable or a single library and shared with all the other DLL/EXE's that are connecting to the single module.

Marco's answer:

First, library packages have more features than just shared memory managers. Unique VMTs (try to use the IS operator in your example on a class created in the other lib/exe) and no need to handcraft proper initialization. One just groups units into libs, and the compiler does the rest. No special code required.

So what must be done for (Library-) packages is different (and non competing) to the more general shared library case. And that is what this page is about.

From this general "shared library" case, a subdivision can be separated that have a shared memorymgr.

Note that there can be a bunch of memory managers used for this, and multiple units that work like sharemem. Nearly any memory manager applies. However it is logical to reserve the "sharemem" unit name for the memory manager that is the most compatible for inter-process work on the given platform (COM on Windows, cmem on Unix). So, I'm talking about the default case here, which doesn't mean that other people can't roll their own.

Also, in-compiler(rtl) support must be as universal as possible, and also work for libraries that are not loadlibrary-ed, but autoloaded at binary startup, and not require handcoding e.g. initialization. Also it mustn't stand in the way of handcoded solutions (like the one you reference), in other words it must be overridable, since otherwise in-compiler(rtl) support would stand in the way of what people build on top of FPC.

It would be useful though, if sb investigate if it is possible to call exported symbols from the binary from an autoloaded library (for the Tier 1 targets, Linux/FreeBSD - Windows - OS X). This because then a library could maybe indeed plug in the mother binary.

In short the first objective is to simply have a default scheme that works like Delphi's sharemem to put in the "sharemem" unit.

Lars says: Well another idea: instead of exporting the memory manager from the exe I was thinking about making a fpsharemem.dll that exports one single common fpc memory manager on each platform for all the programs and dll's to use, instead of using CMEM. i.e. all units put fpsharemem.dll in their uses clause. In fact, that's actually what the demo does but instead of a separate fpsharemem.dll it is just inside that single dll included with the demo and all the other code. i.e. why use CMEM if we can use freepascal memory manager? The freepascal mem manager is available on all platforms isn't it, as long as there is a fp dll is created for each platform?

I guess to answer my own questions it must have to do with COM/IPC (inter process communication) issues/compatibilities. Well anyway, still a very interesting discussion. Doing it by hand the way I did was just a demo to show the concept in action and to prove to people that ansistrings and automated types can be used in regular old DLL's.

References

Contribuciones