Frage

Ich habe eine Cocoa-Anwendung, dass Verwendungen otool erforderlich gemeinsam genutzte Bibliotheken zu finden, dass eine App Bedürfnisse richtig funktionieren. Zum Beispiel sage ich otool -L auf einer App ausführen, die QTKit.framework verwendet. Ich erhalte eine Liste der gemeinsam genutzten Bibliotheken, die von dem Programm verwendet (einschließlich der grundlegenden Frameworks wie Cocoa.framework und AppKit.framework):

/System/Library/Frameworks/QTKit.framework/Versions/A/QTKit (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 476.0.0)
    /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 949.0.0)

..... and so on for a bunch of other frameworks

, die zeigt, dass die App QTKit.framework verwendet. Allerdings, wenn ich „otool -L“ wieder auf dem binären für QTKit.framework (/System/Library/Frameworks/QTKit.framework/Versions/A/QTKit) verwende ich diese:

/System/Library/Frameworks/QTKit.framework/Versions/A/QTKit (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox (compatibility version 1.0.0, current version 1.0.0)
/System/Library/PrivateFrameworks/CoreMedia.framework/Versions/A/CoreMedia (compatibility version 1.0.0, current version 1.0.0)
/System/Library/PrivateFrameworks/MediaToolbox.framework/Versions/A/MediaToolbox (compatibility version 1.0.0, current version 1.0.0)
/System/Library/PrivateFrameworks/VideoToolbox.framework/Versions/A/VideoToolbox (compatibility version 1.0.0, current version 1.0.0)
/System/Library/PrivateFrameworks/CoreMediaIOServices.framework/Versions/A/CoreMediaIOServices (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 751.0.0)
/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 1038.0.0)
/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit (compatibility version 1.0.0, current version 275.0.0)
/System/Library/Frameworks/QuickTime.framework/Versions/A/QuickTime (compatibility version 1.0.0, current version 1584.0.0)
/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore (compatibility version 1.2.0, current version 1.6.0)
/System/Library/Frameworks/IOSurface.framework/Versions/A/IOSurface (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox (compatibility version 1.0.0, current version 435.0.0)
/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.9.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 123.0.0)
/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 227.0.0)
/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices (compatibility version 1.0.0, current version 44.0.0)
/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 550.0.0)
/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices (compatibility version 1.0.0, current version 38.0.0)
/System/Library/Frameworks/CoreVideo.framework/Versions/A/CoreVideo (compatibility version 1.2.0, current version 1.6.0)

Das zeigt, eine Last mehr Gerüste, dass die ursprüngliche otool Ausgabe auf der App binären zeigten. Gibt es eine Möglichkeit rekursiv otool zu laufen zu haben, was bedeutet, es den Rahmen packt, dass die App braucht, geht dann in und sucht jede dieser Frameworks für Abhängigkeiten?

War es hilfreich?

Lösung

Nein, Sie haben immer wieder laufen otool oder dessen Parsing-Code integrieren ( hier ). Vergessen Sie nicht über @executable_path Handhabung.

Hier ist es in Python (ohne @executable_path, Kanonisierung oder Dateinamen-mit-Spaces unterstützt werden), da dies einfacher als zu debuggen Pseudo-Code versuchen:

import subprocess

def otool(s):
    o = subprocess.Popen(['/usr/bin/otool', '-L', s], stdout=subprocess.PIPE)
    for l in o.stdout:
        if l[0] == '\t':
            yield l.split(' ', 1)[0][1:]

need = set(['/Applications/iTunes.app/Contents/MacOS/iTunes'])
done = set()

while need:
    needed = set(need)
    need = set()
    for f in needed:
        need.update(otool(f))
    done.update(needed)
    need.difference_update(done)

for f in sorted(done):
    print f

Andere Tipps

Hier ist meine Lösung, dass ich fix macdeployqt die Ausgabe verwenden, wenn Homebrew installierten Bibliotheken. Was ich gefunden habe ist, dass macdeployqt macht einen guten Job des dylibs im Ordner Framework setzen, aber es funktioniert nicht die Pfade zu beheben.

https://github.com/jveitchmichaelis/deeplabel/blob/master /fix_paths_mac.py

Ich habe Nicholas' Skript modifiziert ein bisschen mehr verwendbar zu sein - es korrigiert @executable_path, @rpath und @loader_path. Dies ist nicht gerade die Produktion Code, aber es hat mich ohne Abhängigkeiten von anderen Macs laufen Anwendungen können bereits installiert ist.

Ausführen mit: python fix_paths_mac.py ./path/to/your.app/Contents/MacOS/your_exe. das heißt, es auf den binären innerhalb eines App-Pakets zeigen und es wird den Rest herauszufinden.

Ich bin davon ausgegangen, dass die meisten der Probleme von Sachen kommen zu /usr/local verknüpft. Also, wenn der Code feststellt, dass eine Abhängigkeit ist, dass auf eine Datei in /usr/local, es wird die Pfade entsprechend beheben. Sie können die pass Anweisung ändern, in einer Datei zu kopieren, wenn es nicht in dem Frameworks Ordner ist, aber ich habe nicht auf eine Situation gestoßen, wo es eine fehlende dylib, es ist nur falsch verknüpft.

import subprocess
import os
import sys
from shutil import copyfile

executable = sys.argv[1]
app_folder = os.path.join(*executable.split('/')[:-3])
content_folder = os.path.join(app_folder, "Contents")
framework_path = os.path.join(content_folder, "Frameworks")

print(executable)
print("Working in {} ".format(app_folder))

def file_in_folder(file, folder):
    return os.path.exists(os.path.join(folder, file))

def otool(s):
    o = subprocess.Popen(['/usr/bin/otool', '-L', s], stdout=subprocess.PIPE)

    for l in o.stdout:
        l = l.decode()

        if l[0] == '\t':
            path = l.split(' ', 1)[0][1:]

            if "@executable_path" in path:
                path = path.replace("@executable_path", "")
                # fudge here to strip /../ from the start of the path.
                path = os.path.join(content_folder, path[4:])

            if "@loader_path" in path:
                path = path.replace("@loader_path", framework_path)

            if "@rpath" in path:
                path = path.replace("@rpath", framework_path)

            dependency_dylib_name = os.path.split(path)[-1]

            if "usr/local" in path:
                if app_folder in s:

                    print("Warning: {} depends on {}".format(s, path))

                    if file_in_folder(dependency_dylib_name, framework_path):
                        print("Dependent library {} is already in framework folder".format(dependency_dylib_name))

                        print("Running install name tool to fix {}.".format(s))

                        if dependency_dylib_name == os.path.split(s)[-1]:
                            _ = subprocess.Popen(['install_name_tool', '-id', os.path.join("@loader_path", dependency_dylib_name), s], stdout=subprocess.PIPE)

                        _ = subprocess.Popen(['install_name_tool', '-change', path, os.path.join("@loader_path", dependency_dylib_name), s], stdout=subprocess.PIPE)
                else:
                    # Potentially you could copy in the offending dylib here.
                    pass

            yield path

need = set([executable])
done = set()

while need:
    needed = set(need)
    need = set()
    for f in needed:
        need.update(otool(f))
    done.update(needed)
    need.difference_update(done)
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top