Wann sollten wir in Xcode "eingebettete Binärdateien" anstelle von "verknüpften Frameworks" verwenden?

140

Es gibt eine gute Frage zum Unterschied zwischen diesen beiden Optionen, wie unter Link Binär mit Bibliotheken VS Embed Frameworks beschrieben .

Scheint, als hätten wir Optionen, um beide zu verwenden. Fragen Sie sich nur, in welchem ​​Fall wir eingebettete Binärdateien besser verwenden sollten, als ein verknüpftes Framework.

Gibt es solide Beispiele, um dies klarer anzugehen? Vielen Dank

Wald
quelle
Mögliches Duplikat von Link Binary mit Bibliotheken VS Embed Frameworks
Suhaib

Antworten:

239

Die von Ihnen verknüpfte Frage bezieht sich auf die Funktion "Binär mit Bibliotheken verknüpfen", die sich etwas von einer eingebetteten Binärdatei unterscheidet.

"Binär mit Bibliotheken verknüpfen" bedeutet, was Sie in Bezug auf die Verknüpfung erwarten würden: Unabhängig davon, ob es sich bei der Binärdatei um eine statische Bibliothek, eine dynamische Bibliothek oder ein Framework handelt, wird sie zum Zeitpunkt der Verknüpfung nach der Kompilierung mit Ihrem Objektcode verknüpft.

Wenn Sie an eine Verknüpfung mit einer statischen Bibliothek denken, ist das, was passiert, ziemlich klar: Der Linker kopiert den Code aus der Bibliothek (z. B. libFoo.a) in Ihre Ausgabe-Binärdatei. Ihre Ausgabedatei wird größer, muss jedoch zur Laufzeit keine externen Abhängigkeiten auflösen. Alles, was Ihr Programm ausführen muss (in Bezug auf die statische Bibliothek), ist nach der Erstellung vorhanden.

Bei einer dynamischen Bibliothek (.dylib oder vom System bereitgestelltes Framework) wird erwartet, dass die Bibliothek, mit der Sie verknüpfen, beim Ausführen Ihres Programms irgendwo im Ladepfad der dynamischen Bibliothek des Systems vorhanden ist. Auf diese Weise haben Sie nicht den Aufwand, alle externen Bibliotheken von Drittanbietern in Ihre Binärdatei zu kopieren, und alle verschiedenen Programme auf einem Computer, die ebenfalls mit dieser Bibliothek verknüpft sind, können sie finden, was aber auch minimalen Speicherplatz spart Möglicherweise Speicherplatz, abhängig davon, wie und wo das System Bibliotheken zwischenspeichert.

Ein Framework ähnelt einer dynamischen Bibliothek, kann jedoch Ressourcen in seiner Verzeichnisstruktur enthalten (Bilder, Audio, andere Frameworks usw.). In diesem Fall wird eine einfache statische Bibliothek oder eine .dylib-Datei nicht geschnitten, sodass Sie möglicherweise eine Verknüpfung zu einem Framework herstellen müssen, damit es findet, was für eine ordnungsgemäße Ausführung erforderlich ist.

Wenn Sie eine Verknüpfung zu einem Framework eines Drittanbieters herstellen (z. B. etwas, das Sie von github heruntergeladen und selbst erstellt haben), ist es möglicherweise nicht auf dem System vorhanden, auf dem Sie ausgeführt werden möchten. In diesem Fall würden Sie nicht nur eine Verknüpfung zum Framework herstellen, sondern es auch mithilfe der Phase "Frameworks kopieren" in Ihr Anwendungspaket einbetten. Wenn Ihr Programm ausgeführt wird, wird der Laufzeit-Linker (auch als Resolver bezeichnet) zusätzlich zum Systemladepfad in Ihrem Bundle nachsehen, das eingebettete Framework finden und verknüpfen, damit Ihre App den Code hat, den sie zum Ausführen benötigt.

Was eigentlich eine "eingebettete Binärdatei" ist, ist eine ausführbare Datei, die Sie beide über eine Phase "Dateien kopieren" in Ihr Anwendungspaket einbetten und die Sie selbst ausführen, möglicherweise mit einem Aufruf von popen()oder ähnlichem. Die eingebettete Binärdatei wird möglicherweise von Ihrem Programm aufgerufen, ist jedoch nicht damit verknüpft. Es ist eine vollständig externe Entität (wie Programme im /binVerzeichnis).

In der Praxis werden Sie für vom System bereitgestellte Bibliotheken und Frameworks einen Link zu diesen erstellen, und das ist alles, was Sie tun müssen.

Wenn Sie eine von Ihnen erstellte Bibliothek verknüpfen müssen, für die keine eingebetteten Ressourcen erforderlich sind (dh für die kein Framework erforderlich ist), können Sie einfach eine Verknüpfung mit einer statischen Bibliothek herstellen. Wenn Sie feststellen, dass Ihr Programm mehrere Module enthält, die denselben Bibliothekscode verwenden möchten, kann das Konvertieren in ein Framework oder eine dynamische Bibliothek und das Verknüpfen mit diesem Modul Platz sparen und praktisch sein (insbesondere, wenn die Speichernutzung ein Problem darstellt).

Schließlich können Frameworks nicht nur Ressourcen, sondern auch Header- und / oder Lizenzdateien enthalten. Die Verwendung eines Frameworks zur Übermittlung dieser Dateien ist eigentlich ein praktischer Verteilungsmechanismus, so dass Sie häufig ein Framework einbinden möchten, damit diese Dinge zusammen mit Ihrer Binärdatei markiert werden können (dh Lizenzanforderungen können dies obligatorisch machen).

--- BEARBEITEN ---

Adam Johns hat die folgende Frage als Kommentar gepostet:

Dies ist eine großartige Antwort. Es gibt jedoch etwas, bei dem ich immer noch ein wenig verwirrt bin. Was bedeutet es, die Binärdatei selbst auszuführen? Meinen Sie einfach den Code des eingebetteten Frameworks? Ich weiß, dass Sie popen () erwähnt haben, aber Sie sagen, meine App ruft popen () auf? Ich weiß nicht wirklich was das bedeutet.

Ich sage, eine eingebettete Binärdatei ist nur eine andere Ressourcendatei in Ihrem Bundle, wie eine Audiodatei oder ein Bild, obwohl die Datei stattdessen ein ausführbares Befehlszeilentool ist. Mit der popen()Funktion ( man popenvon Ihrem Terminal aus, um mehr darüber zu erfahren) können Sie beliebige Programme von einem anderen laufenden Programm ausführen. Die system()Funktion ist ein anderer Weg. Es gibt andere, und ich werde hier ein historisches Beispiel geben, das das Verständnis der Verwendung einer eingebetteten Binärdatei etwas klarer macht:

Wie Sie wahrscheinlich wissen, wird eine App unter Mac OS X mit einer Benutzer-ID des aktuellen Benutzers gestartet. Bei den meisten gängigen Installationen ist dies der Standardbenutzer am Desktop admin, dem die Benutzer-ID zugewiesen wird 501.

Unter Unix-basierten Betriebssystemen hat nur der rootBenutzer (Benutzer-ID 0) vollen Zugriff auf das gesamte Dateisystem. Manchmal muss ein vom Desktop-Benutzer gestartetes Installationsprogramm Dateien in einem privilegierten Verzeichnis installieren (z. B. Treiber). In diesem Fall muss das Anwendungsprogramm seine Berechtigungen an den rootBenutzer weitergeben, damit es in diese eingeschränkten Verzeichnisse schreiben kann.

Um dies unter Betriebssystemen unter OS X 10.7 zu vereinfachen, hat Apple in seiner Authorization Services-API die Funktion AuthorizationExecuteWithPrivileges () bereitgestellt (dies ist jetzt veraltet, aber immer noch ein nützliches Beispiel).

AuthorizationExecuteWithPrivileges()nahm als Argument einen Pfad zu einem Befehlszeilentool, das als ausgeführt werden soll root. Das Befehlszeilentool war ein ausführbares Shell-Skript oder eine kompilierte Binärdatei, die Sie zum Ausführen Ihrer Installationslogik geschrieben haben. Dieses Tool wurde wie jede andere Ressourcendatei in Ihrem Anwendungspaket installiert.

Wenn das Betriebssystem aufgerufen wird, wird ein Autorisierungsdialogfeld angezeigt, in dem Sie nach dem Kennwort des Benutzers gefragt werden (das haben Sie bereits gesehen!). Bei Eingabe wird das Programm wie rootim Namen Ihrer App ausgeführt. Dieser Vorgang ähnelt dem Ausführen eines Programms mit sich popen()selbst, popen()bietet Ihnen jedoch allein nicht den Vorteil einer Eskalation von Berechtigungen.

Par
quelle
62
Woher weißt du diese Dinge?
Ian Warburton
56
@ IanWarburton Ich programmiere seit über 20 Jahren Apple-Betriebssysteme und habe hier und da ein paar Kleinigkeiten entdeckt. :)
Par
1
@ JustAMartin Ich meine link, aber Sie haben Recht , dass Sie es auch über eine Kopierdatei-Phase einbetten müssen (wie würden Sie es sonst verwenden?). Das Ziel der Verwendung eines Frameworks eines Drittanbieters oder einer eingebetteten Binärdatei besteht darin, den von der Entität bereitgestellten Code auszuführen. Bei einer eingebetteten Binärdatei ist keine Verknüpfung erforderlich. Zur Laufzeit erstellen Sie einen Pfad zur Binärdatei und führen ihn dann manuell aus. Mit einem Framework verknüpft der Linker zur Kompilierungszeit es, wenn Sie Ihre App erstellen. Wenn es sich um ein Framework eines Drittanbieters handelt, binden Sie es über eine Phase zum Kopieren von Dateien ein. Schließlich verknüpft der Laufzeit-Linker es erneut, wenn Sie Ihre App ausführen .
Par
1
Die Dinge sind etwas unklar, was Sie auf @JustAMartin geantwortet haben. Das Ziel der Verwendung eines Frameworks eines Drittanbieters oder einer eingebetteten Binärdatei besteht darin, den von der Entität bereitgestellten Code auszuführen. Heutzutage können eingebettete Binärdateien auch Frameworks von Drittanbietern sein. Ich versuche zu verstehen, was Sie hier meinen ... AFA Ich habe verstanden, dass eingebettete Binärdateien bedeuten, dass eine separate Binärdatei des eingebetteten Frameworks in das App-Bundle eingeführt wird. Wenn Sie nur dasselbe Framework verknüpfen, wird dies in dieselbe Binärdatei wie eingefügt das der App. Bitte korrigieren Sie mich Wenn ich falsch
liege
1
Vielleicht gibt es neue Xcode-Magie, die ein eingebettetes Framework lädt. Es ist schon eine Weile her, dass ich diese Funktionalität gebraucht habe. Wenn Sie mehr darüber erfahren möchten, was los ist, stellen Sie bitte hier auf SO eine neue Frage.
Par
35

Zusamenfassend,

  • Systembibliotheken, verknüpfen Sie sie;
  • Betten Sie Bibliotheken von Drittanbietern ein.

Warum?

  • Wenn Sie versuchen, Systembibliotheken einzubetten, werden Sie diese nicht in der Popup-Liste finden.
  • Wenn Sie Bibliotheken von Drittanbietern verknüpfen, kommt es wahrscheinlich zu einem Absturz.
Strahlende Zukunft
quelle
6

Es ist ein Teil des DependencyManagements [About]

Bitte beachten Sie, dass Xcode 11nur ein Frameworks, Libraries, and Embedded ContentAbschnitt in der GeneralRegisterkarte enthält

Link Binär

Build Phases -> Link Binary With Librariesist ein Spiegel von General -> Linked Frameworks and Libraries.

Statische Bibliothek und Framework

Wenn Sie Static Library or Static Frameworkdiesem Abschnitt ein hinzufügen , wird es in der Frameworks Gruppe [Info] ( Project Navigator -> <workspace/project> -> Frameworks) angezeigt und Ihrem Projekt wird ein Verweis hinzugefügt. Dann wird es von verwendet Static Linker. Static LinkerBeim Kompilieren wird der gesamte Code aus der Bibliothek in die ausführbare Objektdatei aufgenommen / kopiert . Static linkerarbeitet zusammen mitBuild Settings -> <Library/Framework> Search Paths

Static Library

Static Framework

  • Build Settings -> Framework Search Paths. Wenn Sie static frameworkdiesem Abschnitt kein hinzufügen , wird ein Kompilierungsfehler angezeigt [Kein solches Modul]

Binär einbetten

Statische Bibliothek und statisches Framework

Das Einbetten würde für a keinen Sinn machen Static Libraryund Static Frameworkweil die Symbole aus ihnen in die ausführbare Binärdatei kompiliert werden. Mit Xcode können Sie kein static libraryunter dem Abschnitt Einbetten ablegen.

Dynamisches Framework

Build Phases -> Embed Frameworksist ein Spiegel von General -> Embedded Binaries. Durch das Einbetten wird Ihrem Anwendungspaket tatsächlich eine Kopie des Frameworks hinzugefügt. Wenn ein Framework zu einem EmbedAbschnitt hinzugefügt / daraus entfernt wird, wird es automatisch zu einem LinkedAbschnitt hinzugefügt / daraus entfernt . Standardmäßig befindet sich der Ordner des Bundles Frameworks, Sie können ihn jedoch mithilfe des DestinationFelds ändern . Außerdem können Sie a angeben Subpath.

Dynamic linker :dyldBeim Laden oder Ausführen wird versucht, das eingebettete Framework mit @rpath[Info] zu finden. Wenn es nicht gefunden wird, tritt der Fehler auf [dyld: Bibliothek nicht geladen]

[Bei Verwendung von Link und Einbetten]

[Wortschatz]

yoAlex5
quelle