XCode 4.4.1 ignoriert LD_RUNPATH_SEARCH_PATHS

7

Ich habe es mit einem seltsamen Verhalten von XCode zu tun:

%Vor%

Grundsätzlich ignoriert es meine Runpath Search Path ( LD_RUNPATH_SEARCH_PATHS ) Konfiguration, die tatsächlich @loader_path/../Frameworks ist.

Ich kann in diesem Moment kein eingebettetes Framework laden: /

otool sagt

%Vor%

P.S. Wenn Sie sich fragen, ob ich die Kopie zur Framework-Build-Phase hinzugefügt habe, lautet die Antwort ja.

    
kilianc 01.09.2012, 02:02
quelle

1 Antwort

19

Die kurze Version

Das Problem besteht darin, dass beim Erstellen von SBJSON.framework der Installationsname nicht für die Verwendung von @rpath konfiguriert wurde. Wenn Ihre App die dynamische Bibliothek lädt, wird sie daher in /Library/Frameworks angezeigt und nicht dort, wo der RUN-Pfad Ihrer App angezeigt wird.

Um es zu beheben, müssen Sie eine Build-Einstellung für das SBJSON.framework -Ziel ändern. Ändern Sie die Einstellung Dynamic Library Install Name in @rpath/${EXECUTABLE_PATH} . Dann baue es einfach neu, verlinke es mit dem neu erstellten Framework und du kannst loslegen.

Die lange Version

Frameworks sind im Kern nur dynamische Bibliotheken. Dies bedeutet, dass der in der Bibliothek enthaltene Code nicht in Ihre App eingebettet ist, sondern aus dem Paket SBJSON.framework zur Laufzeit abgerufen wurde. Um dies zu tun, muss Ihre App wissen, wo Sie nach der dynamischen Bibliothek suchen müssen.

Das funktioniert so, wenn der Linker beim Verknüpfen mit einem Framework nicht die gesamte Bibliothek in Ihre App einbindet. Stattdessen fügt es nur einen kleinen Abschnitt hinzu, der der App mitteilt, wo sie die Bibliothek finden soll, wenn sie ausgeführt wird. Das bedeutet natürlich, dass der Compiler wissen muss, wo sich die Bibliothek zur Laufzeit befindet. Es findet diese Informationen, indem es auf den "Install Name" der dynamischen Bibliothek schaut.

Der Installationsname einer dynamischen Bibliothek ist im Wesentlichen nur der Pfad, zu dem die Bibliothek erwartet wird. In der Vergangenheit wurden die meisten dynamischen Bibliotheken und Frameworks systemweit geteilt. Dinge wie Foundation.framework und CoreData.framework zum Beispiel leben in /System/Library/Frameworks , und alle Apps können vernünftigerweise erwarten, sie dort zu finden. Wenn also CoreData.framework erstellt wird, wird der Installationsname auf /System/Library/Frameworks/... gesetzt. Wenn Xcode Ihre App mit Core Data verknüpft, wird der Installationsname des Frameworks angezeigt und es wird beim Start der App im Framework an diesen Pfad geladen.

Das ist alles gut und gut, aber es hilft Ihnen nicht, wenn Sie ein Framework in Ihre App einbetten müssen. Sie wissen nicht, wo sich die App zur Laufzeit auf dem System befinden wird. Der Benutzer kann es von /Applications ausführen, aber es kann auch von ~/Downloads ausgeführt werden. Es gibt keinen einzigen Pfad, den Sie als Installationsname angeben könnten, der zur Laufzeit immer korrekt auf das Framework zeigen würde.

Um damit umzugehen, können Sie den Installationsnamen des Frameworks auf @loader_path/../Frameworks setzen. Wenn der dynamische Loader @loader_path anzeigt, wird er durch den Pfad der aktuell geladenen App ersetzt. Wenn dieser Installationsname verwendet wird, kann das Framework im Ordner Frameworks einer beliebigen App installiert werden.

Aber die Dinge sind immer noch nicht perfekt. Das Framework diktiert immer noch, wo es platziert werden soll. Wenn eine andere App beispielsweise das Framework stattdessen in einen Ordner " Libraries " stellen möchte, ist es kein Glück. Das Framework ist verantwortlich dafür, wo es statt der App platziert werden kann. Dies ist eine Umkehrung des Abhängigkeitsbaums und ist nicht ideal. Die App sollte in der Lage sein, das Framework von überall dort zu laden, wo es es speichern will, egal was andere Frameworks machen.

So wurde in OS X 10.5 @rpath eingeführt. Wenn der Installationsname einer Dylib oder eines Frameworks mit @rpath beginnt, wendet sich der Loader und fragt die App, was "Runpath-Suchpfade" sind und ersetzt diese. Dadurch kann die App angeben, wo ihre Frameworks leben werden . Mit @rpath delegiert das Framework die Entscheidung zurück an die App. Die App kann @loader_path verwenden, wenn sie möchte, oder sie kann einen absoluten Pfad angeben, wenn sie dies möchte. Es könnte sogar einen freigegebenen Ordner angeben, der von einer ganzen Reihe von Apps verwendet wird.

Ihr Problem

Also, zu deinem Problem. Sie haben den Pfad für den Suchpfad der App korrekt auf @loader_path/../Frameworks festgelegt. Der Installationsname des Frameworks verwendet jedoch nicht @rpath ; tatsächlich verwendet es immer noch einen fest codierten Pfad zu /Library/Frameworks/... . Da der Installationsname des Frameworks nicht @rpath verwendet, werden die RUN-Pfade der App nicht einmal konsultiert. Es versucht einfach, SBJSON aus dem Ordner /Library zu verknüpfen. Da es nicht vorhanden ist, stürzt Ihre App ab, bevor sie gestartet wird.

Sie müssen den Installationsnamen des SBJSON-Frameworks ändern, um @rpath zu verwenden. Setzen Sie die Einstellung Dynamic Library Install Name auf @rpath/${EXECUTABLE_PATH} . ( ${EXECUTABLE_PATH} ist der relative Pfad zur internen dynamischen Bibliothek aus dem Ordner, der das Framework enthält.)

Sobald Sie das Framework mit dem neuen Installationsnamen erstellt haben, sollten Sie in der Lage sein, eine Verknüpfung mit dem neuen Framework herzustellen, sicherzustellen, dass es in den Frameworks/ -Ordner des App-Bundles kopiert wird, und Sie können loslegen!

P.S. Wenn das nicht alles klar ist, hat Mike Ash eine ziemlich gute Rezension von @rpath und Freunden gemacht. Sie können hier finden.

    
BJ Homer 01.09.2012, 06:19
quelle

Tags und Links