{
  lib,
  stdenv,
  fetchFromGitHub,
  gitUpdater,
  cereal,
  libcxx,
  glslang,
  simd,
  spirv-cross,
  spirv-headers,
  spirv-tools,
  vulkan-headers,
  xcbuild,
  AppKit,
  Foundation,
  Metal,
  QuartzCore,
  # MoltenVK supports using private APIs to implement some Vulkan functionality.
  # Applications that use private APIs can’t be distributed on the App Store,
  # but that’s not really a concern for nixpkgs, so use them by default.
  # See: https://github.com/KhronosGroup/MoltenVK/blob/main/README.md#metal_private_api
  enablePrivateAPIUsage ? true,
}:

let
  inherit (stdenv.hostPlatform) isStatic;
in
stdenv.mkDerivation (finalAttrs: {
  pname = "MoltenVK";
  version = "1.2.9";

  buildInputs = [
    AppKit
    Foundation
    Metal
    QuartzCore
    cereal
    glslang
    simd
    spirv-cross
    spirv-headers
    spirv-tools
    vulkan-headers
  ];

  nativeBuildInputs = [ xcbuild ];

  outputs = [
    "out"
    "bin"
    "dev"
  ];

  src = fetchFromGitHub {
    owner = "KhronosGroup";
    repo = "MoltenVK";
    rev = "v${finalAttrs.version}";
    hash = "sha256-9k7NMw2M6IqCUQNBekzDaS6VYAOKwPmuCfJkENQ7oiI=";
  };

  postPatch = ''
    # Move `mvkGitRevDerived.h` to a stable location
    substituteInPlace Scripts/gen_moltenvk_rev_hdr.sh \
      --replace-fail '$'''{BUILT_PRODUCTS_DIR}' "$NIX_BUILD_TOP/$sourceRoot/build/include" \
      --replace-fail '$(git rev-parse HEAD)' ${finalAttrs.src.rev}

    # Modify MoltenVK Xcode projects to build with xcbuild and dependencies from nixpkgs.
    for proj in MoltenVK MoltenVKShaderConverter; do
      # Remove xcframework dependencies from the Xcode projects. The basic format is:
      #     (children|files) = (
      #         DCFD7F822A45BDA0007BBBF7 /* SPIRVCross.xcframework in Frameworks */,
      #         etc
      #     )
      # This regex will only remove lines matching `xcframework` that are in these blocks
      # to avoid accidentally corrupting the project.
      sed -E -e '/(children|files) = /,/;/{/xcframework/d}' \
        -i "$proj/$proj.xcodeproj/project.pbxproj"
      # Ensure the namespace used is consistent with the spirv-cross package in nixpkgs.
      substituteInPlace "$proj/$proj.xcodeproj/project.pbxproj" \
        --replace-fail SPIRV_CROSS_NAMESPACE_OVERRIDE=MVK_spirv_cross SPIRV_CROSS_NAMESPACE_OVERRIDE=spirv_cross
    done
    substituteInPlace MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj \
      --replace-fail MetalGLShaderConverterTool MoltenVKShaderConverter \
      --replace-fail MetalGLShaderConverter-macOS MoltenVKShaderConverter

    # Don’t try to build `xcframework`s because `xcbuild` can’t build them.
    sed -e '/xcframework/d' -i Scripts/package_all.sh

    # Remove vendored dependency links.
    find . -lname '*/External/*' -delete

    # The library will be linked in the install phase regardless of version,
    # so truncate it if it exists to avoid link failures.
    test -f Scripts/create_dylib.sh && truncate --size 0 Scripts/create_dylib.sh

    # Link glslang source because MoltenVK needs non-public headers to build.
    mkdir -p build/include
    ln -s "${glslang.src}" "build/include/glslang"
  '';

  env.NIX_CFLAGS_COMPILE = toString (
    [
      "-isystem ${lib.getDev libcxx}/include/c++/v1"
      "-I${lib.getDev spirv-cross}/include/spirv_cross"
      "-I${lib.getDev spirv-headers}/include/spirv/unified1"
    ]
    ++ lib.optional enablePrivateAPIUsage "-DMVK_USE_METAL_PRIVATE_API=1"
  );

  env.NIX_LDFLAGS = toString [
    "-lMachineIndependent"
    "-lGenericCodeGen"
    "-lglslang"
    "-lOSDependent"
    "-lSPIRV"
    "-lSPIRV-Tools"
    "-lSPIRV-Tools-opt"
    "-lspirv-cross-msl"
    "-lspirv-cross-core"
    "-lspirv-cross-glsl"
    "-lspirv-cross-reflect"
  ];

  buildPhase = ''
    runHook preBuild

    NIX_CFLAGS_COMPILE+=" \
      -I$NIX_BUILD_TOP/$sourceRoot/build/include \
      -I$NIX_BUILD_TOP/$sourceRoot/Common"

    xcodebuild build \
      SYMROOT=$PWD/Products OBJROOT=$PWD/Intermedates \
      -jobs $NIX_BUILD_CORES \
      -configuration Release \
      -project MoltenVKPackaging.xcodeproj \
      -scheme 'MoltenVK Package (macOS only)' \
      -destination generic/platform=macOS \
      -arch ${stdenv.hostPlatform.darwinArch}

    runHook postBuild
  '';

  postBuild =
    if isStatic then
      ''
        mkdir -p Package/Release/MoltenVK/static
        cp Products/Release/libMoltenVK.a Package/Release/MoltenVK/static
      ''
    else
      ''
        # MoltenVK’s Xcode project builds the dylib, but it doesn’t seem to work with
        # xcbuild. This is based on the script versions prior to 1.2.8 used.
        mkdir -p Package/Release/MoltenVK/dynamic/dylib
        clang++ -Wl,-all_load -Wl,-w \
          -dynamiclib \
          -compatibility_version 1.0.0 -current_version 1.0.0 \
          -LProducts/Release \
          -framework AppKit \
          -framework CoreGraphics \
          -framework Foundation \
          -framework IOKit \
          -framework IOSurface \
          -framework Metal \
          -framework QuartzCore \
          -lobjc \
          -lMoltenVKShaderConverter \
          -lspirv-cross-reflect \
          -install_name "$out/lib/libMoltenVK.dylib" \
          -o Package/Release/MoltenVK/dynamic/dylib/libMoltenVK.dylib \
          -force_load Products/Release/libMoltenVK.a
      '';

  installPhase = ''
    runHook preInstall

    libraryExtension=${if isStatic then ".a" else ".dylib"}
    packagePath=${if isStatic then "static" else "dynamic/dylib"}

    mkdir -p "$out/lib" "$out/share/vulkan/icd.d" "$bin/bin" "$dev"

    cp Package/Release/MoltenVKShaderConverter/Tools/MoltenVKShaderConverter "$bin/bin"
    cp -r Package/Release/MoltenVK/include "$dev"
    cp Package/Release/MoltenVK/$packagePath/libMoltenVK$libraryExtension "$out/lib"

    # Install ICD definition for use with vulkan-loader.
    install -m644 MoltenVK/icd/MoltenVK_icd.json \
      "$out/share/vulkan/icd.d/MoltenVK_icd.json"
    substituteInPlace "$out/share/vulkan/icd.d/MoltenVK_icd.json" \
      --replace-fail ./libMoltenVK.dylib "$out/lib/libMoltenVK.dylib"

    runHook postInstall
  '';

  passthru.updateScript = gitUpdater {
    rev-prefix = "v";
    ignoredVersions = ".*-(beta|rc).*";
  };

  meta = {
    description = "Vulkan Portability implementation built on top of Apple’s Metal API";
    homepage = "https://github.com/KhronosGroup/MoltenVK";
    changelog = "https://github.com/KhronosGroup/MoltenVK/releases";
    maintainers = [ lib.maintainers.reckenrode ];
    license = lib.licenses.asl20;
    platforms = lib.platforms.darwin;
  };
})
