likes
comments
collection
share

在iOS项目中依赖Flutter Module-④报错Multiple commands produce/[CP] Embed Pods Frameworks

作者站长头像
站长
· 阅读数 5
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,但是目前还能用。

在iOS项目中依赖Flutter Module-④报错Multiple commands produce/[CP] Embed Pods Frameworks

我用的是Xcode12.5,默认使用New Build System,排查这几个报错的framework后发现存在重复导入/依赖的情况,Flutter侧的iOS插件层依赖了MMKVFMDBSentry,另外在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

在iOS项目中依赖Flutter Module-④报错Multiple commands produce/[CP] Embed Pods Frameworks

查看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.xcfilelistPods-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。

  1. 选择旧的构建系统,具体的操作路径: Xcode -> File -> WorkSpace Settings -> Build System -> Legacy Build Sysyte,可行,但不建议,因为这个构建系统已经被标记Deprecated
  2. 选择新的构建系统,但是要从源头解决重复依赖的问题,所以我从FlutterModuleSDK删除了这些可能重复依赖的xcframework,在iOS项目编译时只使用iOS侧依赖的第三方库即可,保留一个输入源即可。可以看构建脚本 flutter_build_script.sh,把需要删除的xcframework加到黑名单,编译Flutter之后会删除掉黑名单里的xcframework,这样编译iOS项目的时候就不会重复构建framework。

转载自:https://juejin.cn/post/6999901332345733133
评论
请登录