nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
1{
2 lib,
3 stdenv,
4 # LLVM version closest to ROCm fork to override
5 llvmPackages_20,
6 overrideCC,
7 lndir,
8 rocm-device-libs,
9 fetchFromGitHub,
10 runCommand,
11 symlinkJoin,
12 rdfind,
13 zstd,
14 gcc-unwrapped,
15 glibc,
16 replaceVars,
17 libffi,
18 libxml2,
19 removeReferencesTo,
20 fetchpatch,
21 # Build compilers and stdenv suitable for profiling
22 # leaving compressed line tables (-g1 -gz) unstripped
23 # TODO: Should also apply to downstream packages which use rocmClangStdenv?
24 profilableStdenv ? false,
25 # Whether to use LTO when building the ROCm toolchain
26 # Slows down this toolchain's build, for typical ROCm usecase
27 # time saved building composable_kernel and other heavy packages
28 # will outweight that. ~3-4% speedup multiplied by thousands
29 # of corehours.
30 withLto ? true,
31 # whether rocm stdenv uses libcxx (clang c++ stdlib) instead of gcc stdlibc++
32 withLibcxx ? false,
33}:
34
35let
36 version = "7.1.1";
37 # major version of this should be the clang version ROCm forked from
38 rocmLlvmVersion = "20.0.0-rocm";
39 # llvmPackages_base version should match rocmLlvmVersion
40 # so libllvm's bitcode is compatible with the built toolchain
41 llvmPackages_base = llvmPackages_20;
42 llvmPackagesNoBintools = llvmPackages_base.override {
43 bootBintools = null;
44 bootBintoolsNoLibc = null;
45 };
46
47 stdenvToBuildRocmLlvm =
48 if withLibcxx then
49 overrideCC llvmPackagesNoBintools.libcxxStdenv llvmPackagesNoBintools.clangUseLLVM
50 else
51 # oddly fuse-ld=lld fails without this override
52 overrideCC llvmPackagesNoBintools.stdenv (
53 llvmPackagesNoBintools.libstdcxxClang.override {
54 inherit (llvmPackages_base) bintools;
55 }
56 );
57
58 gcc-include = runCommand "gcc-include" { } ''
59 mkdir -p $out
60 ln -s ${gcc-unwrapped}/include/ $out/
61 ln -s ${gcc-unwrapped}/lib/ $out/
62 '';
63
64 disallowedRefsForToolchain = [
65 stdenv.cc
66 stdenv.cc.cc
67 stdenv.cc.bintools
68 gcc-unwrapped
69 stdenvToBuildRocmLlvm
70 stdenvToBuildRocmLlvm.cc
71 stdenvToBuildRocmLlvm.cc.cc
72 ];
73 # A prefix for use as the GCC prefix when building rocm-toolchain
74 gcc-prefix-headers = symlinkJoin {
75 name = "gcc-prefix-headers";
76 paths = [
77 glibc.dev
78 gcc-unwrapped.out
79 ];
80 disallowedRequisites = [
81 glibc.dev
82 gcc-unwrapped.out
83 ];
84 postBuild = ''
85 rm -rf $out/{bin,libexec,nix-support,lib64,share,etc}
86 rm $out/lib/gcc/x86_64-unknown-linux-gnu/*/plugin/include/auto-host.h
87
88 mkdir /build/tmpout
89 mv $out/* /build/tmpout
90 cp -Lr --no-preserve=mode /build/tmpout/* $out/
91 set -x
92 versionedIncludePath="$(echo $out/include/c++/*/)"
93 mv $versionedIncludePath/* $out/include/c++/
94 rm -rf $versionedIncludePath/
95 '';
96 };
97 gcc-prefix = symlinkJoin {
98 name = "gcc-prefix";
99 paths = [
100 gcc-prefix-headers
101 glibc
102 gcc-unwrapped.lib
103 ];
104 disallowedRequisites = [
105 glibc.dev
106 gcc-unwrapped.out
107 ];
108 postBuild = ''
109 rm -rf $out/{bin,libexec,nix-support,lib64,share,etc}
110 rm $out/lib/ld-linux-x86-64.so.2
111 ln -s $out $out/x86_64-unknown-linux-gnu
112 '';
113 };
114 llvmSrc = fetchFromGitHub {
115 owner = "ROCm";
116 repo = "llvm-project";
117 rev = "rocm-${version}";
118 hash = "sha256-CfknIRVeR1bCKh1xzXKl3ehVp0kWT0uGrI9C1HTSKVo=";
119 };
120 llvmMajorVersion = lib.versions.major rocmLlvmVersion;
121 # An llvmPackages (pkgs/development/compilers/llvm/) built from ROCm LLVM's source tree
122 llvmPackagesRocm = llvmPackages_base.override (_old: {
123 stdenv = stdenvToBuildRocmLlvm;
124
125 # not setting gitRelease = because that causes patch selection logic to use git patches
126 # ROCm LLVM is closer to 20 official
127 # gitRelease = {}; officialRelease = null;
128 officialRelease = { }; # Set but empty because we're overriding everything from it.
129 # this version determines which patches are applied
130 version = rocmLlvmVersion;
131 src = llvmSrc;
132 monorepoSrc = llvmSrc;
133 doCheck = false;
134 });
135 refsToRemove = builtins.concatStringsSep " -t " [
136 stdenvToBuildRocmLlvm
137 stdenvToBuildRocmLlvm.cc
138 stdenvToBuildRocmLlvm.cc.cc
139 stdenv.cc
140 stdenv.cc.cc
141 stdenv.cc.bintools
142 ];
143 # Hacky way to avoid nixfmt indenting the entire scope body suggested by @emilazy
144 overrideLlvmPackagesRocm =
145 f:
146 let
147 overridenScope = llvmPackagesRocm.overrideScope (final: prev: f { inherit final prev; });
148 in
149 {
150 inherit (overridenScope)
151 # Expose only a limited set of packages that we care about for ROCm
152 bintools
153 compiler-rt
154 compiler-rt-libc
155 clang
156 clang-unwrapped
157 libcxx
158 lld
159 llvm
160 rocm-toolchain
161 rocmClangStdenv
162 openmp
163 ;
164 };
165 sysrootCompiler =
166 {
167 cc,
168 name,
169 paths,
170 linkPaths,
171 }:
172 let
173 linked = symlinkJoin { inherit name paths; };
174 in
175 runCommand name
176 {
177 # If this is erroring, try why-depends --precise on the symlinkJoin of inputs to look for the problem
178 # nix why-depends --precise .#rocmPackages.llvm.rocm-toolchain.linked /store/path/its/not/allowed
179 disallowedRequisites = disallowedRefsForToolchain;
180 passthru.linked = linked;
181 linkPaths = linkPaths;
182 passAsFile = [ "linkPaths" ];
183 # TODO(@LunNova): Try to use --sysroot with clang in its original location instead of
184 # relying on copying the binary?
185 # $clang/bin/clang++ --sysroot=$rocm-toolchain is not equivalent
186 # to a clang copied to $rocm-toolchain/bin here, have not yet figured out why
187 }
188 ''
189 mkdir -p $out/
190 cp --reflink=auto -rL ${linked}/* $out/
191 chmod -R +rw $out
192 mkdir -p $out/usr
193 ln -s $out/ $out/usr/local
194 # we don't need mixed 32 bit, the presence of lib64 is used by LLVM to decide it's a multilib sysroot
195 rm -rf $out/lib64
196 rm -rf $out/lib/cmake $out/lib/lib*.a
197 mkdir -p $out/lib/clang/${llvmMajorVersion}/lib/linux/
198 ln -s $out/lib/linux/libclang_rt.* $out/lib/clang/${llvmMajorVersion}/lib/linux/
199
200 find $out -type f -exec sed -i "s|${cc.out}|$out|g" {} +
201 find $out -type f -exec sed -i "s|${cc.dev}|$out|g" {} +
202
203 ${lib.getExe rdfind} -makesymlinks true ${
204 builtins.concatStringsSep " " (map (x: "${x}/lib") paths)
205 } $out/ # create links *within* the sysroot to save space
206
207 for i in $(cat $linkPathsPath); do
208 ${lib.getExe lndir} -silent $i $out
209 done
210
211 echo 'export CC=clang' >> $out/nix-support/setup-hook
212 echo 'export CXX=clang++' >> $out/nix-support/setup-hook
213 '';
214 tablegenUsage = x: !(lib.strings.hasInfix "llvm-tblgen" x);
215 llvmTargetsFlag = "-DLLVM_TARGETS_TO_BUILD=AMDGPU;${
216 {
217 "x86_64" = "X86";
218 "aarch64" = "AArch64";
219 }
220 .${stdenv.targetPlatform.parsed.cpu.name}
221 or (throw "Unsupported CPU architecture: ${stdenv.targetPlatform.parsed.cpu.name}")
222 }";
223 llvmMeta = {
224 # TODO(@LunNova): it would be nice to support aarch64 for rocmPackages
225 platforms = [ "x86_64-linux" ];
226 };
227 # TODO(@LunNova): Some of this might be worth supporting in llvmPackages, dropping from here
228 commonCmakeFlags = [
229 llvmTargetsFlag
230 # Compression support is required for compressed offload kernels
231 # Set FORCE_ON so that failure to find the compression lib will be a build error
232 (lib.cmakeFeature "LLVM_ENABLE_ZSTD" "FORCE_ON")
233 # required for threaded ThinLTO to work
234 (lib.cmakeBool "LLVM_ENABLE_THREADS" true)
235 # LLVM tries to call git to embed VCS info if FORCE_VC_ aren't set
236 (lib.cmakeFeature "LLVM_FORCE_VC_REVISION" "rocm-${version}")
237 (lib.cmakeFeature "LLVM_FORCE_VC_REPOSITORY" "https://github.com/ROCm/llvm-project")
238 (lib.cmakeFeature "LLVM_VERSION_SUFFIX" "")
239 (lib.cmakeBool "LLVM_ENABLE_LIBCXX" withLibcxx)
240 (lib.cmakeFeature "CLANG_DEFAULT_CXX_STDLIB" (if withLibcxx then "libc++" else "libstdc++"))
241 (lib.cmakeFeature "CLANG_VENDOR" "nixpkgs-AMD")
242 (lib.cmakeFeature "CLANG_REPOSITORY_STRING" "https://github.com/ROCm/llvm-project/tree/rocm-${version}")
243 ]
244 ++ lib.optionals withLibcxx [
245 (lib.cmakeFeature "CLANG_DEFAULT_RTLIB" "compiler-rt")
246 ]
247 ++ lib.optionals withLto [
248 (lib.cmakeBool "CMAKE_INTERPROCEDURAL_OPTIMIZATION" true)
249 (lib.cmakeBool "LLVM_ENABLE_FATLTO" false)
250 ]
251 ++ lib.optionals (withLto && stdenvToBuildRocmLlvm.cc.isClang) [
252 (lib.cmakeFeature "LLVM_ENABLE_LTO" "FULL")
253 (lib.cmakeFeature "LLVM_USE_LINKER" "lld")
254 ];
255
256 llvmExtraCflags = lib.concatStringsSep " " (
257 lib.optionals (stdenv.hostPlatform.system == "x86_64-linux") [
258 # Unprincipled decision to build x86_64 ROCm clang for at least skylake and tune for zen3+
259 # In practice building the ROCm package set with anything earlier than zen3 is annoying
260 # and earlier than skylake is implausible due to too few cores and too little RAM
261 # Speeds up composable_kernel builds by ~4%
262 # If this causes trouble in practice we can drop this. Set since 2025-03-24.
263 "-march=skylake"
264 "-mtune=znver3"
265 ]
266 ++ lib.optionals profilableStdenv [
267 # compressed line only debug info for profiling
268 "-gz"
269 "-g1"
270 ]
271 );
272 inherit (llvmPackagesRocm) libcxx;
273in
274overrideLlvmPackagesRocm (s: {
275 libllvm = (s.prev.libllvm.override { }).overrideAttrs (old: {
276 patches = old.patches ++ [
277 (fetchpatch {
278 # fix compile error in tools/gold/gold-plugin.cpp
279 name = "gold-plugin-fix.patch";
280 url = "https://github.com/llvm/llvm-project/commit/b0baa1d8bd68a2ce2f7c5f2b62333e410e9122a1.patch";
281 hash = "sha256-yly93PvGIXOnFeDGZ2W+W6SyhdWFM6iwA+qOeaptrh0=";
282 relative = "llvm";
283 })
284 ./perf-increase-namestring-size.patch
285 # TODO: consider reapplying "Don't include aliases in RegisterClassInfo::IgnoreCSRForAllocOrder"
286 # it was reverted as it's a pessimization for non-GPU archs, but this compiler
287 # is used mostly for amdgpu
288 ];
289 dontStrip = profilableStdenv;
290 hardeningDisable = [ "all" ];
291 nativeBuildInputs = old.nativeBuildInputs ++ [ removeReferencesTo ];
292 buildInputs = old.buildInputs ++ [
293 zstd
294 ];
295 preFixup = ''
296 moveToOutput "lib/lib*.a" "$dev"
297 moveToOutput "lib/cmake" "$dev"
298 sed -Ei "s|$lib/lib/(lib[^/]*)\.a|$dev/lib/\1.a|g" $dev/lib/cmake/llvm/*.cmake
299 '';
300 env = (old.env or { }) // {
301 NIX_CFLAGS_COMPILE = "${(old.env or { }).NIX_CFLAGS_COMPILE or ""} ${llvmExtraCflags}";
302 };
303 cmakeFlags = (builtins.filter tablegenUsage old.cmakeFlags) ++ commonCmakeFlags;
304 # Ensure we don't leak refs to compiler that was used to bootstrap this LLVM
305 disallowedReferences = (old.disallowedReferences or [ ]) ++ disallowedRefsForToolchain;
306 postFixup = ''
307 ${old.postFixup or ""}
308 find $lib -type f -exec remove-references-to -t ${refsToRemove} {} +
309 '';
310 meta = old.meta // llvmMeta;
311 });
312 lld =
313 (s.prev.lld.override {
314 }).overrideAttrs
315 (old: {
316 dontStrip = profilableStdenv;
317 hardeningDisable = [ "all" ];
318 nativeBuildInputs = old.nativeBuildInputs ++ [
319 removeReferencesTo
320 ];
321 buildInputs = old.buildInputs ++ [
322 zstd
323 ];
324 env = (old.env or { }) // {
325 NIX_CFLAGS_COMPILE = "${(old.env or { }).NIX_CFLAGS_COMPILE or ""} ${llvmExtraCflags}";
326 };
327 cmakeFlags = (builtins.filter tablegenUsage old.cmakeFlags) ++ commonCmakeFlags;
328 # Ensure we don't leak refs to compiler that was used to bootstrap this LLVM
329 disallowedReferences = (old.disallowedReferences or [ ]) ++ disallowedRefsForToolchain;
330 postFixup = ''
331 ${old.postFixup or ""}
332 find $lib -type f -exec remove-references-to -t ${refsToRemove} {} +
333 '';
334 meta = old.meta // llvmMeta;
335 });
336 clang-unwrapped = (
337 (s.prev.clang-unwrapped.override {
338 enableClangToolsExtra = false;
339 }).overrideAttrs
340 (old: {
341 passthru = old.passthru // {
342 inherit gcc-prefix;
343 };
344 patches = old.patches ++ [
345 # Never add FHS include paths
346 ./clang-bodge-ignore-systemwide-incls.diff
347 # Prevents builds timing out if a single compiler invocation is very slow but
348 # per-arch jobs are completing by ensuring there's terminal output
349 ./clang-log-jobs.diff
350 ./opt-offload-compress-on-by-default.patch
351 ./perf-shorten-gcclib-include-paths.patch
352 (fetchpatch {
353 # [ClangOffloadBundler]: Add GetBundleIDsInFile to OffloadBundler
354 sha256 = "sha256-G/mzUdFfrJ2bLJgo4+mBcR6Ox7xGhWu5X+XxT4kH2c8=";
355 url = "https://github.com/GZGavinZhao/rocm-llvm-project/commit/6d296f879b0fed830c54b2a9d26240da86c8bb3a.patch";
356 relative = "clang";
357 })
358 ];
359 hardeningDisable = [ "all" ];
360 nativeBuildInputs = old.nativeBuildInputs ++ [
361 removeReferencesTo
362 ];
363 buildInputs = old.buildInputs ++ [
364 zstd
365 ];
366 env = (old.env or { }) // {
367 NIX_CFLAGS_COMPILE = "${(old.env or { }).NIX_CFLAGS_COMPILE or ""} ${llvmExtraCflags}";
368 };
369 dontStrip = profilableStdenv;
370 # Ensure we don't leak refs to compiler that was used to bootstrap this LLVM
371 disallowedReferences = (old.disallowedReferences or [ ]) ++ disallowedRefsForToolchain;
372 # Enable structured attrs for separateDebugInfo, because it is required with disallowedReferences set
373 __structuredAttrs = true;
374 # https://github.com/llvm/llvm-project/blob/6976deebafa8e7de993ce159aa6b82c0e7089313/clang/cmake/caches/DistributionExample-stage2.cmake#L9-L11
375 cmakeFlags =
376 # TODO: Remove in followup, tblgen now works correctly but would rebuild
377 (builtins.filter tablegenUsage old.cmakeFlags)
378 ++ commonCmakeFlags
379 ++ lib.optionals (!withLibcxx) [
380 # FIXME: Config file in rocm-toolchain instead of GCC_INSTALL_PREFIX?
381 # Expected to be fully removed eventually
382 "-DUSE_DEPRECATED_GCC_INSTALL_PREFIX=ON"
383 "-DGCC_INSTALL_PREFIX=${gcc-prefix}"
384 ];
385 preFixup = ''
386 ${toString old.preFixup or ""}
387 moveToOutput "lib/lib*.a" "$dev"
388 moveToOutput "lib/cmake" "$dev"
389 mkdir -p $dev/lib/clang/
390 ln -s $lib/lib/clang/${llvmMajorVersion} $dev/lib/clang/
391 sed -Ei "s|$lib/lib/(lib[^/]*)\.a|$dev/lib/\1.a|g" $dev/lib/cmake/clang/*.cmake
392 '';
393 postFixup = ''
394 ${toString old.postFixup or ""}
395 find $lib -type f -exec remove-references-to -t ${refsToRemove} {} +
396 find $dev -type f -exec remove-references-to -t ${refsToRemove} {} +
397 '';
398 meta = old.meta // llvmMeta;
399 })
400 );
401 # A clang that understands standard include searching in a GNU sysroot and will put GPU libs in include path
402 # in the right order
403 # and expects its libc to be in the sysroot
404 rocm-toolchain =
405 with s.final;
406 (sysrootCompiler {
407 cc = clang-unwrapped;
408 name = "rocm-toolchain";
409 paths = [
410 clang-unwrapped.out
411 clang-unwrapped.lib
412 bintools.out
413 compiler-rt.out
414 openmp.out
415 openmp.dev
416 ]
417 ++ lib.optionals withLibcxx [
418 libcxx
419 ]
420 ++ lib.optionals (!withLibcxx) [
421 glibc
422 glibc.dev
423 ];
424 linkPaths = [
425 bintools.bintools.out
426 ]
427 ++ lib.optionals (!withLibcxx) [
428 gcc-include.out
429 ];
430 })
431 // {
432 version = llvmMajorVersion;
433 cc = rocm-toolchain;
434 libllvm = llvm;
435 isClang = true;
436 isGNU = false;
437 };
438 compiler-rt-libc = s.prev.compiler-rt-libc.overrideAttrs (old: {
439 patches = old.patches ++ [
440 # fix build with glibc >= 2.42
441 (fetchpatch {
442 url = "https://github.com/llvm/llvm-project/commit/59978b21ad9c65276ee8e14f26759691b8a65763.patch";
443 hash = "sha256-ys5SMLfO3Ay9nCX9GV5yRCQ6pLsseFu/ZY6Xd6OL4p0=";
444 relative = "compiler-rt";
445 })
446 ];
447 meta = old.meta // llvmMeta;
448 });
449 compiler-rt = s.final.compiler-rt-libc;
450 clang = s.final.rocm-toolchain;
451
452 rocmClangStdenv = with s.final; overrideCC (if withLibcxx then libcxxStdenv else stdenv) clang;
453
454 # Projects
455 openmp =
456 with s.final;
457 (llvmPackagesRocm.openmp.override {
458 llvm = llvm;
459 clang-unwrapped = clang-unwrapped;
460 }).overrideAttrs
461 (old: {
462 disallowedReferences = (old.disallowedReferences or [ ]) ++ disallowedRefsForToolchain;
463 nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [
464 removeReferencesTo
465 ];
466 cmakeFlags =
467 old.cmakeFlags
468 ++ commonCmakeFlags
469 ++ [
470 "-DDEVICELIBS_ROOT=${rocm-device-libs.src}"
471 # OMPD support is broken in ROCm 6.3+ Haven't investigated why.
472 "-DLIBOMP_OMPD_SUPPORT:BOOL=FALSE"
473 "-DLIBOMP_OMPD_GDB_SUPPORT:BOOL=FALSE"
474 ];
475 buildInputs = old.buildInputs ++ [
476 clang-unwrapped
477 zstd
478 libxml2
479 libffi
480 ];
481 postFixup = ''
482 ${old.postFixup or ""}
483 ln -s $out/lib/libomp.so $dev/lib/libomp.so
484 '';
485 });
486 # AMD has a separate MLIR impl which we package under rocmPackages.rocmlir
487 # It would be an error to rely on the original mlir package from this scope
488 mlir = null;
489})