Récemment, j'ai commencé à travailler sur Delphi et j'ai constaté que de nombreux packages étaient utilisés dans le programme original, mais j'étais toujours dans un état ignorant. Il peut prendre un certain temps pour étudier ce problème. Ainsi, énumérez d'abord les questions qui doivent être analysées:
Qu'est-ce qu'un sac? Qu'est-ce qu'un EXE? Quelles sont leurs différences de composition? Quelle est la relation entre le package et DCU? Que fait DCP? Quelle est la relation entre ces fichiers au moment de la compilation? Comment est-il chargé? Comment faire fonctionner le package après le chargement? DLL peut exporter, mais pourquoi le Delphi aide-t-il à ne pas afficher les exportations du package, mais un code utilise des exprovistes dans le package?
Tout d'abord, jetons un coup d'œil au processus de compilation de Delphi. Il existe deux types de projets à Delphi: les packages et les programmes. Commençons par un simple, commençons par DPR. Selon la documentation d'aide de Delphi, la structure d'un fichier DPR typique est la suivante:
1 éditeur de programme;
2
3 utilisations
4 formulaires, {changer en qforms dans Linux}
5 Reabout dans 'reabout.pas' {Aboutbox},
6 reste dans 'reste.pas' {mainform};
7
8 {$ r * .res}
9
10 commencer
11 Application.Title: = 'Text Editor';
12 application.CreateForm (tmainForm, MainForm);
13 application.run;
14 fin.
Parmi eux, 10 à 14 lignes, commencez… la fin est naturellement l'entrée d'exécution du programme. La partie d'utilisation indique certaines unités que le programme doit utiliser, ce qui est plutôt vague. besoin? Ensuite, chaque unité utilisera d'autres unités, et ce problème semble devenir de plus en plus compliqué. Examinons d'abord la structure de l'ensemble du code source:
Je suppose que la première étape du compilateur consiste à traverser ce graphique dirigé, à compiler chaque unité, si nécessaire, et à générer le DCU correspondant. Quant à ce problème "nécessaire", j'ai d'abord pensé que la déclaration d'utilisation de l'unité était dans, mais plus tard j'ai trouvé que c'était mal. Parce que dans le cas ci-dessus, l'unité3 ne spécifie pas le chemin d'accès dans la clause USE de Unit1, mais le fichier DCU correspondant est toujours généré correctement. Plus tard, Filemon est utilisé pour surveiller la situation d'ouverture des fichiers, et le processus de découverte est le suivant: Pour chaque nœud du graphique, le compilateur recherche les nœuds correspondants dans le chemin de recherche dans le répertoire actuel - Attribut de projet - Chemin de bibliothèque dans la bibliothèque Environnement.
Maintenant que la compilation est effectuée, chaque unité (c'est-à-dire le fichier PAS) a généré le fichier DCU pour celui-ci. En ce qui concerne les connexions, le problème est compliqué. La connexion statique signifie combiner tous ces DCU ensemble. De cette façon, l'appel d'une unité à une autre unité devient une question interne du programme. Cet avantage est qu'il est rapide et simple, et des problèmes tels que le partage simultané sont faciles à gérer. L'inconvénient est que le programme cible est important, et si un autre programme doit être écrit maintenant et que l'unité3 peut être réutilisée, unité3.dcu sera à nouveau copiée lors de la connexion. De cette façon, lorsque deux programmes fonctionnent en même temps, il y aura deux copies de l'unité3 en mémoire, ce qui est un gaspillage. La connexion dynamique signifie que lorsque deux programmes se connectent, ils conservent uniquement les références à Unit3 et ne copient pas le contenu de Unit3. Au moment de l'exécution, chargez l'unité3 en mémoire et rendez les deux programmes communs. La DLL et le BPL sont toutes deux des solutions pour les connexions dynamiques. Le problème est que la seule option de connexion à Delphi apparaît dans le menu Project | Options | Packages, et la phrase "Build with Runtime Packages" est vraiment trop vague. Nous devons donc l'étudier à nouveau.
Lorsque le programme est exécuté, nous pouvons utiliser View | Debug Window | Moudles pour voir quelles choses sont chargées dans la mémoire et quel contenu ils contiennent.
Pour être simple, nous avons mis en place un programme avec la structure suivante:
Program ProjectExe;
usages
Formes,
Fenêtres,
UnitFormmain dans 'UnitFormmain.Pas' {FormMain};
{$ R * .res}
Commencer
Application.Initialize;
Application.CreateForm (TFormMain, formMain);
Application.run;
fin.
unit UnitFormMain;
interface
usages
Windows, stdctrls, formulaires, Unitformanother, classes, commandes;
taper
Tformmain = classe (tform)
Button1: Tbutton;
Procédure Button1Click (expéditeur: tobject);
Privé
{Déclarations privées}
publique
{Déclarations publiques}
fin;
var
FormMain: TFormmain;
Mise en œuvre
{$ R * .dfm}
procédure tformmain.button1click (expéditeur: tobject);
var
LForm: Tformanother;
Commencer
Lform: = tformanother.create (application);
Lform.showmodal;
Lform.free;
fin;
fin.
unité unité de formelle;
interface
usages
Formes;
taper
Tformanother = classe (tform)
Privé
{Déclarations privées}
publique
{Déclarations publiques}
fin;
Mise en œuvre
{$ R * .dfm}
fin.
Allons maintenant les nouvelles. "Build with Runtime Packages" est vérifié, et maintenant il est constaté que le fichier Runtime projectExe.exe ne contient que quatre parties: deux formulaires, un sysinit.pas et un projectexe.dpr; Dans l'arborescence de processus: RTL60 et VCL60, leur contenu est les unités qui sont apparues dans la connexion statique tout à l'heure. ProjectExe.exe n'est que 16k maintenant. En d'autres termes, une partie de l'unité du graphique dirigé est placée dans l'EXE et l'autre partie est placée dans le BPL. Mais sur quoi est basé la division? Est-il basé sur la clause d'utilisation, ou basée sur la liste dans "Build with Runtime Packages" ici? Poursuivant le test, j'ai constaté que si la liste contient uniquement VCL60, les deux BPL plus un EXE chargé dans la mémoire sont toujours chargés dans la mémoire; L'exe a changé: le nombre d'unités à l'intérieur a augmenté, et ils se trouvent essentiellement dans le package VCL60. Je suppose qu'il devrait y avoir une relation d'exigence entre les packages RTL et VCL. Cela sera testé à l'étape suivante. Cependant, lors du processus d'estimation initial, la liste des packages sera certainement utilisée pour exclure les unités qui existent déjà dans le package à partir de l'EXE.
Après la connexion dynamique, il y a un autre problème: le chargement. Il existe deux stratégies de chargement, également connues sous le nom de automatique, qui génère du code à partir de Delphi, et charge automatiquement le package avant de charger l'EXE; la mémoire. Le problème est que je dois déterminer dans quelles circonstances Delphi chargera automatiquement un package et dans quelles circonstances puis-je éviter que Delphi soit intelligent afin que je puisse utiliser le package de manière flexible. Dans l'expérience précédente, on peut voir qu'avant que le fichier DPR ne soit exécuté pour commencer, le package statiquement connecté a été chargé en mémoire. Je ne connais pas le processus spécifique.