2015-09-09 7 views
6

Quale dovrebbe essere il modo corretto di utilizzare le classi in una libreria statica in un framework privato, un'app e un'estensione? Il mio progetto di esempio può essere trovato qui https://github.com/keithyipkw/frameworkCome utilizzare la libreria statica in Embedded Private Frameworks e App su iOS

Nel secondo commit, l'SDK era collegato con .a. in esecuzione l'applicazione ha creato l'errore

Ld /Users/keithyip/Library/Developer/Xcode/DerivedData/FrameworkApp-bpzqozighjdtncegosucvgelzagc/Build/Products/Debug-iphonesimulator/FrameworkApp.app/FrameworkApp normal x86_64 
    cd /Users/keithyip/Documents/Workspace/FrameworkApp 
    export IPHONEOS_DEPLOYMENT_TARGET=8.4 
    export PATH="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin:/Applications/Xcode.app/Contents/Developer/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin" 
    /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -arch x86_64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator8.4.sdk -L/Users/keithyip/Library/Developer/Xcode/DerivedData/FrameworkApp-bpzqozighjdtncegosucvgelzagc/Build/Products/Debug-iphonesimulator -F/Users/keithyip/Library/Developer/Xcode/DerivedData/FrameworkApp-bpzqozighjdtncegosucvgelzagc/Build/Products/Debug-iphonesimulator -filelist /Users/keithyip/Library/Developer/Xcode/DerivedData/FrameworkApp-bpzqozighjdtncegosucvgelzagc/Build/Intermediates/FrameworkApp.build/Debug-iphonesimulator/FrameworkApp.build/Objects-normal/x86_64/FrameworkApp.LinkFileList -Xlinker -rpath -Xlinker @executable_path/Frameworks -Xlinker -objc_abi_version -Xlinker 2 -fobjc-arc -fobjc-link-runtime -Xlinker -no_implicit_dylibs -mios-simulator-version-min=8.4 /Users/keithyip/Library/Developer/Xcode/DerivedData/FrameworkApp-bpzqozighjdtncegosucvgelzagc/Build/Products/Debug-iphonesimulator/SDK.framework/SDK -Xlinker -dependency_info -Xlinker /Users/keithyip/Library/Developer/Xcode/DerivedData/FrameworkApp-bpzqozighjdtncegosucvgelzagc/Build/Intermediates/FrameworkApp.build/Debug-iphonesimulator/FrameworkApp.build/Objects-normal/x86_64/FrameworkApp_dependency_info.dat -o /Users/keithyip/Library/Developer/Xcode/DerivedData/FrameworkApp-bpzqozighjdtncegosucvgelzagc/Build/Products/Debug-iphonesimulator/FrameworkApp.app/FrameworkApp 

Undefined symbols for architecture x86_64: 
    "_OBJC_CLASS_$_GAI", referenced from: 
     objc-class-ref in AppDelegate.o 
ld: symbol(s) not found for architecture x86_64 
clang: error: linker command failed with exit code 1 (use -v to see invocation) 

Il simbolo è globale nel .a ma locale nella SDK

$ nm -a /Users/keithyip/Library/Developer/Xcode/DerivedData/FrameworkApp-bpzqozighjdtncegosucvgelzagc/Build/Products/Debug-iphonesimulator/SDK.framework/SDK | grep '_OBJC_CLASS_$_GAI' 
00000000000d94e0 s _OBJC_CLASS_$_GAI 

Nel terzo commettere, ho aggiunto il .a al bersaglio app. L'applicazione ha funzionato, ma con avvertenze

objc[3743]: Class GAI is implemented in both /Users/keithyip/Library/Developer/Xcode/DerivedData/FrameworkApp-bpzqozighjdtncegosucvgelzagc/Build/Products/Debug-iphonesimulator/SDK.framework/SDK and /Users/keithyip/Library/Developer/CoreSimulator/Devices/752A7B8E-405E-4403-BDD8-A168613774B1/data/Containers/Bundle/Application/D16B5121-2DA9-452B-9574-95B35AE3E197/FrameworkApp.app/FrameworkApp. One of the two will be used. Which one is undefined. 

ho controllato l'SDK e applicazione binaria in base ai percorsi di file in un messaggio

$ nm -a /Users/keithyip/Library/Developer/Xcode/DerivedData/FrameworkApp-bpzqozighjdtncegosucvgelzagc/Build/Products/Debug-iphonesimulator/SDK.framework/SDK | grep '_OBJC_CLASS_$_GAI' 
00000000000d94e0 s _OBJC_CLASS_$_GAI 

$ nm -a /Users/keithyip/Library/Developer/CoreSimulator/Devices/752A7B8E-405E-4403-BDD8-A168613774B1/data/Containers/Bundle/Application/D16B5121-2DA9-452B-9574-95B35AE3E197/FrameworkApp.app/FrameworkApp | grep '_OBJC_CLASS_$_GAI' 
0000000100032c88 s _OBJC_CLASS_$_GAI 

Scavando più a fondo con nm -m, libGoogleAnalyticsServices.a è diverso da altre librerie statiche. Il collegamento ad altre librerie in una libreria dinamica è privo di problemi.

0000000000002b20 (__DATA,__objc_data) private external _OBJC_CLASS_$_GAI 

sembra essere impossibile tenere i simboli pubblici

clang: error: invalid argument '-keep_private_externs' not allowed with '-dynamiclib' 
+0

Suppongo che tu abbia libGoogleAnalyticsServices.a nel tuo progetto nel primo caso che sembra contenere il codice di classe. Il tuo SDK ha solo le intestazioni? O lo stai collegando alla tua libreria statica? Vale la pena di mostrare il comando completo del linker che non è riuscito dalla build per il primo caso. –

+0

L'SDK di esempio contiene SDKObject che utilizza una classe in GA. Anche la mia app deve utilizzare direttamente la stessa classe. Non riesco a costruirlo a meno che non aggiungo il .a sia all'SDK che all'app. – keithyip

risposta

4

Normalmente si può semplicemente collegare una libreria statica ad una libreria dinamica. Tuttavia in questo caso i simboli in .a sono esterni privati ​​(visibilità = nascosti), è impossibile includere libGoogleAnalyticsServices.a in una libreria dinamica e utilizzare i simboli all'esterno della libreria dinamica su iOS.Le opzioni per risolvere come questo momento sono

  1. Cambiare la libreria dinamica per una libreria statica
  2. refactoring del codice per rimuovere GA dalla libreria dinamica
  3. Creare classi wrapper per GA in modo che i callees non hanno bisogno per creare un collegamento a GA

Se qualcuno imbattersi in una situazione simile in futuro, altre opzioni sono

  1. Chiedere al vend o per esporre i simboli
  2. Verificare se esiste un "objcopy --globalize-symbols" equivalente per iOS. La cosa più vicina è objconv mentre scrivo questo. Supporta OS X ma non iOS. An objcopy equivalent for Mac/iPhone?
2

preso il tuo progetto e provato un certo numero di cose. L'unica cosa che sembra funzionerebbe sarebbe stata quella di utilizzare l'opzione di compilazione -flat_namespace. Di default, tutto si costruisce con uno spazio dei nomi a due livelli.

Se si utilizza l'opzione -flat_namespace, il linker consente di utilizzare -undefined suppress che impedisce l'errore sui simboli non definiti. Il risultato sarebbe che si risolverebbero tutti completamente quando verrà eseguito il collegamento finale e collegherai in google.a con la build dell'app.

Sfortunatamente, la libreria di google non è piatta, quindi non può funzionare se non si ottiene una build piatta.

L'unica cosa che sicuramente funziona è quella di trasformare il tuo target SDK in target statico. Prendendo ciò che hai postato e facendo questa modifica, compila e corre senza errori. Quindi sembra la soluzione migliore o evitare il problema con altri mezzi, come hai notato nei tuoi commenti.

+0

Come hai eseguito l'applicazione con -undefined? Ho provato ma l'app si è bloccata a causa di simboli mancanti. – keithyip

+0

Non mi ha permesso di costruire perché la libreria di Google non era compatibile. Ho impostato l'opzione -flat_space sull'app e SDK e -intliminazione limitata solo sull'SDK e ho collegato Google solo nell'app, ma si è lamentato e non è mai arrivato fino in fondo. Solo successe stava impostando l'SDK su statico che funzionava alla prima e senza errori. –

0

sono stato colpito un problema simile, tranne che su OS X: stavo creando un quadro con un dylib all'interno, e il collegamento in una libreria statica. Volevo rendere pubblici i simboli sulla libreria statica disponibile per le app che utilizzano il framework. Anche se avevo impostato attributi di visibilità corretti sulle classi/metodi della libreria statica che volevo esportare, questi simboli erano spogliati dalla libreria finale.

Una soluzione era scrivere un po 'di codice nella libreria dinamica per fare riferimento a questi simboli nella lib statica; questo ha finito col fare in modo che il linker non togliesse i simboli di esportazione dalla lib statica.

La soluzione definitiva è stata la creazione della libreria statica come file oggetto rilocabile; la libreria dinamica risultante aveva tutti i simboli di esportazione dalla lib statica che volevo, e il bit del codice di riferimento nella lib dinamica non era richiesto.