Xcode6Ios创建Cocoa Touch框架-架构问题
-
21-12-2019 - |
题
我正在尝试为iOS应用程序制作一个动态框架。改名的是新版本,我们可以在创建一个新项目时选择一个可可触摸框架,而不再需要添加聚合目标、运行脚本等来创建一个。我在构建框架时没有问题。但是当我试图在iOS应用程序中使用它时,我会遇到一些架构问题。
ld: warning: ignoring file /Library/Frameworks/MyFramework.framework/MyFramework, file was built for x86_64 which is not the architecture being linked (arm64): /Library/Frameworks/MyFramework.framework/MyFramework
Undefined symbols for architecture arm64:
"_OBJC_CLASS_$_MyFrameworkWebService", referenced from:
objc-class-ref in AppDelegate.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
ld: warning: ignoring file /Library/Frameworks/MyFramework.framework/MyFramework, file was built for x86_64 which is not the architecture being linked (armv7): /Library/Frameworks/MyFramework.framework/MyFramework
Undefined symbols for architecture armv7:
"_OBJC_CLASS_$_MyFrameworkWebService", referenced from:
objc-class-ref in AppDelegate.o
ld: symbol(s) not found for architecture armv7
clang: error: linker command failed with exit code 1 (use -v to see invocation)
嗯,我已经尝试更改框架项目和目标的设置(仅架构和构建有效架构和有效架构)。我为iOS应用程序项目做了同样的事情,但没有任何工作。我想有些事情我不明白。
例如,当我只为i386(iOS模拟器)构建框架时,请使用命令行检查 "xcrun lipo-info MyFramework",我有一个问题
劳工处:警告:忽略文件/库/框架/MyFramework。框架/MyFramework,文件是为x86_64构建的,而x86_64不是正在链接的体系结构(i386)。..
如果有人可以帮助我得到一个适用于所有iOS体系结构(包括模拟器)的框架。
解决方案 11
抱歉我让这个主题打开了这么长的时间......你们中的一些人已经正确回答了我的问题。当我写这个问题时,我没有捕获有两种切片(也称为FAT)框架(即将使用)。一个用于iOS设备,一个用于模拟器。当我发现我使用lipo命令用来融合两个切片并自动完成完整框架时。
其他提示
基于所有响应, raywenderlich .com 和 gist 由 chris conway 我想出了这个。
执行以下步骤,我能够构建一个Cocoa触摸框架(包括Swift和Objective-C文件),其中包含模拟器和设备的所有架构:
- 在框架的项目中创建一个新的(聚合)目标
- 在“构建阶段”中选择“添加运行脚本”和复制的这个文件
- 选择 聚合目标在 scheme 选择下降
- build target 聚合方案
希望它有助于:)
更新:修复了GIST中的错误,其中步骤#3中的路径不正确。感谢 tokuriku !!
更新在Xcode 7和8中,单击“文件”>“新建”>“目标...”,选择“其他”组以选择聚合目标
尝试以下步骤创建包含框架项目和应用程序项目的工作区。
工作区:
- 创建一个工作区。
框架项目:
- 在工作区内创建一个ios 可可触摸框架项目。
- 添加一个简单的目标c class myclass (标题.h和实现文件.m),并创建一个方法 - (void)问候语。
- go project build阶段> 标题> move myclass.h 从 project 到 public < /强>。
- 更改框架项目的方案,然后选择 iOS模拟器,然后构建。 (选择 iOS设备如果将此框架集成在设备上运行的应用程序。我将在此示例中继续使用模拟器)
- 您应该没有问题构建,框架构建是在派生数据目录中找到的,您可以在 constorizer 中找到。
应用程序项目:
- 在工作区内创建Swift单视图应用程序。
- 拖动到iOS模拟器框架构建(在调试-iphonesimulator 或 recelety-iphonesimulator )到您的项目中。
- 创建桥接标题以将客观的C类方法曝光到SWIFT。
- 导入桥接标题文件中的myclass.h。
- 请注意,如果找不到MyClass定义,则添加框架标题标题,构建设置标题搜索路径。
- 在 ViewController.swift 的ViewDidload中创建 myclass 的实例,然后调用问候语。
- 为目标添加框架>嵌入二进制文件
- 将方案更改为应用程序项目,然后选择 iOS模拟器,然后构建。
- 你应该能够看到问候留言。
请注意,上面的示例演示如何构建在模拟器中运行的应用程序。如果您需要创建在模拟器和设备上运行的通用静态库,则将一般步骤为:
- 为模拟器 构建库
- 构建设备 的库
- 使用 lipo 结合它们
网站上有很好的引用,这里。
为框架创建通用二进制文件:导航到框架派生数据目录然后 / cant / products ,以下命令应该帮助您在产品目录中创建一个通用二进制文件:
lipo -create -output "framework-test-01-universal" "Debug-iphonesimulator/framework-test-01.framework/framework-test-01" "Debug-iphoneos/framework-test-01.framework/framework-test-01"
.
注意, Framework-Test-01 是我的框架项目名称。
以下是创建fat(通用)框架的步骤:
套装
ONLY_ACTIVE_ARCH=NO
在Build Settings
在你的项目中。- 为模拟器构建库
- 为设备构建库
在控制台中打开
Products
框架的文件夹 (您可以通过打开框架文件夹和cd ..
从那里)
跑 这个脚本 从
Products
文件夹。它在此文件夹中创建fat框架。(或者按照下面的说明手动执行 4. 5.)framework_name="${$(basename $(find ./Debug-iphoneos -type d -name '*.framework' -maxdepth 1))%.*}" && \ cp -R Debug-iphoneos/$framework_name.framework ./$framework_name.framework && \ lipo -create -output "$framework_name.framework/$framework_name" "Debug-iphonesimulator/$framework_name.framework/$framework_name" "Debug-iphoneos/$framework_name.framework/$framework_name"
或:
结合这2个框架使用 利波 通过此脚本(替换
YourFrameworkName
到你的框架名称)lipo -create -output "YourFrameworkName" "Debug-iphonesimulator/YourFrameworkName.framework/YourFrameworkName" "Debug-iphoneos/YourFrameworkName.framework/YourFrameworkName"
替换为现有框架中的新二进制文件:
cp -R Debug-iphoneos/YourFrameworkName.framework ./YourFrameworkName.framework mv YourFrameworkName ./YourFrameworkName.framework/YourFrameworkName
- 利润:
./YourFrameworkName.framework
- 是现成的脂肪二进制! 您可以将其导入到您的项目中!
对于项目,不在 xcworkspace
-es:
您也可以尝试使用 这个要旨 但它似乎不适用于工作区中的项目。
我的做法与 vladof 类似,但希望更简单一些。我将该框架作为应用程序项目的子项目。
框架项目
- 创建一个新的 iOS Cocoa Touch 框架。称之为 MyLib。这将创建一个 MyLib.h
- 添加一个简单的 Cocoa Touch Obj-C 类 MyClass (.h & .m) 并在 .m 的实现中创建一个返回字符串的方法 - (NSString *)greetings;
- 在 MyLib.h 中,在底部附近添加 #import "MyClass.h"
- 在目标的“构建阶段/标头”部分中,将 MyClass.h 从“项目”部分移动到“公共”部分。
- 进行构建 (cmd-B)
- 关闭项目
应用项目
- 创建一个新的单视图应用程序项目,可以是 Swift,也可以是 Obj-C。称之为我的应用程序。
- 从 Finder 中,将 MyLib 项目文件拖到 MyApp 窗口的左侧组织器部分,并确保插入行位于 MyApp 的正下方。这使得 MyLib 成为 MyApp 的子项目。(在其他项目中仍然可以同样的方式使用)
- 单击管理器中的 MyApp,然后选择 MyApp 目标并选择构建阶段。
- 在目标依赖项中,单击 + 号并添加 MyLib。
- 在“与库链接”中,单击 + 号并添加 MyLib.framework。
对于 Obj-C 应用程序
- 在ViewController.m中,添加#import
- 在 viewDidLoad 中,添加以下行:
- MyLib *x = [[MyLib alloc] init];
- NSLog(@"%@", x.greetings);
- 运行该项目,您应该在调试窗口中看到该消息。-
对于 Swift 应用程序
- 在 ViewController.swift 中,添加 import MyLib
- 在 viewDidLoad 中,添加以下行:
- 变量x:我的库 = 我的库()
- println("(x.greetings())") -
通过这种方式,应用程序依赖于框架,因此如果您对框架类进行更改,则不必更改目标来单独构建框架,它只会先编译框架,然后再编译应用程序。
我已经改变了某人的脚本有点支持所有模拟器的架构:
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
# make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
# Step 1. Build Device and Simulator versions
xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator VALID_ARCHS="x86_64 i386" BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
# Step 2. Copy the framework structure to the universal folder
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"
# Step 3. Create universal binary file using lipo and place the combined executable in the copied framework directory
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}"
# Step 4. Convenience step to copy the framework to the project's directory
cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}"
# Step 5. Delete temporary build directory in the project's directory
rm -rf "${PROJECT_DIR}/build"
# Step 6. Convenience step to open the project's directory in Finder
open "${PROJECT_DIR}"
. 自从上述链接之前的旧视频不再可用。
vladof共享的方法周围的额外点,这些方法更适用于Swift基于Swift的框架
- 关联链路中的脚本需要修改以自Swift为ARM和I386的单独编译文件分开编译iPhoneSimulator和iPhoneOS复制所有文件
- 确保您只有archs=“x86_64”ocke_active_arch= no for iPhoneSimulator以避免模拟器的链接问题
- 确保您的界面/类扩展NSObject否则当您尝试使用swift中的代码时,您将遇到问题(它将抱怨无法使用()。
最后,我拿到了我的工作! 对不起大黄色框架,我不知道如何更好地格式化。
解决方案来自Claudio Romandi,但链接的脚本有一个小问题。我无法评论他的帖子,因为我需要50个声誉,所以我留下了很少的选择,而是为了复制他的帖子来拥有完整的解决方案..
- 在框架项目中创建一个新的(聚合)目标
- 在工作区中选择聚合并添加“新运行脚本阶段”
-
将以下代码放入其中:
#!/bin/sh UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal # make sure the output directory exists mkdir -p "${UNIVERSAL_OUTPUTFOLDER}" # Step 1. Build Device and Simulator versions xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build xcodebuild -target "${PROJECT_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build # Step 2. Copy the framework structure (from iphoneos build) to the universal folder cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/" # Step 3. Copy Swift modules (from iphonesimulator build) to the copied framework directory cp -R "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/." "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule" # Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}" # Step 5. Convenience step to copy the framework to the project's directory cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}" # Step 6. Convenience step to open the project's directory in Finder open "${PROJECT_DIR}"
-
在方案选择下拉下来选择聚合
- build,你已经完成了!
问题是模拟器目录指向非现有目录,将“框架”更改为“$ {project_name}”在2个地方执行以下诀窍:)
想要为skywinder 这里。我遵循这些步骤,但仍然无法让我的框架在模拟器上运行,只有设备。修复:
-i进入了框架的调试 - iphonesimulator版本,在模块/ [frameworkname]中.swiftmodule,我复制了所有I386和X86文件。
-i然后进入了新创建的框架的胖版本,并导航到同一个文件夹。我粘贴在i386和x86文件中(与已经存在的arm文件一起使用),然后将我的胖框架添加到我的项目中。
voila,她工作在模拟器和真实的设备上!这是Xcode 10 / Swift 4.2 btw
这个问题已发布一段时间以前(Xcode 6),但我最近用Xcode 10遇到了同样的问题。
所以问题是:构建的框架不支持足够的体系结构。
如果一个人不知道架构代表什么,不同的iPhone设备有不同的架构,这里是一个完整的列表:- ARM6:iPhone 1,2,3g
- arm7:用于最旧的iOS 7支持设备[32位]。 iphone 4, 4s
- ARM7S:在iPhone 5和5C中使用[32位]。 iphone 5,5c
- ARM64:在iPhone 5s中的64位臂处理器[64位]。 iPhone 5S 和上面。
- ARM64E:用于A12芯片组。 iphone xs / xs max / xr
- i386:对于32位模拟器
- x86_64:用于64位模拟器
所以,如果您在模拟器上使用框架,则框架需要支持I386或X86_64;如果您在iPhone 6上运行应用程序,则框架需要支持ARM64架构。
因此,在大多数情况下,框架需要支持所有上述架构。
现在回到如何解决问题。我们需要为两个设备和模拟器构建框架。
如何构建设备:
- 在“常规”中,指定“部署目标”。
- 在“构建设置”中,将“仅构建活动架构”将“否”
- 在“构建设置”中,确保“有效架构”列出所有 您需要的架构。通常我们只是使用默认值 选项(ARM64,ARM64E,ARMV7,ARMV7S)。
- 转到“编辑方案” - >“运行” - >“构建配置”,更改“构建 配置“释放”
- 选择“Active Scheme”Generic IOS设备“。命中cmd + b以构建项目。
- 右键单击[MyFrameWorkProject] .FrameWork在Xcode项目中的“产品”文件夹下,并在“查找器”中点击“Show”。[MyFrameWorkProject] .Framework支持所有规定的架构 第2步。
- 拖动[myframeworkproject] .framework到需要使用的项目 这个框架。此外,将[MyFrameWorkProject]拖动到“嵌入二进制文件”。
- 步骤1至4相同。
- 选择任何模拟器作为活动方案。命中cmd + b构建 项目。
- 步骤6至7与上述相同。
如何构建模拟器:
如何构建用于设备和模拟器:
有设备框架后,您需要将模拟器的框架与“Lipo”命令组合在一起。 将模拟器的框架重命名为[MyFrameWorkProject] _sim.framework并将两个框架复制到同一文件夹。在终端中运行命令(确保您在文件夹中):
lipo -create -output [MyFrameworkProject].framework/[MyFrameworkProject] [MyFrameworkProject].framework/MyFrameworkProject [MyFrameworkProject]_sim.framework/MyFrameworkProject
.
现在[myframeworkproject] .framework是支持模拟器和设备的最终产品。