Search code examples
c++cmakemetal

How to build Apple's Metal-cpp example using CMake?


Recently, Apple has released a library to use Metal directly using C++. The example that I've found online (https://github.com/moritzhof/metal-cpp-examples), works if I copy the source code and follow the steps outlined by Apple (https://developer.apple.com/metal/cpp/) in Xcode. I don't use the included Xcode project files, to avoid any "hidden" settings.

Now I'm trying to get the same example to build using CMake, with this CMakeLists.txt:

cmake_minimum_required(VERSION 3.8)
project(HelloWorld)

set(CMAKE_CXX_STANDARD 17)

include_directories(${PROJECT_SOURCE_DIR}/metal-cpp)

set(SOURCE_FILES metal-cpp-test/main.cpp metal-cpp-test/metal_adder.cpp)
add_executable(program ${SOURCE_FILES})

# specify which libraries to connect
# target_link_libraries(program ${METAL})
# target_link_libraries(program ${FOUNDATION})
# target_link_libraries(program ${QUARTZCORE})

find_library(METAL Metal)
find_library(FOUNDATION Foundation)
find_library(QUARTZCORE QuartzCore)

target_link_libraries(program stdc++ "-framework Metal" "-framework Foundation" "-framework QuartzCore" objc)

It compiles successfully, but the line

auto lib = _device->newDefaultLibrary();

Now seems to return a null-ptr. Any idea what the reason for this could be and how to solve this?


Solution

  • All .metal files in an Xcode project that builds an application are compiled and built into a single default library.

    _device->newDefaultLibrary() return a new library object that contains the functions from the default library. This method returns nil if the default library cannot be found.

    Since you are not using Xcode, you should manually compile Metal Shading Language source code and build a Metal library.

    Then, at runtime, call the newLibrary(filePath, &error) method to retrieve and access your library as a MTL::Library object.

    NS::String* filePath = NS::String::string("The full file path to a .metallib file", NS::UTF8StringEncoding);
    NS::Error* error;
    auto library =_device->newLibrary(filePath, &error);
    if(error)
    {
                        
    }