Originally published by Alvinzhu. Me

The problem

We recently changed the module that our group was responsible for to be integrated into the main project through Cocoapods, and we encountered an error like the following when running the unit test Target:

Showing All Messages
Multiple commands produce '/Users/Alvin/Library/Developer/Xcode/DerivedData/XCFrameworkDemo-fjmdgsvymhuemlebgdzvccvivdtu/Build/Products/Debug-ipho nesimulator/cocoapods-artifacts-Debug.txt':

1. That command depends on command in Target 'XCFrameworkDemo' (project 'XCFrameworkDemo'(script phase "[CP] Prepare Artifacts" 2command depends on command in Target 'XCFrameworkDemoTests' (project 'XCFrameworkDemo'): Script phase "[CP] Prepare Artifacts"Copy the code

After some investigation, it turned out that this was a bug in Cocoapods integrating with the XCFramework.

XCFramework

XCFramework is a new code framework format launched by apple in WWDC2019. It is mainly designed to solve the distribution problem of code base on different platforms and architectures. Currently, the Apple ecosystem can be roughly divided into 4 different OS (iOS, macOS, watchOS, tvOS), and each OS supports different architectures:

In the past, to support multiple platforms, users of the code base had to configure different libraries, sometimes setting search paths, compilation options, and so on. But if the code base supports XCFramework, just drag the new.xcFramework file directly to Xcode, and Xcode will take care of everything for us.

The essence of the XCFramework is a folder-like container that places files from multiple platforms and architectures together in a specified format. A typical directory structure looks like this, with BugfenderSDK as an example:

Info.plist is used the same way as elsewhere, recording the properties of the.xcFramework, except CFBundlePackageType is XFWK, and the rest defines the platform, architecture, and library path supported by the SDK.

Integrate the XCFramework through Cocoapods

As the most popular dependency management tool in the Apple ecosystem, Cocoapods supports the XCFramework starting in the 1.9 Beta. To process.xcFramework files, pod install adds a new step called [CP] Prepare Artifacts in the Build Phases of Target.

As you can see, in this step a script file is executed and a list of input and output files is set. The xcfilelist file is a new feature of WWDC18 to help Xcode handle Targets dependencies better. It can be used to speed up compilation:

In WWDC’18 Session #408 (“Building Faster in Xcode”), they present a new feature of Xcode 10 where you can provide .xcfilelist files to specify the list of input and output files for the build phase, which will allow Xcode to better determine the dependency graph between targets, files having to be rebuilt, etc.

Note: Input & Output files for build phases were already present in previous versions of Xcode to determine when to run the build phases and optimise the build dependency resolution; What’s new in Xcode 10 is the ability to put the list of those input/output files in xcfilelist — that can then be generated/updated by external tools without having to modify the xcodeproj for that

If all the files in the input/output file list already exist, Xcode skips the reconstruction. In other words, developers can customize the build steps, skipping operations that don’t need to be performed repeatedly and reducing compile time. The input and output files listed in the Demo are as follows.

The Pods – XCFrameworkDemoTests – artifacts – Debug – input – files. Xcfilelist:

${PODS_ROOT}/Target Support Files/Pods-XCFrameworkDemoTests/Pods-XCFrameworkDemoTests-artifacts.sh
${PODS_ROOT}/BugfenderSDK/BugfenderSDK.xcframework
Copy the code

The Pods – XCFrameworkDemoTests – artifacts – Debug – output – files. Xcfilelist:

${BUILT_PRODUCTS_DIR}/cocoapods-artifacts-${CONFIGURATION}.txt
Copy the code

What the script does can be summarized as follows:

  1. Locate the corresponding library in the.XCFramework based on the platform and schema to which you are compiling and copy it to the DerivedData directory
  2. generatecocoapods-artifacts-${CONFIGURATION}.txtFile, the contents of which are the library path after the first step copy, used for the compilation link of the final product.

XCFrameworkDemo and XCFrameworkDemoTests both rely on BugfenderSDK, a third-party library with the XCFramework. As a result, cocoapods-artifacts-${CONFIGURATION}. TXT file is generated after [CP] Prepare Artifacts.

The solution

There are three ways to solve this problem:

  1. Upgrade to 1.10.0 or above. Starting with this version, Cocoapods will be removed again[CP] Prepare ArtifactsStep, solve the problem completely. However, this requires the entire project team and tool chain to be upgraded and can be adopted by smaller teams.
  2. Avoid relying directly on third-party libraries with THE XCFramework for both main project targets and unit test targets. For example, package all dependencies into another subtarget. This can be complicated, such as changing my module to integrate into a sub-target requires a lot of work.
  3. Change to source compilation or revert to the original.framework or.A integration.