在iOS项目中依赖Flutter Module-④报错Multiple commands produce/[CP] Embed Pods Frameworks
Multiple commands produce '/Users/user/Library/Developer/Xcode/DerivedData/MyProj-flazyqyatfvrvsgcoofvwrizuvot/Build/Products/Debug-iphoneos/MyProj.app/Frameworks/FMDB.framework':
1) That command depends on command in Target 'MyProj' (project 'MyProj'): script phase “[CP] Embed Pods Frameworks”
2) That command depends on command in Target 'MyProj' (project 'MyProj'): script phase “[CP] Embed Pods Frameworks”
Multiple commands produce '/Users/user/Library/Developer/Xcode/DerivedData/MyProj-flazyqyatfvrvsgcoofvwrizuvot/Build/Products/Debug-iphoneos/MyProj.app/Frameworks/MMKV.framework':
1) That command depends on command in Target 'MyProj' (project 'MyProj'): script phase “[CP] Embed Pods Frameworks”
2) That command depends on command in Target 'MyProj' (project 'MyProj'): script phase “[CP] Embed Pods Frameworks”
Multiple commands produce '/Users/user/Library/Developer/Xcode/DerivedData/MyProj-flazyqyatfvrvsgcoofvwrizuvot/Build/Products/Debug-iphoneos/MyProj.app/Frameworks/MMKVCore.framework':
1) That command depends on command in Target 'MyProj' (project 'MyProj'): script phase “[CP] Embed Pods Frameworks”
2) That command depends on command in Target 'MyProj' (project 'MyProj'): script phase “[CP] Embed Pods Frameworks”
Multiple commands produce '/Users/user/Library/Developer/Xcode/DerivedData/MyProj-flazyqyatfvrvsgcoofvwrizuvot/Build/Products/Debug-iphoneos/MyProj.app/Frameworks/Sentry.framework':
1) That command depends on command in Target 'MyProj' (project 'MyProj'): script phase “[CP] Embed Pods Frameworks”
2) That command depends on command in Target 'MyProj' (project 'MyProj'): script phase “[CP] Embed Pods Frameworks”
这个编译错误是Xcode10使用新构建系统之后才出现的,新构建系统为了提高可靠性和构建性能会检查重复构建/重复输出文件,检测到重复构建产物可能会抛出相关错误,Multiple commands produce '*.framework'
是其中之一。
重复构建产物是新版构建系统新增功能之一,更全面的介绍可以看官方的介绍文档 # Build System Release Notes for Xcode 10。
首先检查构建系统设置,用新版Xcode打开项目,点击屏幕左上角的File
-> WorkSpace Settings
,即可看到构建系统的配置项,如下图所示。
Xcode10以后默认使用
New Build System
,即新版构建系统,而旧版构建系统Legacy Build Sysytem
已经标记为Deprecated
,但是目前还能用。
我用的是Xcode12.5,默认使用New Build System
,排查这几个报错的framework后发现存在重复导入/依赖的情况,Flutter侧的iOS插件层依赖了MMKV
、FMDB
和Sentry
,另外在iOS侧也依赖了这几个库。编译Flutter Module阶段,插件层依赖的第三方库会被编译成相关的.xcframework
,最后通过本地podspec中转依赖将.xcframework
嵌入到iOS项目中,iOS侧通过CocoaPods依赖的第三方库在编译阶段也会被编译成.xcframework
嵌入到项目中。编译前存放在不同的路径下,但是编译时会加工导出到同一个路径下,如此就出现重复构建的问题。
# Build System Release Notes for Xcode 10 中虽然没有提到Multiple commands produce ...
,但是提到了duplicate output file
错误,要求确保某个Target的产物目录都在同一个编译阶段处理,不能在多个编译阶段重复生产/输出文件。
Targets which have multiple asset catalogs that aren’t in the same build phase may produce an error regarding a “duplicate output file”. (39810274)
Workaround: Ensure that all asset catalogs are processed by the same build phase in the target.
还提到It is an error for any individual file in the build to be produced by more than one build command.
,如果在多个构建命令中生产同一个文件也会出错。而前面展开的错误信息,则属于在Target的某个编译阶段重复构建某个.framework
,而且都发生在[CP] Embed Pods Frameworks
脚本阶段。在Xcode中展开[CP] Embed Pods Frameworks
即可看到相关的脚本和输入输出列表文件,具体包括以下文件:
- Pods-MyProj-frameworks.sh
- Pods-MyProj-frameworks-Debug-input-files.xcfilelist
- Pods-MyProj-frameworks-Debug-output-files.xcfilelist
- Pods-MyProj-frameworks-Release-input-files.xcfilelist
- Pods-MyProj-frameworks-Release-output-files.xcfilelist
查看Pods-MyProj-frameworks.sh
源码后发现,这个脚本会逐个调用install_framework
函数把Pods中依赖的第三方库都重新生成签名的framework,调用install_framework
时会传入库文件的导入路径。可以看到出现了重复的第三方库,但是路径不一样。${BUILT_PRODUCTS_DIR}
里面是CococPods正常依赖的第三方库,${PODS_XCFRAMEWORKS_BUILD_DIR}
里面是依赖的Flutter编译产物(xcframework)。
...
install_framework "${BUILT_PRODUCTS_DIR}/FMDB/FMDB.framework"
install_framework "${BUILT_PRODUCTS_DIR}/MMKV/MMKV.framework"
install_framework "${BUILT_PRODUCTS_DIR}/MMKVCore/MMKVCore.framework"
...
install_framework "${PODS_XCFRAMEWORKS_BUILD_DIR}/Flutter/Flutter.framework"
install_framework "${PODS_XCFRAMEWORKS_BUILD_DIR}/FMDB/FMDB.framework"
install_framework "${PODS_XCFRAMEWORKS_BUILD_DIR}/MMKV/MMKV.framework"
install_framework "${PODS_XCFRAMEWORKS_BUILD_DIR}/MMKVCore/MMKVCore.framework"
install_framework "${PODS_XCFRAMEWORKS_BUILD_DIR}/mmkv_flutter/mmkv_flutter.framework"
而在install_framework
函数内部,会计算产物的导出路径,将构建的framework导出到这个路径。而且构建产物都放在${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}
目录下,具体路径由framework名称决定。如果导入路径中的framework名称重复,则会出现重复构建framework的情况。
local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
binary="${destination}/${basename}.framework/${basename}"
再打开Pods-MyProj-frameworks-Debug-input-files.xcfilelist
和Pods-MyProj-frameworks-Debug-output-files.xcfilelist
文件,这2个文件分别列举了所有framework的输入路径和输出路径,并且跟Pods-MyProj-frameworks.sh
里面用到的输入输出路径一致。打开Pods-MyProj-frameworks-Debug-input-files.xcfilelist
文件能看到FMDB.framework / MMKV.framework / ...
这些库有不同的输入路径,而在Pods-MyProj-frameworks-Debug-output-files.xcfilelist
文件中这些库则出现了如下的重复输出路径,并且跟install_framework
函数内部计算的导出路径一致。通过对比,编译成功的情况下是不会出现重复项的,如果有重复的构建导出路径,则会出现Multiple commands produce '*.framework'
编译错误。
...
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FMDB.framework
...
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MMKV.framework
...
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FMDB.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MMKV.framework
所以问题出在script phase “[CP] Embed Pods Frameworks”
编译阶段,新构建系统检测到了重复构建行为,而解决方案我目前找到2个,建议选择方案2。
- 选择旧的构建系统,具体的操作路径:
Xcode -> File -> WorkSpace Settings -> Build System -> Legacy Build Sysyte
,可行,但不建议,因为这个构建系统已经被标记Deprecated
。- 选择新的构建系统,但是要从源头解决重复依赖的问题,所以我从
FlutterModuleSDK
删除了这些可能重复依赖的xcframework
,在iOS项目编译时只使用iOS侧依赖的第三方库即可,保留一个输入源即可。可以看构建脚本 flutter_build_script.sh
,把需要删除的xcframework
加到黑名单,编译Flutter之后会删除掉黑名单里的xcframework
,这样编译iOS项目的时候就不会重复构建framework。
转载自:https://juejin.cn/post/6999901332345733133