BuildToolPlugin/XcodeBuildToolPlugin for generating Swift wrappers from Metal

I've got a command line tool which generates Swift wrappers for my Metal kernels (GitHub - audulus/Anodize: Type safety for Metal 🤘).

I would like to integrate it with Xcode so I don't have to run it manually. Ideally, it should run on default.metallib which Xcode creates whenever you have a metal file in your project. That way, I wouldn't have to redundantly compile all the metal files to generate another metallib to load just for reflection of the kernel functions.

The metallib file isn't part of the XcodeTarget's inputFiles. Perhaps I can still construct a path to it?

I tried this:

#if canImport(XcodeProjectPlugin)
import XcodeProjectPlugin

extension AnodizePlugin: XcodeBuildToolPlugin {

    /// This entry point is called when operating on an Xcode project.
    func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] {
        let inputFiles = target.inputFiles.filter { $0.url.pathExtension == "metallib" }
        // inputFiles is empty!
        let outputURL = context.pluginWorkDirectoryURL.appending(path: "Anodized.swift")

        return [
            .buildCommand(displayName: "Anodizing",
                          executable: try context.tool(named: "Anodize").url,
                          arguments: inputFiles.map { $0.url.path() },
                          inputFiles: inputFiles.map { $0.url },
                          outputFiles: [outputURL])
        ]
    }

}
#endif
3 Likes

Ok, it seems like the BuildToolPlugin sandbox doesn't allow an MTLDevice to be created, so I can't use Metal's reflection.

Would be nice if there was a way to load and and use reflection on a metallib without needing an MTLDevice, but that doesn't seem to be the case.