iOS 框架测试在 Xcode 工作区中失败
iOS Framework Tests fail in Xcode Workspace
我有一个 Xcode 工作区,其中包含 2 个 Swift 项目、OAuth 和 Commons。
每个项目都有一个 iOS 框架目标和一个测试目标。他们互不依赖。
Commons 项目 没有依赖关系 而 OAuth 框架目标 导入 WebKit (import WebKit
).
现在,如果我 运行 Xcode 中的测试,OAuth 测试工作正常,但 Commons 测试失败并显示以下 Xcode 错误日志:
Test target CommonsTests encountered an error (Early unexpected exit, operation never finished bootstrapping - no restart will be attempted)
如果我运行使用以下命令从命令行进行测试
xcodebuild -workspace Workspace.xcworkspace -configuration Debug -destination "platform=iOS Simulator,name=iPhone 6" -scheme OAuth test
xcodebuild -workspace Workspace.xcworkspace -configuration Debug -destination "platform=iOS Simulator,name=iPhone 6" -scheme Commons test
我在第二个命令后得到以下错误:
The bundle “CommonsTests” couldn’t be loaded because it is damaged or missing necessary resources. Try reinstalling the bundle.
(dlopen_preflight(~/Library/Developer/Xcode/DerivedData/Workspace-aslcnsaomwggxqcxoozzfuztgszf/Build/Products/Debug-iphonesimulator/CommonsTests.xctest/CommonsTests): Library not loaded: @rpath/libswiftWebKit.dylib
Referenced from: ~/Library/Developer/Xcode/DerivedData/Workspace-aslcnsaomwggxqcxoozzfuztgszf/Build/Products/Debug-iphonesimulator/OAuth.framework/OAuth Reason: image not found)
我的设置可能有什么问题?
其他人也会出现此问题吗?
解决方法:
1) 如果我还在 CommonsTests 捆绑包中包含 WebKit,则一切正常。
但是由于 OAuth 和 Commons 框架之间没有依赖关系,我看不出有任何必要这样做的理由。
2) 如果我将 OAuth 项目(和目标)重命名为 OAuth2 之类的名称,一切正常。
这真的很奇怪。可能是名称冲突或缓存问题。
重命名解决方法是否解决了其他人的问题?
示例项目:https://www.dropbox.com/s/dn3ywhxlc9kb6y4/SampleProject.zip?dl=0
设置:
Xcode 7.3(Xcode 7.2 也出现错误)
OS X 10.11.4(OS X 10.11.3 也出现错误)
再次查看问题后,我找到了奇怪行为的原因。
简答:
/System/Library/PrivateFrameworks/OAuth.framework/OAuth
有一个私有的 OAuth Apple 框架,它与我自己的 OAuth 框架发生名称冲突,因为 xctest
似乎 link 这个框架。
长答案:
xctest
或 XCTest.framework
似乎从 Private Frameworks 文件夹加载 OAuth.framework。
如果使用 Xcode 内的工作空间,测试环境使用以下 dyld 环境变量:
"DYLD_FRAMEWORK_PATH“ = "/Users/{USER}/Library/Developer/Xcode/DerivedData/{PROJECT}/Build/Products/Debug-iphonesimulator:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Frameworks“;
该变量具有以下作用:
DYLD_FRAMEWORK_PATH
This is a colon separated list of directories that contain frameworks. The dynamic linker
searches these directories before it searches for the framework by its install name. It
allows you to test new versions of existing frameworks. (A framework is a library install name
that ends in the form XXX.framework/Versions/YYY/XXX or XXX.framework/XXX, where XXX and YYY
are any name.)
For each framework that a program uses, the dynamic linker looks for the framework in each
directory in DYLD_FRAMEWORK_PATH in turn. If it looks in all the directories and can't find
the framework, it searches the directories in DYLD_LIBRARY_PATH in turn. If it still can't
find the framework, it then searches DYLD_FALLBACK_FRAMEWORK_PATH and DYLD_FALL-BACK_LIBRARY_PATH DYLD_FALLBACK_LIBRARY_PATH
BACK_LIBRARY_PATH in turn.
DYLD_FRAMEWORK_PATH
定义框架的搜索目录并 覆盖 默认搜索路径和安装名称,它们嵌入到依赖的二进制文件中。即使二进制文件指定了框架安装路径,如
/System/Library/Frameworks/OAuth
环境变量导致目录的行为
/Users/{USER}/Library/Developer/Xcode/DerivedData/{PROJECT}/Build/Products/Debug-iphonesimulator
无论实际安装名称如何,都会搜索 OAuth.framework/OAuth
二进制文件。
此行为是有意为之的,因为它允许使用较新版本覆盖现有二进制文件中的框架,而无需重新编译二进制文件。
但是,如果两个框架具有相同的名称,它也可能导致误导 linking 二进制文件。然后,即使另一个框架由路径指定,也可以加载具有相同名称的框架之一。如果第一个目录在 DYLD_FRAMEWORK_PATH
中包含在另一个目录之前或根本不包含,则第一个目录将因其名称而被选中,而不考虑指定的安装名称路径。
具体例子:
xctest二进制加载命令:
/System/Library/PrivateFrameworks/OAuth.framework/OAuth (compatibility version 300.0.0, current version 1280.24.0)
OAuth 存在于以下路径中:
/System/Library/PrivateFrameworks/OAuth.framework/OAuth
/Users/{USER}/Library/Developer/Xcode/DerivedData/{PROJECT}/Build/Products/Debug-iphonesimulator/OAuth.framework/OAuth
xctest 使用以下环境变量启动:
"DYLD_FRAMEWORK_PATH“ = "/Users/{USER}/Library/Developer/Xcode/DerivedData/{PROJECT}/Build/Products/Debug-iphonesimulator:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Frameworks“;
然后是
的 OAuth 框架
/Users/{USER}/Library/Developer/Xcode/DerivedData/{PROJECT}/Build/Products/Debug-iphonesimulator/OAuth.framework/OAuth
即使安装名称是
也会使用
/System/Library/PrivateFrameworks/OAuth.framework/OAuth
我有一个 Xcode 工作区,其中包含 2 个 Swift 项目、OAuth 和 Commons。
每个项目都有一个 iOS 框架目标和一个测试目标。他们互不依赖。
Commons 项目 没有依赖关系 而 OAuth 框架目标 导入 WebKit (import WebKit
).
现在,如果我 运行 Xcode 中的测试,OAuth 测试工作正常,但 Commons 测试失败并显示以下 Xcode 错误日志:
Test target CommonsTests encountered an error (Early unexpected exit, operation never finished bootstrapping - no restart will be attempted)
如果我运行使用以下命令从命令行进行测试
xcodebuild -workspace Workspace.xcworkspace -configuration Debug -destination "platform=iOS Simulator,name=iPhone 6" -scheme OAuth test
xcodebuild -workspace Workspace.xcworkspace -configuration Debug -destination "platform=iOS Simulator,name=iPhone 6" -scheme Commons test
我在第二个命令后得到以下错误:
The bundle “CommonsTests” couldn’t be loaded because it is damaged or missing necessary resources. Try reinstalling the bundle.
(dlopen_preflight(~/Library/Developer/Xcode/DerivedData/Workspace-aslcnsaomwggxqcxoozzfuztgszf/Build/Products/Debug-iphonesimulator/CommonsTests.xctest/CommonsTests): Library not loaded: @rpath/libswiftWebKit.dylib
Referenced from: ~/Library/Developer/Xcode/DerivedData/Workspace-aslcnsaomwggxqcxoozzfuztgszf/Build/Products/Debug-iphonesimulator/OAuth.framework/OAuth Reason: image not found)
我的设置可能有什么问题? 其他人也会出现此问题吗?
解决方法:
1) 如果我还在 CommonsTests 捆绑包中包含 WebKit,则一切正常。 但是由于 OAuth 和 Commons 框架之间没有依赖关系,我看不出有任何必要这样做的理由。
2) 如果我将 OAuth 项目(和目标)重命名为 OAuth2 之类的名称,一切正常。 这真的很奇怪。可能是名称冲突或缓存问题。
重命名解决方法是否解决了其他人的问题?
示例项目:https://www.dropbox.com/s/dn3ywhxlc9kb6y4/SampleProject.zip?dl=0
设置:
Xcode 7.3(Xcode 7.2 也出现错误)
OS X 10.11.4(OS X 10.11.3 也出现错误)
再次查看问题后,我找到了奇怪行为的原因。
简答:
/System/Library/PrivateFrameworks/OAuth.framework/OAuth
有一个私有的 OAuth Apple 框架,它与我自己的 OAuth 框架发生名称冲突,因为 xctest
似乎 link 这个框架。
长答案:
xctest
或 XCTest.framework
似乎从 Private Frameworks 文件夹加载 OAuth.framework。
如果使用 Xcode 内的工作空间,测试环境使用以下 dyld 环境变量:
"DYLD_FRAMEWORK_PATH“ = "/Users/{USER}/Library/Developer/Xcode/DerivedData/{PROJECT}/Build/Products/Debug-iphonesimulator:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Frameworks“;
该变量具有以下作用:
DYLD_FRAMEWORK_PATH
This is a colon separated list of directories that contain frameworks. The dynamic linker
searches these directories before it searches for the framework by its install name. It
allows you to test new versions of existing frameworks. (A framework is a library install name
that ends in the form XXX.framework/Versions/YYY/XXX or XXX.framework/XXX, where XXX and YYY
are any name.)
For each framework that a program uses, the dynamic linker looks for the framework in each
directory in DYLD_FRAMEWORK_PATH in turn. If it looks in all the directories and can't find
the framework, it searches the directories in DYLD_LIBRARY_PATH in turn. If it still can't
find the framework, it then searches DYLD_FALLBACK_FRAMEWORK_PATH and DYLD_FALL-BACK_LIBRARY_PATH DYLD_FALLBACK_LIBRARY_PATH
BACK_LIBRARY_PATH in turn.
DYLD_FRAMEWORK_PATH
定义框架的搜索目录并 覆盖 默认搜索路径和安装名称,它们嵌入到依赖的二进制文件中。即使二进制文件指定了框架安装路径,如
/System/Library/Frameworks/OAuth
环境变量导致目录的行为
/Users/{USER}/Library/Developer/Xcode/DerivedData/{PROJECT}/Build/Products/Debug-iphonesimulator
无论实际安装名称如何,都会搜索 OAuth.framework/OAuth
二进制文件。
此行为是有意为之的,因为它允许使用较新版本覆盖现有二进制文件中的框架,而无需重新编译二进制文件。
但是,如果两个框架具有相同的名称,它也可能导致误导 linking 二进制文件。然后,即使另一个框架由路径指定,也可以加载具有相同名称的框架之一。如果第一个目录在 DYLD_FRAMEWORK_PATH
中包含在另一个目录之前或根本不包含,则第一个目录将因其名称而被选中,而不考虑指定的安装名称路径。
具体例子:
xctest二进制加载命令:
/System/Library/PrivateFrameworks/OAuth.framework/OAuth (compatibility version 300.0.0, current version 1280.24.0)
OAuth 存在于以下路径中:
/System/Library/PrivateFrameworks/OAuth.framework/OAuth
/Users/{USER}/Library/Developer/Xcode/DerivedData/{PROJECT}/Build/Products/Debug-iphonesimulator/OAuth.framework/OAuth
xctest 使用以下环境变量启动:
"DYLD_FRAMEWORK_PATH“ = "/Users/{USER}/Library/Developer/Xcode/DerivedData/{PROJECT}/Build/Products/Debug-iphonesimulator:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Frameworks“;
然后是
的 OAuth 框架
/Users/{USER}/Library/Developer/Xcode/DerivedData/{PROJECT}/Build/Products/Debug-iphonesimulator/OAuth.framework/OAuth
即使安装名称是
也会使用
/System/Library/PrivateFrameworks/OAuth.framework/OAuth