Quand devrions-nous utiliser des «binaires incorporés» plutôt que des «cadres liés» dans Xcode?


140

Il y a une bonne question sur la différence entre ces deux options, comme décrit dans Lien binaire avec les bibliothèques VS Embed Frameworks .

On dirait que nous avons des options pour les utiliser tous les deux, demandez-vous simplement dans quel cas nous devrions mieux utiliser les binaires intégrés, ou plutôt que le cadre lié?

Y a-t-il des exemples solides pour résoudre ce problème plus clairement? Merci


Réponses:


239

La question que vous avez liée fait référence à la fonctionnalité "Lier le binaire avec les bibliothèques", qui est quelque peu différente d'un binaire incorporé.

"Lier le binaire avec les bibliothèques" signifie ce à quoi vous vous attendez en ce qui concerne le lien: indépendamment du fait que le binaire soit une bibliothèque statique, une bibliothèque dynamique ou un framework, il sera lié à votre code objet au moment du lien après la compilation.

Quand vous pensez à la liaison avec une bibliothèque statique, ce qui se passe est assez clair: l'éditeur de liens copie le code de la bibliothèque (par exemple libFoo.a) dans votre binaire de sortie. Votre fichier de sortie augmente en taille mais n'a pas besoin de résoudre les dépendances externes au moment de l'exécution. Tout ce dont votre programme a besoin pour s'exécuter (par rapport à la bibliothèque statique) est présent après sa construction.

Avec une bibliothèque dynamique (.dylib ou framework fourni par le système), on s'attend à ce que la bibliothèque que vous liez soit présente quelque part dans le chemin du chargeur de bibliothèque dynamique du système lorsque vous exécutez votre programme. De cette façon, vous n'avez pas la charge de copier toutes les bibliothèques externes tierces dans votre binaire, et tous les différents programmes sur un ordinateur qui sont également liés à cette bibliothèque pourront la trouver, ce qui économise un minimum d'espace disque, mais aussi potentiellement de l'espace mémoire, selon comment et où le système met en cache les bibliothèques.

Un framework ressemble beaucoup à une bibliothèque dynamique, mais peut contenir des ressources dans sa structure de répertoires (images, audio, autres frameworks, etc.). Dans ce cas, une simple bibliothèque statique ou un fichier .dylib ne le coupera pas, vous devrez peut-être créer un lien vers un framework juste pour qu'il puisse trouver ce dont il a besoin pour fonctionner correctement.

Lorsque vous créez un lien vers un framework tiers (dites quelque chose que vous avez téléchargé depuis github et que vous avez créé vous-même), il se peut qu'il ne soit pas présent sur le système sur lequel vous avez l'intention de fonctionner. Dans ce cas, vous ne feriez pas seulement un lien vers le framework, mais vous l'intégreriez également dans votre bundle d'applications en utilisant la phase "Copier les Frameworks". Lorsque votre programme s'exécute, l'éditeur de liens d'exécution (alias le résolveur) cherchera à l'intérieur de votre bundle en plus du chemin du chargeur système, trouvera le cadre intégré et le liera afin que votre application ait le code dont elle a besoin pour s'exécuter.

Enfin, ce qui est proprement un "binaire incorporé" est un exécutable que vous intégrez à la fois dans votre bundle d'application via une phase de copie de fichiers et que vous exécutez vous-même, peut-être avec un appel à popen()ou similaire. Le binaire intégré peut être appelé par votre programme, mais il n'y est pas lié. C'est une entité entièrement externe (comme les programmes du /binrépertoire).

En pratique, pour les bibliothèques et les frameworks fournis par le système, vous établissez un lien avec eux et c'est tout ce que vous avez à faire.

Si vous avez besoin de lier une bibliothèque que vous avez construite qui n'a pas besoin de ressources intégrées (c'est-à-dire ne nécessite pas de framework pour exister), alors vous pouvez simplement créer un lien avec une bibliothèque statique. Si vous trouvez que vous avez plusieurs modules dans votre programme qui souhaitent utiliser le même code de bibliothèque, le convertir en un framework ou une bibliothèque dynamique et établir une liaison avec cela peut économiser de l'espace et peut être pratique (en particulier si l'utilisation de la mémoire est un problème).

Enfin, les frameworks peuvent inclure non seulement des ressources, mais aussi des fichiers d'en-tête et / ou de licence. Utiliser un framework pour véhiculer ces fichiers est en fait un mécanisme de distribution pratique si souvent vous voudrez peut-être incorporer un framework juste pour que ces éléments puissent être associés à votre binaire (c'est-à-dire que les exigences de licence peuvent rendre cela obligatoire).

--- ÉDITER ---

Adam Johns a posté la question suivante en commentaire:

C'est une excellente réponse. Il y a cependant quelque chose sur lequel je suis encore un peu confus. Que signifie exécuter le binaire vous-même? Voulez-vous dire simplement utiliser le code du framework intégré? Je sais que vous avez mentionné popen (), mais vous dites que mon application appelle popen ()? Je ne sais pas vraiment ce que ça veut dire.

Je dis qu'un binaire intégré n'est qu'un autre fichier de ressources dans votre bundle, comme un fichier audio ou une image, bien que le fichier soit plutôt un outil de ligne de commande exécutable. La popen()fonction ( man popendepuis votre terminal pour en savoir plus) vous permet d'exécuter des programmes arbitraires à partir d'un autre programme en cours d'exécution. La system()fonction est une autre manière. Il y en a d'autres, et je vais donner ici un exemple historique qui peut rendre la compréhension de l'utilisation d'un binaire intégré un peu plus claire:

Comme vous le savez probablement, lorsque vous lancez une application sur Mac OS X, elle est lancée avec un identifiant d'utilisateur de l'utilisateur actuel. Dans les installations les plus courantes, il s'agit de l'utilisateur par défaut sur le bureau admin, auquel un identifiant d'utilisateur est attribué 501.

Sur les systèmes d'exploitation Unix, seul l' rootutilisateur (ID utilisateur 0) a un accès complet à l'ensemble du système de fichiers. Il arrive parfois qu'un programme d'installation lancé par l'utilisateur Desktop ait besoin d'installer des fichiers dans un répertoire privilégié (pilotes par exemple). Dans ce cas, le programme d'application doit élever ses privilèges à l' rootutilisateur afin qu'il puisse écrire dans ces répertoires restreints.

Pour faciliter cela dans les systèmes d'exploitation via OS X 10.7, Apple a fourni dans son API Authorization Services la fonction AuthorizationExecuteWithPrivileges () (c'est maintenant obsolète, mais c'est toujours un exemple utile).

AuthorizationExecuteWithPrivileges()a pris comme argument un chemin vers un outil de ligne de commande pour exécuter en tant que root. L'outil de ligne de commande était un script shell exécutable ou un binaire compilé que vous aviez écrit pour exécuter votre logique d'installation. Cet outil a été installé dans votre ensemble d'applications comme n'importe quel autre fichier de ressources.

Lorsqu'il est appelé, le système d'exploitation affiche une boîte de dialogue d'autorisation demandant le mot de passe de l'utilisateur (vous l'avez déjà vu!) Et une fois entré, il exécute le programme au nom rootde votre application. Ce processus est similaire à la simple exécution d'un programme avec popen()vous-même, bien que popen()seul ne vous donne pas l'avantage d'une élévation de privilèges.


62
Comment savez-vous ces choses?
Ian Warburton

56
@IanWarburton Je programme des systèmes d'exploitation Apple depuis plus de 20 ans et j'ai ramassé quelques bribes ici et là. :)
par

1
@ JustAMartin Je veux dire link, mais vous avez raison de dire que vous devez également l'intégrer via une phase de copie de fichiers (sinon comment l'utiliseriez-vous?). Le but de l'utilisation d'un framework tiers ou d'un binaire intégré est d'exécuter le code fourni par l'entité. Avec un binaire intégré, aucune liaison n'est impliquée. Au moment de l'exécution, vous construisez un chemin vers le binaire, puis vous l'exécutez manuellement. Avec un framework, l'éditeur de liens au moment de la compilation le liera lorsque vous construirez votre application, puis (s'il s'agit d'un framework tiers) vous l'incorporerez via une phase de copie de fichiers, et enfin l'éditeur de liens d'exécution le liera à nouveau lorsque vous exécutez votre application. .
par

1
Les choses ne sont pas claires quant à ce que vous avez répondu à @JustAMartin. Le but de l'utilisation d'un framework tiers ou d'un binaire intégré est d'exécuter le code fourni par l'entité. De nos jours, les binaires intégrés peuvent également être des frameworks tiers. J'essaie de comprendre ce que vous voulez dire ici ... AFA J'ai compris, les binaires embarqués signifient, un binaire séparé du framework intégré sera introduit dans le bundle App, Et si vous liez simplement le même framework, il le mettrait dans le même binaire que celui de l'app. Veuillez me corriger si je me trompe ...
hariszaman

1
Peut-être qu'il y a une nouvelle magie Xcode qui chargera un framework intégré. Cela faisait un moment que j'avais besoin de cette fonctionnalité. Si vous souhaitez explorer davantage ce qui se passe, postez une nouvelle question ici sur SO.
par

35

En bref,

  • bibliothèques système, liez-les;
  • Bibliothèques tierces, intégrez-les.

Pourquoi?

  • si vous essayez d'incorporer des bibliothèques système, vous ne les trouverez pas dans la liste contextuelle;
  • si vous liez des bibliothèques tierces, vous aurez probablement un plantage.

7

Cela fait partie de la Dependencygestion [À propos]

Veuillez noter que Xcode 11ne contient que la Frameworks, Libraries, and Embedded Contentsection dans l' Generalonglet

Lien binaire

Build Phases -> Link Binary With Librariesest un miroir de General -> Linked Frameworks and Libraries.

Bibliothèque statique et cadre

Si vous ajoutez un Static Library or Static Frameworkà cette section, il apparaîtra dans le Frameworks groupe [À propos] ( Project Navigator -> <workspace/project> -> Frameworks) et une référence sera ajoutée à votre projet pour cela. Ensuite, il sera utilisé par Static Linker. Static Linkerau moment de la compilation inclura / copiera tout le code de la bibliothèque dans le fichier objet exécutable. Static linkerfonctionne en paire avecBuild Settings -> <Library/Framework> Search Paths

Static Library

Static Framework

  • Build Settings -> Framework Search Paths. Si vous n'ajoutez pas de a static frameworkà cette section, vous obtiendrez une erreur de compilation [No such module]

Incorporer le binaire

Bibliothèque statique et cadre statique

L'intégration n'aurait aucun sens pour a Static Libraryet Static Frameworkparce que leurs symboles sont compilés dans l'exécutable binaire. Xcode ne vous permettra pas de déposer un static librarysous la section Intégrer.

Cadre dynamique

Build Phases -> Embed Frameworksest un miroir de General -> Embedded Binaries. L'intégration ajoute en fait une copie du framework dans votre bundle d'applications. En conséquence, lorsqu'un cadre est ajouté / supprimé à la Embedsection, il sera automatiquement ajouté / supprimé à la Linkedsection. Par défaut, le dossier du bundle est Frameworksmais vous pouvez le modifier à l'aide de Destinationfield. De plus, vous pouvez spécifier un fichier Subpath.

Dynamic linker :dyldau chargement ou à l'exécution essaiera de trouver le framework intégré à l' aide de @rpath[About] S'il n'est pas trouvé, l'erreur se produira [dyld: Bibliothèque non chargée]

[Lorsque vous utilisez Link and Embed]

[Vocabulaire]

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.