Metal runtime shader library compilation and linking issue

In my project I need to do the following:

  1. In runtime create metal Dynamic library from source.

  2. In runtime create metal Executable library from source and Link it with my previous created Dynamic library.

  3. Create compute pipeline using those two libraries created above.

But I get the following error at the third step:

Error Domain=AGXMetalG15X_M1 Code=2 "Undefined symbols:
  _Z5noisev, referenced from: OnTheFlyKernel
" UserInfo={NSLocalizedDescription=Undefined symbols:
  _Z5noisev, referenced from: OnTheFlyKernel
}

import Foundation
import Metal

class MetalShaderCompiler {
    let device = MTLCreateSystemDefaultDevice()!
    var pipeline: MTLComputePipelineState!
    
    func compileDylib() -> MTLDynamicLibrary {
        let source = """
        #include <metal_stdlib>
        using namespace metal;
        
        half3 noise() {
            return half3(1, 0, 1);
        }
        """
        let option = MTLCompileOptions()
        option.libraryType = .dynamic
        option.installName = "@executable_path/libFoundation.metallib"
        let library = try! device.makeLibrary(source: source, options: option)
        let dylib = try! device.makeDynamicLibrary(library: library)
        return dylib
    }
    
    func compileExlib(dylib: MTLDynamicLibrary) -> MTLLibrary {
        let source = """
        #include <metal_stdlib>
        using namespace metal;
        extern half3 noise();
        kernel void OnTheFlyKernel(texture2d<half, access::read> src [[texture(0)]],
                               texture2d<half, access::write> dst [[texture(1)]],
                               ushort2 gid [[thread_position_in_grid]]) {
        
            half4 rgba = src.read(gid);
        
            rgba.rgb += noise();
        
            dst.write(rgba, gid);
        }
        """
        let option = MTLCompileOptions()
        option.libraryType = .executable
        option.libraries = [dylib]
        let library = try! self.device.makeLibrary(source: source, options: option)
        return library
    }
    
    func runtime() {
        let dylib = self.compileDylib()
        let exlib = self.compileExlib(dylib: dylib)
        
        let pipelineDescriptor = MTLComputePipelineDescriptor()
        pipelineDescriptor.computeFunction = exlib.makeFunction(name: "OnTheFlyKernel")
        pipelineDescriptor.preloadedLibraries = [dylib]
        
        pipeline = try! device.makeComputePipelineState(descriptor: pipelineDescriptor, options: .bindingInfo, reflection: nil)
    }
}

Answered by DTS Engineer in 805305022

Take a look at the Creating a Metal Dynamic Library sample's approach for compiling, linking and executing a dylib compute kernel.

Build GPU binaries with Metal explains the details.

Take a look at the Creating a Metal Dynamic Library sample's approach for compiling, linking and executing a dylib compute kernel.

Build GPU binaries with Metal explains the details.

Thank you for your reply. I’m already familiar with the examples you provided. Unfortunately they do not solve my problem, because the(Creating a Metal Dynamic Library) sample only covers up to step one, and my code is actually based on the information shown in the video (Build GPU binaries with Metal).

I suggest you submit a code-level support request so that we can discuss details with respect to the full implementation in your Xcode project.

Once I have that, we can continue the discussion here in the forums. When you create the request, indicate that you were referred by someone at Apple and make sure to include a link to this thread.

Metal runtime shader library compilation and linking issue
 
 
Q