about summary refs log tree commit diff
path: root/nixpkgs/pkgs/os-specific/darwin/moltenvk/default.nix
blob: 4e332e6fe55774ab2dc971e297e743eaf8d69f7a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
{
  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.7";

  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-0+S/kueV+AEVt+oFnh4cgcDRVtEbUH1QiHFPhGhimCA=";
  };

  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 = "A 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;
  };
})