Pourquoi compiler D'abord à un fichier objet?

au cours de la dernière année, j'ai commencé à programmer à Fortran en travaillant dans une université de recherche. La plupart de mon expérience antérieure est dans les langues Web comme PHP ou vieux ASP, donc je suis un débutant à compiler les déclarations.

j'ai deux codes différents que je suis en train de modifier.

création d'une déclaration explicite .o fichiers des modules<!-(Par exemple gfortran-c filea.f90) avant de créer l'exécutable.

un Autre sont création du fichier exécutable directement (parfois de la création .les fichiers mod, mais non .o les fichiers, par exemple gfortran-o les fichiers exécutables.f90 fichierb.F90 fichier principal.f90).

  • y a-t-il une raison (autre que, peut-être, les Makefiles) pour préférer une méthode à l'autre?
30
demandé sur Tony 2011-03-12 19:40:33

5 réponses

compiler d'abord des fichiers objet s'appelle compilation séparée. Il existe de nombreux avantages et quelques inconvénients.

les Avantages:

  • facile à transformer les fichiers objets (.o) vers les bibliothèques et lien vers elles plus tard
  • beaucoup de gens peuvent travailler sur différents fichiers source en même temps
  • Compilation plus rapide (vous ne compilez pas les mêmes fichiers encore et encore quand la source n'a pas changé)
  • les fichiers objet peuvent être créés à partir de différents sources linguistiques et liées entre elles plus tard. Pour ce faire, les fichiers objet doivent simplement utiliser le même format et les conventions d'appel compatibles.
  • la compilation séparée permet la distribution de bibliothèques à l'échelle du système (qu'il s'agisse de bibliothèques OS, de bibliothèques de langue standard ou de bibliothèques tierces), statiques ou partagées.

Inconvénients:

  • il y a quelques optimisations (comme l'optimisation des fonctions à l'extérieur) que le compilateur ne peut pas effectuer, et le linker ne s'en soucie pas; cependant, de nombreux compilateurs incluent maintenant l'option d'effectuer "l'optimisation du temps de liaison", ce qui annule largement cet inconvénient. Mais cela reste un problème pour les bibliothèques système et les bibliothèques tierces, en particulier pour les bibliothèques partagées (impossible d'optimiser les parties d'un composant qui peuvent changer à chaque exécution, cependant d'autres techniques comme la compilation JIT peuvent atténuer cela).
  • dans certaines langues, le programmeur doit fournir une sorte d'en-tête pour l'utilisation d'autres qui seront liés à cet objet. Par exemple dans C vous devez fournir .h fichiers avec vos fichiers de l'objet. Mais c'est une bonne pratique de toute façon.
  • dans les langues avec des inclusions basées sur du texte comme C ou C++, si vous changez un prototype de fonction, vous devez le changer en deux endroits. Une fois dans le fichier d'en-tête, une fois dans le fichier d'implémentation.
28
répondu kriss 2018-03-20 08:16:03

Lorsque vous avez un projet avec quelques 100 fichiers source, vous ne voulez pas de recompiler d'entre eux chaque fois qu'on change. En compilant chaque fichier source dans un fichier objet séparé et en ne recompilant que les fichiers sources qui sont affectés par un changement, vous passez le minimum de temps de la modification du code source à un nouvel exécutable.

make est l'outil courant utilisé pour suivre de telles dépendances et recréer votre binaire quand quelque chose change. En général, vous définissez ce sur quoi chaque fichier source dépend (ces dépendances peuvent typiquement être générées par votre compilateur - dans un format adapté à make), et laisser make Gérer les détails de la création d'un binaire à jour.

14
répondu Erik 2011-03-12 16:46:59

le .o fichier est le fichier objet. C'est une représentation intermédiaire du programme final.

spécifiquement, typiquement, le .o le fichier a compilé le code, mais ce qu'il n'a pas est les adresses finales pour toutes les différentes routines ou données.

une des choses dont un programme a besoin avant de pouvoir être exécuté est quelque chose de similaire à une image mémoire.

Par exemple.

si vous avez votre programme principal et qu'il appelle une routine A. (c'est faux fortran, Je n'ai pas touché depuis des décennies, alors travaille avec moi ici.)

PROGRAM MAIN
INTEGER X,Y
X = 10
Y = SQUARE(X)
WRITE(*,*) Y
END

alors vous avez la fonction carrée.

FUNCTION SQUARE(N)
SQUARE = N * N
END

les unités sont compilées individuellement. Vous pouvez voir que lorsque MAIN est compilé, il ne sait pas où est "SQUARE", à quelle adresse il se trouve. Il a besoin de savoir que donc quand il appelle l'instruction de sous-programme saut de microprocesseur (JSR), l'instruction a un endroit où aller.

le .o file a déjà l'instruction JSR, mais il n'a pas la valeur réelle. Cela vient plus tard dans la phase de liaison ou de chargement (selon votre application).

Donc, l'alimentation de SECTEUR .o fichier a tout le code pour main, et une liste de références qu'il veut résoudre (notamment carré). SQUARE est essentiellement stand alone, il n'a pas de références, mais en même temps, il n'avait pas d'adresse où il existe dans la mémoire encore.

L'éditeur de liens de prendre toutes les .o les fichiers et les combiner dans un seul exe. Dans les vieux jours, compilé code serait littéralement une image mémoire. Le programme commencerait à une certaine adresse et serait simplement chargé sur RAM wholesale, puis exécuté. Donc, dans le scénario, vous pouvez voir le linker prendre les deux .o les fichiers, les concaténant ensemble (pour obtenir des carrés adresse réelle), puis il retournerait et trouver la référence carrée dans le principal, et remplir l'adresse.

les linkers modernes ne vont pas très loin, et reportent une grande partie du traitement final au moment où le programme est chargé. Mais l' le concept est similaire.

en compilant to .o les fichiers, vous finissez avec des unités de logique réutilisables qui sont ensuite combinées par les processus de liaison et de chargement avant l'exécution.

L'autre aspect intéressant est que l' .o fichiers peuvent provenir de différentes langues. Dans la mesure où les mécanismes d'appel sont compatibles (c'est-à-dire comment les arguments sont passés aux fonctions et aux procédures et vice versa), une fois compilés, les arguments sont compilés en a.o, la langue source devient moins pertinente. Vous pouvez lier, combiner, Code C avec code FORTRAN, par exemple.

dans PHP et all, le processus est différent parce que tout le code est chargé dans une seule image à l'exécution. Vous pouvez considérer les FORTRANs .o fichiers similaires à la façon dont vous utiliseriez PHPs include mécanisme pour combiner les fichiers dans un grand, ensemble cohérent.

5
répondu Will Hartung 2011-03-12 17:00:57

une autre raison, en dehors du temps de compilation, est que le processus de compilation est un multi-étape du processus.

The multi-part process.

les fichiers objets ne sont qu'une sortie intermédiaire de ce processus. Ils seront éventuellement utilisés par le linker pour produire le fichier exécutable.

2
répondu Peter K. 2011-03-12 16:51:10

nous compilons pour objecter des fichiers pour pouvoir les lier ensemble pour former des exécutables plus gros. Ce n'est pas la seule façon de le faire.

il y a aussi des compilateurs qui ne le font pas de cette façon, mais qui compilent en mémoire et exécutent le résultat immédiatement. Auparavant, lorsque les élèves devaient utiliser des ordinateurs centraux, c'était la norme. Le Turbo Pascal l'a aussi fait de cette façon.

1
répondu Bo Persson 2011-03-12 17:58:29