Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Xcode 10 new build system makes asset catalog invalid specified by podspec's`resource(s)` #8122

Open
ooopscc opened this issue Sep 22, 2018 · 27 comments

Comments

Projects
None yet
@ooopscc
Copy link

commented Sep 22, 2018

Report

What did you do?

ℹ Please replace these two lines with what you did.
Xcode 10 new build system, CocoaPods 1.5.3.
Private pod (named Pod1), podspec: s.resources = ['Pod1/Assets/*'], this folder includes a asset catalog(images.xcassets).
Pod install and compile

What did you expect to happen?

image in Pod1's images.xcassets do not show in UI by using -[UIImage imageNamed:] with new build system

What happened instead?

  • images not show.
  • images in pod's images.assets not in Asset.car in .app
  • build log:
Showing All Messages
:-1: ignoring duplicated output file: '/Users/ooops/Library/Developer/Xcode/DerivedData/Example-aavrswxzmgwwppbxcwetebxamdir/Build/Products/Debug-iphonesimulator/Example.app/Assets.car' (in target 'Example')

CocoaPods Environment

Stack

   CocoaPods : 1.5.3
        Ruby : ruby 2.2.7p470 (2017-03-28 revision 58194) [x86_64-darwin17]
    RubyGems : 2.6.14
        Host : Mac OS X 10.14 (18A384a)
       Xcode : 10.0 (10A255)
         Git : git version 2.19.0
Ruby lib dir : /Users/ooops/.rvm/rubies/ruby-2.2.7/lib
Repositories : master - https://github.com/CocoaPods/Specs.git @ 29c32347b0e16c19f1f2b438980959b5240bcc48
               sankuai-binaryspecs - ssh://git@git.sankuai.com/ios/binaryspecs.git @ 5c5f950f2d3697f524280a4d7bcb3dee485ba9ca
               sankuai-bizapp-specs - ssh://git@git.sankuai.com/sjst/bizapp-specs.git @ f4413e94a43dc0539f11d4d453bdd09a5710d370
               sankuai-specs - ssh://git@git.sankuai.com/ios/specs.git @ 33e04c7093977188ea0944da9f9a5f6582957c8e
               sankuai-specs-1 - ssh://git@git.sankuai.com/wm/specs.git @ dbee903fe0a3627de127fda74117f76338db224f

Installation Source

Executable Path: /Users/ooops/.rvm/gems/ruby-2.2.7/bin/pod

Plugins

cocoapods-deintegrate : 1.0.2
cocoapods-plugins     : 1.0.0
cocoapods-search      : 1.0.0
cocoapods-stats       : 1.0.0
cocoapods-trunk       : 1.3.0
cocoapods-try         : 1.1.0

Podfile

# Uncomment the next line to define a global platform for your project
platform :ios, '9.0'

target 'Example' do
  # Uncomment the next line if you're using Swift or would like to use dynamic frameworks
  # use_frameworks!

  # Pods for Example
  pod 'Pod1', :path => '../Pod1'
  pod 'Pod2', :path => '../Pod2'

end

Project that demonstrates the issue

cocoapods-resources.zip
I didn't show image in demo app, just open the build artifact and show package content of .app to see if Asset.car contains the image in Pod1/Assets/images.xcassets

Investigation

I have read the Build System Release Notes for Xcode 10, it said

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.

The problem is I don't know how to ensure all asset catalogs are processed in same build phase for the target.
Any advice or guidance would be greatly appreciated.

@ansonbtl

This comment has been minimized.

Copy link

commented Sep 25, 2018

I am having similar issue too. clean and rebuild will include all assets. but when I re-run the project, Assets.car will be empty, recompiled without assets from pods. It seems the "re-run" doesn't copy the assets from pods.

I had to switch back to legacy build system on Xcode 10. Please fix this.

@dnkoutso

This comment has been minimized.

Copy link
Contributor

commented Sep 25, 2018

I havent verified but this might be the same issue as this #8073

Worth trying master to see if it fixes it and use:

install! 'cocoapods', :disable_input_output_paths => true

Other than that I need to find time to investigate this so I am uncertain yet if its a CocoaPods issue or an Xcode 10 new build system issue.

@samirGuerdah

This comment has been minimized.

Copy link

commented Sep 25, 2018

Meanwhile investigation you can you can use a work arounds : using the Xcode Legacy Build System and not the Xcode 10 new build system.

Xcode / File / Workspace Settings / Build system / select "Legacy Build System"

capture d ecran 2018-09-25 a 11 04 14

@ooopscc

This comment has been minimized.

Copy link
Author

commented Sep 25, 2018

@samirGuerdah Thanks for your workaround. I have already known this way can make it work. But I also hope this issue can be solved when using new build system.

@dnkoutso

This comment has been minimized.

Copy link
Contributor

commented Sep 25, 2018

Uncertain yet if its a CocoaPods bug itself or new build system bug. It appears that switching to legacy makes it work for folks. I haven't had the time to investigate it though.

@ooopscc

This comment has been minimized.

Copy link
Author

commented Oct 1, 2018

@dnkoutso Remind

@dnkoutso

This comment has been minimized.

Copy link
Contributor

commented Oct 1, 2018

@ooopscc there is no specific time an issue will be dealt with. This is mostly handled by free time of a few folks. If you need this faster I highly recommend to investigate the sources, otherwise I cannot provide a time frame sorry.

@ooopscc

This comment has been minimized.

Copy link
Author

commented Oct 1, 2018

It is ok to leave it alone for now, because I can use legacy build system. I post this issue not asking for workaround, I already know it. I think it’s not compatible with new build system, just solve it whenever it’s convenient for you. Thanks.

@OneSman7

This comment has been minimized.

Copy link

commented Oct 3, 2018

Trying to investigate this issue. Found that warning is fixed by removing input/output paths (or using related install option). But assets are still not present on incremental builds just like @ansonbtl described.

@shixiaoda

This comment has been minimized.

Copy link

commented Oct 5, 2018

*.xcassets of Copy Bundle Resources --> Assets.car
*.xcassets of [CP] Copy Pods Resource --> other Assets.car
The first one covers second in the New Build System,That's the reason.

@OneSman7

This comment has been minimized.

Copy link

commented Oct 5, 2018

Great guess! Anyone have ideas how to guarantee [CP] Copy Pods Resource execution after Copy Bundle Resources?

@OneSman7

This comment has been minimized.

Copy link

commented Oct 5, 2018

It seems I found the solution.

Placing Assets.car in input files of the [CP] Copy Pods Resource script tells the build system to wait for it to be created before running the script. See Xcode 10 Build System Release notes:

In the new build system, shell scripts can't rely on the state of build artifacts not listed in other build phases (for example, the Info.plist file or .dSYM files.) Add files the script build phase depends on as explicit input dependencies to the shell script build phase. (40852184)

As for the warning about duplicated output, if we remove Assets.car from output files of the script, it is not executed at all. Seems that build system do not see that script processes it + there are no changes in input files. Thus it is skipped. The warning itself does not cause any change in the build process as I can see. I guess we can ignore this warning since it is a known issue with provided workaround . Thus I hope it will be fixed by Apple at some point.

I also inspected build system CompileAssetsCatalog phase and found more arguments to actool that it uses. For example resource thinning in debug configuration and enabling on demand resources. These parameters are passed via env variables to resources script so they can be added to actool call in it.

@dnkoutso I want to create PR that will incorporate the fix and changes above. I found that I can modify the script in copy_resources_script.rb, but I do not see where I can alter script`s input and output files. Maybe you can help me?

Meanwhile the workaround for new build system will be to copy ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Assets.car to the input files of [CP] Copy Pods Resource after pod install or pod update.

@ooopscc

This comment has been minimized.

Copy link
Author

commented Oct 5, 2018

@OneSman7 Probably here.

@ooopscc

This comment has been minimized.

Copy link
Author

commented Oct 7, 2018

@dnkoutso I try to put the action that @OneSman7 describes in post_install hook, but fails.
Would you please help me figure out why this modification will be reverted.

post_install do |installer|
    app_project = installer.aggregate_targets.first.user_project
    main_target = app_project.targets.first
    build_phases = main_target.build_phases.grep(Xcodeproj::Project::Object::PBXShellScriptBuildPhase)
    phase = build_phases[1]  # This is [CP] Copy Pod Resources phase, just for testing.
    phase.input_paths.clear
    phase.shell_script = ""
    app_project.save
end
@OneSman7

This comment has been minimized.

Copy link

commented Oct 7, 2018

@ooopscc as I see your script removes any code from Copy Pod Resources and input paths.
This just breaks the phase.
The cause of the "assets bug" is the parallelization of the new build system. It tries to run as much tasks as possible at once on multiple cores. Thus in incremental builds Copy Pod Resources phase is executed a bit earlier that regular Compile assets phase. So Xcode just overwrites Assets.car.
We need to make sure Copy Pod Resources phase is executed later. As stated in new docs, if script phases depend on certain file it should be stated in input paths. So I proposed to make Copy Pod Resources phase dependant on Assets.car existing in build folder -> add it to input path of this phase.
No other change is needed. To remove the warning we can remove Assets.car from output path, but it hides form the build system that Assets.car is processed by this script, so it decides not to execute it (all other input files do not change from build to build). This warning is a known issue, so I hope that Apple will fix it in the future.

@ooopscc

This comment has been minimized.

Copy link
Author

commented Oct 8, 2018

@OneSman7 Thanks for the details. The hook I wrote is just a test to see if the modification will work. The full script should add the Assets.car to the input paths.
Use the above script, I can get the correct input paths (same as the final one), and the clear and save seems work, but after a while, it is modified and my changes is reverted.

@OneSman7

This comment has been minimized.

Copy link

commented Oct 8, 2018

I see. I do not know what is reverting your changes, but I think that modifying anything except for Pods project in post install hook can have unexpected consequences since it was not intended.
I suggest adding input path manually after each pod install or update. It is not happening so often and the change is not reverted :)

@OneSman7

This comment has been minimized.

Copy link

commented Oct 8, 2018

It seems I overestimated my Ruby skills, my current workload and the complexity of CocoaPods project.
I cannot tell if will be able to create PR any time soon, so I will write about my findings here. Maybe someone else can use them to fix the issue.

The origin of the issue is described in full detail above. To reenable pods assets in incremental builds we need to add ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Assets.car path to the input paths of the Copy Pod Resource script build phase (maybe just copy from output paths). We can ignore the warning of duplicated output since it is a known issue by Apple and do not affect anything.

In CocoaPods/lib/cocoapods/installer/user_project_integrator/target_integrator.rb in resource_output_paths method there is a line basename = extname == '.xcassets' ? 'Assets' : File.basename(resource_input_path). Here we are able to determine that we will output Assets.car. I was thinking about 2 possible additions:

  1. Making 'Assets' a constant. Search for it in output paths in add_copy_resources_script_phase method. If a path with this constant is found, add it to the input path also.
  2. Avoid searching, make resource_output_paths method return Assets.car path if it was added. If it was returned add it to the input paths.

I also studied CompileAssetCatalog command in Xcode 10:

/Applications/Xcode.app/Contents/Developer/usr/bin/actool --output-format human-readable-text --notices --warnings --export-dependency-info .../assetcatalog_dependencies --output-partial-info-plist .../assetcatalog_generated_info.plist --app-icon AppIcon --compress-pngs --enable-on-demand-resources YES --filter-for-device-model iPhone10,6 --filter-for-device-os-version 11.4 --target-device iphone --minimum-deployment-target 9.3 --platform iphonesimulator --product-type com.apple.product-type.application --compile .../Assets.xcassets

I was thinking about adding additional options to actool call in CocoaPods/lib/cocoapods/generator/copy_resources_script.rb:

  1. --enable-on-demand-resources YES. The value can be obtained from ENABLE_ON_DEMAND_RESOURCES=YES env var.
  2. --filter-for-device-model iPhone10,6 --filter-for-device-os-version 11.4. If these options should be added can be obtained from BUILD_ACTIVE_RESOURCES_ONLY=YES env var. The values for options themselves are in TARGET_DEVICE_MODEL=iPhone10,6 and TARGET_DEVICE_OS_VERSION=11.4 env vars.
  3. --product-type com.apple.product-type.application. The value can be obtained from PRODUCT_TYPE=com.apple.product-type.application env var.
  4. The value of COMPRESS_PNG_FILES=YES env var can be used to determine whether to add --compress-pngs option.

These additions can bring support for on demand resources and improve debugging (they enable app resources thinning in debug builds, which decreases resources compile time and helps testing app thinning).

@matt-loflin

This comment has been minimized.

Copy link

commented Oct 10, 2018

Thank you @OneSman7 for the very thorough investigation and explanation!

For others trying to find a workaround, one option is to add the following to your project's Podfile:

# Work around for issue described here: https://github.com/CocoaPods/CocoaPods/issues/8122#issuecomment-427680543
post_install do |installer|
  project_path = '<Your_Project_File_Here>.xcodeproj'
  project = Xcodeproj::Project.open(project_path)
  project.targets.each do |target|
    build_phase = target.build_phases.find { |bp| bp.display_name == '[CP] Copy Pods Resources' }
    
    if build_phase.present?
      build_phase.input_paths.push('${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Assets.car')
    end
  end
  
  project.save(project_path)
end

This would make sure that every time pod install or pod update is run, the copy pod resources phase is updated with the workaround suggested by others in this issue.

@smarchant-owlet

This comment has been minimized.

Copy link

commented Nov 28, 2018

Unfortunately, @matt-loflin's script didn't quite work for me, though I appreciate seeing that script spelled out. Using the script produced the following compiler error on my project:

invalid task ('PhaseScriptExecution [CP]\ Copy\ Pods\ Resources ... with mutable output but no other virtual output node (in target 'Secret')

I'm surprised more people aren't hitting this issue. For me, that warning about duplicated output file on Assets.car isn't benign. My assets (colors in xcassets) don't actually load at runtime.

I was able to reproduce this issue with the finished tutorial project on raywenderlich.com (https://www.raywenderlich.com/5823-how-to-create-a-cocoapod-in-swift). With that project, you see the same warning. And at runtime, you see Could not load the "background" image referenced from a nib in the bundle with identifier.

Seems like using xcassets as resources in a CocoaPod framework is broken under Xcode 10.1 when using the new build system.

@philtre

This comment has been minimized.

Copy link

commented Dec 10, 2018

I've also been having trouble with @matt-loflin's script.
When I run pod install the script works fine; the input path is added to the "[CP] Copy Pods Resources" build phase and all the images work as expected.

However, when I run pod install again, the input path is removed from the build phase. This is obviously a problem and it's an even bigger one when it occurs in a CI workflow.

According to this StackOverflow answer, the script would have to be run after the "Integrating client project" step, but there are no installer hooks that run after the project integrator:
https://stackoverflow.com/questions/33846361/hook-in-podfile-to-edit-my-project-file/38208513#38208513

@gph1991

This comment has been minimized.

Copy link

commented Dec 27, 2018

*.xcassets of Copy Bundle Resources --> Assets.car
*.xcassets of [CP] Copy Pods Resource --> other Assets.car
The first one covers second in the New Build System,That's the reason.

@shixiaoda

I don't think so,If this is true,Why first time run it was work?

@stale

This comment has been minimized.

Copy link

commented Mar 27, 2019

There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub notifications, we have to clean some of the old issues, as many of them have already been resolved with the latest updates.

@stale stale bot added the s1:awaiting input label Mar 27, 2019

@One1Light

This comment has been minimized.

Copy link

commented Mar 28, 2019

Use legacy is not work on xcode10.2. Have some idea?

@stale stale bot removed the s1:awaiting input label Mar 28, 2019

@njuxjy

This comment has been minimized.

Copy link

commented Apr 22, 2019

+1. Still broken for the new build system in Xcode 10.2.
Also for both cocoapods version 1.5.3 and 1.7.0.beta.3.
Waiting for solutions.

@xilin

This comment has been minimized.

Copy link

commented Apr 25, 2019

+1. Still broken for the new build system in Xcode 10.2.

@johnrogers

This comment has been minimized.

Copy link

commented May 9, 2019

+1 still seeing this in 10.2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.