Recientemente, comencé a trabajar en Delphi y descubrí que muchos paquetes se usaban en el programa original, pero siempre estaba en un estado ignorante. Puede llevar algún tiempo estudiar este problema. Así que primero enumere las preguntas que deben analizarse:
¿Qué es una bolsa? ¿Qué es un exe? ¿Cuáles son sus diferencias de composición? ¿Cuál es la relación entre el paquete y la DCU? ¿Qué hace DCP? ¿Cuál es la relación entre estos archivos en el momento de la compilación? ¿Cómo se carga? ¿Cómo operar el paquete después de cargar? DLL puede exportar, pero ¿por qué el Delphi ayuda a no traer las exportaciones del paquete, pero algún código usa exprots en el paquete?
Primero, echemos un vistazo al proceso de compilación de Delphi. Hay dos tipos de proyectos en Delphi: paquetes y programas. Comience con uno simple, comencemos con DPR. Según la documentación de ayuda de Delphi, la estructura de un archivo DPR típico es la siguiente:
1 editor de programas;
2
3 usos
4 formularios, {Cambiar a QForms en Linux}
5 REABOUT en 'REABOT.PAS' {Aboutbox},
6 permanecen en 'permanecer.pas' {mainform};
7
8 {$ r *.res}
9
10 Comienzo
11 Application.title: = 'Editor de texto';
12 Application.CreateForm (tmainform, mainform);
13 Application.run;
14 fin.
Entre ellas, de 10 a 14 líneas, Begin ... End es naturalmente la entrada de ejecución del programa. La parte de usos indica algunas unidades que el programa debe usar, lo cual es bastante vago. ¿necesidad? Luego, cada unidad usará otras unidades, y este problema parece ser cada vez más complicado. Veamos primero la estructura de todo el código fuente:
Supongo que el primer paso del compilador es atravesar este gráfico dirigido, compilar cada unidad, si es necesario, y generar la DCU correspondiente. En cuanto a este problema "necesario", inicialmente pensé que la declaración de uso de la unidad estaba, pero luego descubrí que estaba mal. Porque en el caso anterior, Unit3 no especifica la ruta en la cláusula USE de la Unidad1, pero el archivo DCU correspondiente todavía se genera correctamente. Más tarde, Filemon se usa para monitorear la situación de apertura de archivos, y el proceso de descubrimiento es el siguiente: para cada nodo en el gráfico, el compilador busca los nodos correspondientes en la ruta de búsqueda en el directorio actual - Atributo del proyecto - Ruta de la biblioteca en la biblioteca en la biblioteca entorno.
Ahora que la compilación está realizada, cada unidad (es decir, el archivo PAS) ha generado el archivo DCU para el siguiente. Cuando se trata de conexiones, el problema es complicado. La conexión estática significa combinar todas estas DCU juntas. De esta manera, la llamada de una unidad a otra unidad se convierte en una cuestión interna del programa. Este beneficio es que es rápido y simple, y los problemas como el intercambio concurrente son fáciles de tratar. La desventaja es que el programa de destino es grande, y si se va a escribir otro programa ahora y la Unidad3 se puede reutilizar, unit3.dcu se copiará nuevamente cuando se conecte. De esta manera, cuando dos programas se ejecutan al mismo tiempo, habrá dos copias de la Unidad3 en la memoria, lo cual es un desperdicio. La conexión dinámica significa que cuando dos programas se conectan, solo conservan las referencias a la Unidad3 y no copian el contenido de la Unidad3. En tiempo de ejecución, cargue la Unidad3 en la memoria y haga que los dos programas sean comunes. DLL y BPL son ambas soluciones para conexiones dinámicas. El problema es que la única opción para la conexión en Delphi aparece en el menú del proyecto | Opciones | PAQUETES, y la oración "Build with Runtime Packages" es realmente demasiado vaga. Así que necesitamos estudiarlo nuevamente.
Cuando se ejecuta el programa, podemos usar View | Ventana de depuración | Mudles para ver qué cosas se cargan en la memoria y qué contenido contienen.
Para ser simple, configuramos un programa con la siguiente estructura:
Project ProjectExe;
usos
Formularios,
Windows,
UnitFormMain en 'UnitFormMain.pas' {FormMain};
{$ R *.res}
Comenzar
Aplicación.initialize;
Application.CreateForm (tFormMain, FormMain);
Aplicación.run;
fin.
Unidad Unidad Formmain;
interfaz
usos
Windows, stdctrls, formularios, unitformanother, clases, controles;
tipo
TFormMain = class (tForm)
Botón 1: tbutton;
procedimiento botón1Click (remitente: tobject);
Privado
{Declaraciones privadas}
público
{Declaraciones públicas}
fin;
varilla
FormMain: tFormMain;
Implementación
{$ R *.dfm}
procedimiento tFormMain.Button1Click (remitente: tobject);
varilla
Lform: tformanother;
Comenzar
Lform: = tFormanother.create (aplicación);
Lform.showModal;
Lform.free;
fin;
fin.
Unidad Unidad Formanother;
interfaz
usos
Formas;
tipo
TFormanother = class (tForm)
Privado
{Declaraciones privadas}
público
{Declaraciones públicas}
fin;
Implementación
{$ R *.dfm}
fin.
Recibamos las noticias ahora. "Build with Runtime Packages" se verifica, y ahora se encuentra que el archivo Runtime ProjectExe.exe solo contiene cuatro partes: dos formulario, un sysinit.pas y un proyectoxe.pr; En el árbol de proceso: RTL60 y VCL60, su contenido son las unidades que aparecieron en la conexión estática en este momento. ProjectExe.exe es solo 16K ahora. En otras palabras, parte de la unidad en el gráfico dirigido se coloca en el exe y la otra parte se coloca en el BPL. Pero, ¿en qué se basa la división? ¿Se basa en la cláusula de usos o se basa en la lista en "Build with Runtime Packages" aquí? Continuando con la prueba, descubrí que si la lista solo contiene VCL60, entonces los dos BPL más uno EXE cargado en la memoria todavía están cargados en la memoria; El EXE ha cambiado: el número de unidades en el interior ha aumentado y están básicamente en el paquete VCL60. Supongo que debería haber una relación requisito entre los paquetes RTL y VCL. Esto se probará en el siguiente paso. Sin embargo, durante el proceso de estimación inicial, la lista de paquetes definitivamente se utilizará para excluir unidades que ya existen en el paquete del EXE.
Después de la conexión dinámica, hay otro problema: la carga. Hay dos estrategias para la carga, estática, también conocidas como Automatic, que genera código de Delphi, y carga automáticamente el paquete antes de cargar el EXE es dinámico, es decir, cuando el programa se está ejecutando, especifica un paquete y carga It. El problema es que tengo que averiguar en qué circunstancias cargará automáticamente un paquete y en qué circunstancias puedo evitar que Delphi sea inteligente para que pueda usar el paquete de manera flexible. En el experimento anterior, solo se puede ver que antes de que el archivo DPR se ejecute para comenzar, el paquete conectado estáticamente se ha cargado en la memoria. No conozco el proceso específico.