14

On Xcode 11 my .xcassets, that don't cause any issue on Xcode 10, cause the compilation to fail with the following message:

error: Multiple commands produce '/Users/user/Library/Developer/Xcode/DerivedData/project-enjiypsgxtcdbnaripixgtnjlagx/Build/Products/Debug-iphonesimulator/project.app/Assets.car':
1) Target 'project' (project 'project') has compile command with input '/Users/user/sandbox/project/Resources/buttons.xcassets'
2) That command depends on command in Target 'project' (project 'project'): script phase “[CP] Copy Pods Resources”

The only way I'm able to compile the project is by removing the .xcassets from the target with the obvious downside of having them not available on the build.

PS: This is happening for 2 ObjC projects.

JMiguel
  • 1,459
  • 1
  • 10
  • 12

6 Answers6

19

Add below line at the top of your pod file, right after platform :ios

install! 'cocoapods', :disable_input_output_paths => true

Reference

Varun Parakh
  • 221
  • 1
  • 4
  • 10
17

The answer above is only partially correct: yes, this happens because the pod phase produces Assets.car as an output file, which coincides with the output name for your xcassets - hence Multiple commands produce... error: one command being the script phase [CP] Copy Pods Resources and another - your own project's compile command.

But removing Assets.car from output files will cause the build system to fail to see that the script processes the file, thus it skips it (read this for more details). So what we can do is add Assets.car to the input files - this will create a dependency for the script, telling the build system to wait for the file before executing the script.

enter image description here

NB: like the solution above, you will have to do this every time after updating your pods, since [CP] Copy Pods Resources is generated every time you run pod install or pod update

roxanneM
  • 853
  • 1
  • 7
  • 12
  • Doesn't work, which is expected as Xcode still complains that two build phases produce Assets.car and Xcode is also still right about that. The fact that one of them also first reads it doesn't change the basic problem behind it. – Mecki Nov 25 '19 at 14:26
  • @Mecki you are correct, this is just a workaround rather than proper solution. But passing Assets.car as a parameter to one of the build phases creates a dependency for them: now CP phase will wait until the parameter is created by project compile command and then process it rather than create it's own - this is my understanding of the discussion referenced in my answer. – roxanneM Nov 29 '19 at 15:41
11

To be sure that all build steps are performed in the correct order, yet as many steps in parallel as possible, Xcode needs to know for every build step which input files it depends on and which output files it will generate.

E.g. if step A depends on an input file that is the output file of step B, step B surely has to run before step A. If neither step requires the output file of the other step, they can both run in parallel.

While several steps can surely depend on the same input file, it cannot be the case that multiple steps produce the same output file as in that case, whichever step runs last would overwrite the output file of whichever step runs first and this means the resulting output file content would be unpredictable and that is an error in a build process that shall created predictable results!

In your case the problem is that your Copy Resources build phase contains one (or more) .xcassets bundle(s). Xcode won't just copy these bundles, instead it will combine them, convert and optimize their content, and create a file called Assets.car that contains the content of all the assets catalogs in your project.

Yet if you integrate a Pod and this Pod also has an asset catalog, exactly the same thing will happen and a second Assets.car file is created and now Xcode has a problem: Two build steps both say they create an Assets.car file. Which one shall win? Which of these two files shall end up in the final application? And what about other steps that depend on this file? After which of the build steps do they have to run? This is a serious problem that Xcode cannot resolve.

There are currently two possibly solutions:

  1. Use frameworks. When you use frameworks instead of static libraries, the resources of Pods don't end up in the resources folder of your main application but in the resources folder of the built framework. All you need to do is to add use_frameworks! to your Podfile, either top level or just for a specific target. The downside is that your overall app size will grow a bit and app start time will increase a bit.

  2. Have the Pod-author fix the Pod. Instead of resources s/he shall use resources_bundle as the Podspec documentation also strongly recommends. Using resources actually has other disadvantages (resource files are not optimized, name conflicts can arise between different Pods), whereas using a resource bundle is safe, regardless if Pods are embedded as static libraries or as dynamic frameworks. Note, though, that it is not enough to just alter the Podspec, all code that loads bundle resources must be adopted to load them from the correct bundle (the name will be known as when using resources_bundle in a Podspec file, you also must give the bundle(s) a name).

There is an on-going bug report for this issue, you can find it here:
https://github.com/CocoaPods/CocoaPods/issues/8122

Yet the problem currently is, that every possible solution other than the two mentioned above would basically be an ugly hack and the Cocoapods developers are not happy implementing ugly hacks. The best solution, as hard as it seems, is probably to not fix that problem at all but to stop supporting resources in Podspec files and make resources_bundle mandatory for Pods that contain own resources.

Mecki
  • 125,244
  • 33
  • 244
  • 253
  • Thanks for your answer Mercki! It seems to me that there's a small error in your post: "The downside is that your overall app size will grow a bit and app start time will decrease a bit". From my understanding, dynamically linked frameworks will increase the app start time, unfortunately. I thought that was worth pointing out as people would think option 1 is a silver-bullet kind of solution :) – Romain Apr 24 '20 at 09:46
  • @Romain That's exactly what I said. I said app start time will decrease a bit when you use frameworks. – Mecki Apr 24 '20 at 10:02
  • I'm saying that it will increase it. 'use_frameworks!' builds pods as dynamic frameworks (https://blog.cocoapods.org/CocoaPods-0.36/) and dynamic frameworks cause a higher launch time. – Romain Apr 24 '20 at 10:14
  • @Romain Okay, now I got your point. This was just poorly written. Decrease app start time should mean "your app will get worse" and decrease is not the right word to express that it gets worse as it also "shorten" which implies the opposite. Will fix it. – Mecki Apr 24 '20 at 14:27
  • Alright, I see the confusion Thanks for correcting!! – Romain Apr 24 '20 at 14:32
7

In your library project, such as "LADetailPage", open Targets' "Build Phases", create a predefined phase named "Copy Files", then drag your *.xcassets to the new phase.

Then the library won't make Assets.car from *.xcassets files when building, instead, cocoapods copies the *.xcassets to your main project which imports the lib, and the main project builds all *.xcassets into a single Assets.car file.

enter image description here

DawnSong
  • 4,752
  • 2
  • 38
  • 38
4

Please check your dependencies if there is some pods use 'resources'(not 'resources_bundle') to link its own xcassets in podspec. This way has beed deprecated, because its output file name is 'Assets.car'. It is same with your project xcassets' compile output name.

cotton
  • 111
  • 4
  • This is correct. Adding to it, in case you are not the owner of the pod, and you can't update it (as in one of my projects...), it is possible to go around the error by removing the 'Assets.car' line on .../Pods/Target Support Files/Pods-Project/Pods-Project-resources-[Scheme]-output-files.xcfilelist. It has to be done every time pods are updated... so a script to automate it should be a good idea... – JMiguel Sep 07 '19 at 10:25
-1

Xcode->File->Workspace settings->Building System-> Legacy Build System

example

searsea
  • 23
  • 2
  • 12
    IMHO, enable legacy configurations instead of trying to find a solution that works with the latest tools is just a way of saying "I'll just ignore this issue for now!" :) – JMiguel Oct 10 '19 at 09:41
  • 1
    @JMiguel And we all know that a temporary fix like this becomes a permanent one. Then one day Apple removes the legacy system and we are all doomed. – Mecki Nov 25 '19 at 13:36
  • 1
    This isn't a solution its like skipping the tomorrows problem. if Xcode removes legacy build system then we have to come to a solution. – Vigneshwaran Murugesan Dec 05 '19 at 14:21