[Xcode 12.5] Difficulties with manual XCFrameworks fetching

'Ello there! :wave:

I've just returned to an older project to do some refreshing, mainly migrating as much as possible from old-school fat frameworks to XCFrameworks. :muscle: Yet doing so, I've encountered an issue with xcodebuild (originating in XCBCore – one of XCBCore.XCFrameworkValidationErrors?):

There is no XCFramework found at <full path to potential *.xcframework>

I have a custom Build Phases > Run Script taking care of checking for framework existence and its binary checksums to perform a fetch and unpack of precompiled frameworks from a dedicated S3 storage in case some are missing (after clean repo checkout, on CI, etc.) or have changed, right at the top of the Build Phases tree, just before the Compilation step.

Now – with old-fashioned frameworks, this worked nicely for years, but now it seems some XCFrameworks validator is involved very early in Build setup, preventing me to hit the Build Phase script to fetch xcframeworks. I've tried:

  • putting the script to a separate Aggregated target which the main target would depend upon
    • hoping it would be strictly run first
  • making a stub Library target which the main target would depend upon
    • hoping it would be strictly built first
  • migrating to a workspace with a stub library kept in a different project
    • hoping it would be finally built separately before the main target
  • putting the script invocation to all possible Build Pre-actions
  • disabling parallel building where possible
  • disabling Workspace validation

yet with no luck. :sweat_smile: The validator instantly realises those files don't exist yet and fail the build.

Running my Frameworks checking script manually fixes it (yet cleanup is needed in case it has failed previously :thinking: like if Xcode didn't really reflect the files have been added externally) but that still doesn't really help if I want to keep it in the build flow so the whole process is just open-project-and-run.

Assuming the validator runs really really early in the build preparation, I'm struggling to find a way around. Do you guys have any other idea I could try? :eyes: Cc @NeoNacho as a build systems guru who might have a much deeper insight into how the actual Xcode internals work. :smile:

Have you tried embedding the framework in a swift package? See Distributing Binary Frameworks as Swift Packages. Creating the XCFramework is the hard part; embedding it in a package is easy.

I just tested this myself and it works like a charm. Your project can depend on this package just like you would with any other package. Xcode's built-in support for SPM makes this incredibly easy. You don't have to mess around with any build settings or create any scripts.

Thanks for a tip! :+1: I've observed Binary packages quite a lot, even attempting to do some on-the-fly switching between source and binary packages possibility, still having one quirk there in Xcode 12.5 hopefully to be addressed in the next release. :smile: Yet I'd prefer a solution without SPM involved, like – having an option to disable that check would be completely okay and in sync with classic frameworks so I don't have to look for hacky or wrapping workarounds, moreover in a completely Swift-free project.

What don't you like about SPM? It just seems like you're making your life harder by manually creating a script that fetches the framework. This is what SPM already does for you.

The Xcode build system appears to preprocess all XCFrameworks in the entire build graph, extracting the relevant slices for the current build destination, before it executes any build/script phases in any targets.

So your best chance is to either:

  1. try Build Pre-Action (configured on a per-scheme basis)
  2. forget about the Xcode XCFramework support and extract the good old framework from XCFrameworks manually in your own script (or point search paths & linker flags to the relevant slice directly); or
  3. forget about script phases and manage the XCFramework vendoring outside Xcode.

The situation is similar when one wants to dynamically generate XCFileList.