Ignore .metal files when building for iOS Simulator target

As of Xcode 11, Simulator supports Metal when running on macOS Catalina. Metal files are supported during the build, including when running on macOS Mojave or when building with an older deployment target. Metal won't be functional in those scenarios but you no longer need to exclude files from the build. (Of course when running iOS 13 / tvOS 13 simulators on 10.15 Metal actually works).


You can resolve this by precompiling your .metal file into a Metal library during the build step, and removing the .metal source code from your app target.

Remove .metal file from target

Select your .metal file in the project navigator, and uncheck the target that is giving you the warning.

Metal library compile script

Create a bash script called CompileMetalLib.sh in your project, alongside your .metal file, with contents like this:

xcrun -sdk iphoneos metal -c MyShader.metal -o MyShader.air
xcrun -sdk iphoneos metallib MyShader.air -o MyShader.metallib
rm MyShader.air

Make sure to give it executable permissions by running chmod +x CompileMetalLib.sh.

MyShader.air is the intermediate compile step, and MyShader.metallib is the fully compiled metal library. Read all about compiling a Metal file here

If you're compiling for OS X, change iphoneos to macosx.

Run compile script during build

Now you'll want to trigger this script in your Build Phases.

Add a New Run Script Phase to your target. The contents should look like this:

cd ${SRCROOT}/path/to/folder/containing/yourshader
./CompileMetalLib.sh

It's important to drag this step so that it happens before the Copy Bundle Resources step.

Change your code to use your compiled Metal library

You'll now load the compiled Metal library from your app bundle.

Here's some pseudo-Swift:

let metalLibPath = Bundle.main.path(forResource: "MyShader", ofType: "metallib")
let myLibrary = try metalDevice.makeLibrary(filepath: metalLibPath)

Result

You are manually compiling your .metal file with an external script, and copying the compiled library into your bundle resources. Your code loads this library. Now that you don't have any .metal files in your target, the simulator will no longer throw a warning about not being able to compile for x86_64.