phrase / ios-sdk

Phrase Over the Air iOS SDK
https://phrase.com
Other
14 stars 3 forks source link

Cocoapods Simulator Issue: Use of undeclared identifier 'Phrase' #33

Closed mzsanford closed 3 years ago

mzsanford commented 3 years ago

I'm integrating the PhraseSDK for OTA updates based on these instructions. This is a mixed Objective-C/Swift project with our AppDelegate in Objective-C. I was able to add the Cocoapod (pod 'PhraseSDK', '~> 3.0.1') and build to a device (iPhone SE 2, Intel Mac) without issue. When I attempt to run the same code in a simulator the build fails with Use of undeclared identifier 'Phrase' where I first reference it, calling [[Phrase shared] setDebugMode:true].

I'm using PhraseSDK 3.0.1 and Cocoapods 1.10.1 which should support xcframework. My understanding of #26 is that I should not need to do anything else. Is there something I'm missing?

winkelsdorf commented 3 years ago

Hi Matt,

that sounds like a valid setup, especially because it's building to the iPhone.

Initially I would've said that it is missing an import (Xcode not picking up on the @import PhraseSDK; and probably needs the bridging header to be imported via #import <PhraseSDK/PhraseSDK-Swift.h>, too) - but from not being able to use the SDK only on the simulator, I would say that you either have some architectures excluded via EXCLUDED_ARCHS or the older VALID_ARCHS is used and not inheriting all defaults.

I have verified it to be working both with ObjC-only and Swift-only projects, on x86_64 and M1. Iirc in a mixed environment it is sometime helpful to always embedded the Swift library via Project's Build Configuration, too.

Let me know if importing the bridging header or embedding the Swift Library helps in your case.

hth!

Frederik

mzsanford commented 3 years ago

We already use "Always Embed Swift Standard Libraries" if that's what you mean by Swift Library embedding. I added the bridging header but it did not help. We don't have any EXCLUDED_ARCHS set but we do have a user defined VALID_ARCHS set to $(ARCHS_STANDARD), which shows arm64 armv7. Our Architectures key is set to the same $(ARCHS_STANDARD)/arm64 armv7 value. I'm currently attempting all manner of brute force arch changes but no luck so far. Let me know if you have any other suggestions.

winkelsdorf commented 3 years ago

Yes, that's what I meant. Sorry, that was off the top of my head without having Xcode open. Thanks for the clarification on the architecture settings, that seems to be right.

Your CocoaPods version is valid. I just tried the same and it works with ObjC and CocoaPods 1.10.1 using xcframeworks:

Screen Shot 2021-02-25 at 18 53 55

Compiles and works on a Device and in the Simulator.

I would say there must be something wrong with the project or the Pod download.

Ok, let's try to investigate a few more things.

1) Do you see the PhraseSDK.xcframework inside the Pods directory?

Screen Shot 2021-02-25 at 18 52 24

2) Does it include the Simulator Slice?

Screen Shot 2021-02-25 at 18 52 37

If the files are in place, I am wondering if the build log shows more details?

mzsanford commented 3 years ago

Thanks so much for the quick reply and ideas. I do see the PhraseSDK.xcframework and it includes the Simulator slice. I pulled the text build log and found that it appears to select the correct slice as well:

Build target PhraseSDK of project Pods with configuration Debug

WriteAuxiliaryFile /Users/matt/Library/Developer/Xcode/DerivedData/PROJECT_NAME-cvvusrvpvbkiyfgrtgyxclhswofp/Build/Intermediates.noindex/Pods.build/Debug-iphonesimulator/PhraseSDK.build/Script-7ACA58FA174BB5EC0287349F3368E127.sh (in target 'PhraseSDK' from project 'Pods')
    cd /Users/matt/src/private/COMPANY_NAME/PROJECT_NAME/Pods
    write-file /Users/matt/Library/Developer/Xcode/DerivedData/PROJECT_NAME-cvvusrvpvbkiyfgrtgyxclhswofp/Build/Intermediates.noindex/Pods.build/Debug-iphonesimulator/PhraseSDK.build/Script-7ACA58FA174BB5EC0287349F3368E127.sh

PhaseScriptExecution [CP]\ Copy\ XCFrameworks /Users/matt/Library/Developer/Xcode/DerivedData/PROJECT_NAME-cvvusrvpvbkiyfgrtgyxclhswofp/Build/Intermediates.noindex/Pods.build/Debug-iphonesimulator/PhraseSDK.build/Script-7ACA58FA174BB5EC0287349F3368E127.sh (in target 'PhraseSDK' from project 'Pods')
    cd /Users/matt/src/private/COMPANY_NAME/PROJECT_NAME/Pods
    /bin/sh -c /Users/matt/Library/Developer/Xcode/DerivedData/PROJECT_NAME-cvvusrvpvbkiyfgrtgyxclhswofp/Build/Intermediates.noindex/Pods.build/Debug-iphonesimulator/PhraseSDK.build/Script-7ACA58FA174BB5EC0287349F3368E127.sh

Selected xcframework slice ios-arm64_i386_x86_64-simulator
rsync --delete -av --filter P .*.?????? --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" "/Users/matt/src/private/COMPANY_NAME/PROJECT_NAME/Pods/PhraseSDK/PhraseSDK.xcframework/ios-arm64_i386_x86_64-simulator/" "/Users/matt/Library/Developer/Xcode/DerivedData/PROJECT_NAME-cvvusrvpvbkiyfgrtgyxclhswofp/Build/Products/Debug-iphonesimulator/XCFrameworkIntermediates/PhraseSDK"
building file list ... done
./
PhraseSDK.framework/
PhraseSDK.framework/Info.plist
PhraseSDK.framework/PhraseSDK
PhraseSDK.framework/Headers/
PhraseSDK.framework/Headers/PhraseSDK-Swift.h
PhraseSDK.framework/Headers/PhraseSDK.h
PhraseSDK.framework/Modules/
PhraseSDK.framework/Modules/module.modulemap
PhraseSDK.framework/Modules/PhraseSDK.swiftmodule/
PhraseSDK.framework/Modules/PhraseSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc
PhraseSDK.framework/Modules/PhraseSDK.swiftmodule/arm64-apple-ios-simulator.swiftinterface
PhraseSDK.framework/Modules/PhraseSDK.swiftmodule/arm64.swiftdoc
PhraseSDK.framework/Modules/PhraseSDK.swiftmodule/arm64.swiftinterface
PhraseSDK.framework/Modules/PhraseSDK.swiftmodule/i386-apple-ios-simulator.swiftdoc
PhraseSDK.framework/Modules/PhraseSDK.swiftmodule/i386-apple-ios-simulator.swiftinterface
PhraseSDK.framework/Modules/PhraseSDK.swiftmodule/i386.swiftdoc
PhraseSDK.framework/Modules/PhraseSDK.swiftmodule/i386.swiftinterface
PhraseSDK.framework/Modules/PhraseSDK.swiftmodule/x86_64-apple-ios-simulator.swiftdoc
PhraseSDK.framework/Modules/PhraseSDK.swiftmodule/x86_64-apple-ios-simulator.swiftinterface
PhraseSDK.framework/Modules/PhraseSDK.swiftmodule/x86_64.swiftdoc
PhraseSDK.framework/Modules/PhraseSDK.swiftmodule/x86_64.swiftinterface
PhraseSDK.framework/_CodeSignature/
PhraseSDK.framework/_CodeSignature/CodeResources

sent 684754 bytes  received 452 bytes  1370412.00 bytes/sec
total size is 683109  speedup is 1.00
Copied /Users/matt/src/private/COMPANY_NAME/PROJECT_NAME/Pods/PhraseSDK/PhraseSDK.xcframework/ios-arm64_i386_x86_64-simulator to /Users/matt/Library/Developer/Xcode/DerivedData/PROJECT_NAME-cvvusrvpvbkiyfgrtgyxclhswofp/Build/Products/Debug-iphonesimulator/XCFrameworkIntermediates/PhraseSDK

I then tried calling Phrase.shared.debugMode = true in our first Swift controller to see if that would provide any new insights and that causes a linker failure when building:

ld: warning: ignoring file Pods/PhraseSDK/PhraseSDK.xcframework/ios-arm64_armv7/PhraseSDK.framework/PhraseSDK, missing required architecture x86_64 in file Pods/PhraseSDK/PhraseSDK.xcframework/ios-arm64_armv7/PhraseSDK.framework/PhraseSDK (2 slices)
…
Undefined symbols for architecture x86_64:
  "type metadata accessor for PhraseSDK.Phrase", referenced from:
      Framelord.TLFrameActivityViewController.(initCommon in _FEAFAB23AB862C84868837C639B1E8F2)() -> () in TLFrameActivityViewController.o
  "static PhraseSDK.Phrase.shared.getter : PhraseSDK.Phrase", referenced from:
      Framelord.TLFrameActivityViewController.(initCommon in _FEAFAB23AB862C84868837C639B1E8F2)() -> () in TLFrameActivityViewController.o
  "dispatch thunk of PhraseSDK.Phrase.debugMode.setter : Swift.Bool", referenced from:
      Framelord.TLFrameActivityViewController.(initCommon in _FEAFAB23AB862C84868837C639B1E8F2)() -> () in TLFrameActivityViewController.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

which is odd as this build log contains that same, correct, slice selection. I'm still researching how it selects one slice but then attempts to use something else but any ideas are welcome. Maybe related to https://github.com/CocoaPods/CocoaPods/issues/10026#issuecomment-736171353

winkelsdorf commented 3 years ago

You're very welcome!

Yes, that's really odd. It should never try looking for the x86_64 in the ios-arm64_armv7 directory but instead pickup the one in ios-arm64_i386_x86_64-simulator. The xcframework folder structure is correct.

I just created a fresh ObjC project with a simple podfile including the PhraseSDK which worked well on both a Device and the Simulator. Xcode 12.4 btw.

Then I added an empty dummy Swift file, Xcode asked and created the correct bridging header for the project itself. That worked too:

Screen Shot 2021-02-25 at 19 50 22

My educated guess is that there's something wrong with the project build configuration itself (probably due to old CocoaPod settings). Apple and CocoaPods change the templates occasionally and I found myself comparing fresh project's templates to existing one's from time to time to rule out any errors.

So best try 1) first to create an empty project, do a pod init, add the PhraseSDK and see if that works for you. 2) Add the bridging header by adding a Swift file, too.

If that works, you could try to re-create the CocoaPods workspace. Be sure to have a backup of your data first, as this is the danger zone ;)

I do it that way:

pod deintegrate
rm -rf MyWorkspace.xcworkspace/
rm -rf Pods/
pod install

That forces a recreation of everything pod and workspace related.

Edit: Yes, your link sounds familiar. Both two things we already covered, checking VALID_ARCHS (that should be fine now) and trying to re-create the workspace.

mzsanford commented 3 years ago

I noticed a warning from the only other xcframework Pod we use and confirmed that is also done not work in the simulator. So this is not a PhraseSDK specific problem. The other Pod is a development tool that is only being used against devices so nobody had noticed. I downgraded PhraseSDK to 2.3.1 and the pre-xcframework version works fine. That will un-block our development while I try to solve this Pods/xcframework mystery where it seems the linker goes back to the project directory instead of using the DerivedData version where it correctly placed the slice.

mzsanford commented 3 years ago

I pulled out the very long linker command used for the original Objective-C version and noticed it does not include the XCFrameworkIntermediates directory the rsync is using. It does contain -FPods/PhraseSDK/PhraseSDK.xcframework/ios-arm64_armv7 -FPods/PhraseSDK/PhraseSDK.xcframework/ios-arm64_i386_x86_64-simulator -FPods/PhraseSDK/PhraseSDK.xcframework/ios-arm64_x86_64-maccatalyst. It seems that Cocoapods/XCode end up including all slices as -F arguments in alphabetical order and thus pick up the wrong one. If I remove that first -F then it builds without warning but I've yet to find a solution within Cocoapods/XCode. Will update here if I find one.

winkelsdorf commented 3 years ago

@mzsanford Pretty impressive investigation, glad you were able to identify the underlying issue more. Fwiw, you should have no issues with using PhraseSDK 2.3.1 in the meantime, the backend API has been unchanged between those releases.

Btw: We're still shipping a compatibility framework (as "fat" universal binary) exactly for situations like this. Just point the Podfile to the git repo's Podspec: https://github.com/phrase/ios-sdk/blob/master/PhraseSDK-framework.podspec.

But in this case, I wouldn't bother as a solution to the linker path issue seems reachable.

Crossing my fingers for you!

winkelsdorf commented 3 years ago

@mzsanford Just a quick follow-up: Has this been resolved for you?

mzsanford commented 3 years ago

I ended up working around my editing the linker command for the prototype using Phrase. The project has since ended so I won't have any other feedback on it.

winkelsdorf commented 3 years ago

No problem, thanks for the follow up :)