1{
2 lib,
3 stdenv,
4 llvm_meta,
5 release_version,
6 version,
7 src ? null,
8 monorepoSrc ? null,
9 runCommand,
10 cmake,
11 ninja,
12 python3,
13 libllvm,
14 jq,
15 libcxx,
16 linuxHeaders,
17 freebsd,
18 libxcrypt,
19
20 # Some platforms have switched to using compiler-rt, but still want a
21 # libgcc.a for ABI compat purposes. The use case would be old code that
22 # expects to link `-lgcc` but doesn't care exactly what its contents
23 # are, so long as it provides some builtins.
24 doFakeLibgcc ? stdenv.hostPlatform.isFreeBSD,
25
26 # In recent releases, the compiler-rt build seems to produce
27 # many `libclang_rt*` libraries, but not a single unified
28 # `libcompiler_rt` library, at least under certain configurations. Some
29 # platforms still expect this, however, so we symlink one into place.
30 forceLinkCompilerRt ? stdenv.hostPlatform.isOpenBSD,
31 devExtraCmakeFlags ? [ ],
32 getVersionFile,
33 fetchpatch,
34}:
35
36let
37
38 useLLVM = stdenv.hostPlatform.useLLVM or false;
39 bareMetal = stdenv.hostPlatform.parsed.kernel.name == "none";
40 haveLibc = stdenv.cc.libc != null;
41 # TODO: Make this account for GCC having libstdcxx, which will help
42 # use clean up the `cmakeFlags` rats nest below.
43 haveLibcxx = stdenv.cc.libcxx != null;
44 isDarwinStatic =
45 stdenv.hostPlatform.isDarwin
46 && stdenv.hostPlatform.isStatic
47 && lib.versionAtLeast release_version "16";
48 inherit (stdenv.hostPlatform) isMusl isAarch64 isWindows;
49 noSanitizers = !haveLibc || bareMetal || isMusl || isDarwinStatic || isWindows;
50in
51
52stdenv.mkDerivation (finalAttrs: {
53 pname = "compiler-rt${lib.optionalString (haveLibc) "-libc"}";
54 inherit version;
55
56 src =
57 if monorepoSrc != null then
58 runCommand "compiler-rt-src-${version}" { inherit (monorepoSrc) passthru; } (
59 ''
60 mkdir -p "$out"
61 ''
62 + lib.optionalString (lib.versionAtLeast release_version "14") ''
63 cp -r ${monorepoSrc}/cmake "$out"
64 ''
65 + ''
66 cp -r ${monorepoSrc}/compiler-rt "$out"
67 ''
68 )
69 else
70 src;
71
72 sourceRoot = "${finalAttrs.src.name}/compiler-rt";
73
74 patches =
75 lib.optional (lib.versionOlder release_version "15") (getVersionFile "compiler-rt/codesign.patch") # Revert compiler-rt commit that makes codesign mandatory
76 ++ [
77 (getVersionFile "compiler-rt/X86-support-extension.patch") # Add support for i486 i586 i686 by reusing i386 config
78 # ld-wrapper dislikes `-rpath-link //nix/store`, so we normalize away the
79 # extra `/`.
80 (getVersionFile "compiler-rt/normalize-var.patch")
81 # Fix build on armv6l
82 ./armv6-no-ldrexd-strexd.patch
83 ]
84 ++ lib.optional (lib.versions.major release_version == "12") (fetchpatch {
85 # fixes the parallel build on aarch64 darwin
86 name = "fix-symlink-race-aarch64-darwin.patch";
87 url = "https://github.com/llvm/llvm-project/commit/b31080c596246bc26d2493cfd5e07f053cf9541c.patch";
88 relative = "compiler-rt";
89 hash = "sha256-Cv2NC8402yU7QaTR6TzdH+qyWRy+tTote7KKWtKRWFQ=";
90 })
91 ++ lib.optional (
92 lib.versions.major release_version == "12"
93 || (lib.versionAtLeast release_version "14" && lib.versionOlder release_version "18")
94 ) (getVersionFile "compiler-rt/gnu-install-dirs.patch")
95 ++
96 lib.optional (lib.versionAtLeast release_version "13" && lib.versionOlder release_version "18")
97 (fetchpatch {
98 name = "cfi_startproc-after-label.patch";
99 url = "https://github.com/llvm/llvm-project/commit/7939ce39dac0078fef7183d6198598b99c652c88.patch";
100 stripLen = 1;
101 hash = "sha256-tGqXsYvUllFrPa/r/dsKVlwx5IrcJGccuR1WAtUg7/o=";
102 })
103 ++
104 lib.optional (lib.versionAtLeast release_version "13" && lib.versionOlder release_version "18")
105 # Prevent a compilation error on darwin
106 (getVersionFile "compiler-rt/darwin-targetconditionals.patch")
107 # TODO: make unconditional and remove in <15 section below. Causes rebuilds.
108 ++ lib.optionals (lib.versionAtLeast release_version "15") [
109 # See: https://github.com/NixOS/nixpkgs/pull/186575
110 ./darwin-plistbuddy-workaround.patch
111 ]
112 ++
113 lib.optional (lib.versions.major release_version == "15")
114 # See: https://github.com/NixOS/nixpkgs/pull/194634#discussion_r999829893
115 ./armv7l-15.patch
116 ++ lib.optionals (lib.versionOlder release_version "15") [
117 ./darwin-plistbuddy-workaround.patch
118 (getVersionFile "compiler-rt/armv7l.patch")
119 # Fix build on armv6l
120 ./armv6-mcr-dmb.patch
121 ./armv6-sync-ops-no-thumb.patch
122 ]
123 ++
124 lib.optionals (lib.versionAtLeast release_version "13" && lib.versionOlder release_version "18")
125 [
126 # Fix build on armv6l
127 ./armv6-scudo-no-yield.patch
128 ]
129 ++ lib.optionals (lib.versionAtLeast release_version "13") [
130 (getVersionFile "compiler-rt/armv6-scudo-libatomic.patch")
131 ]
132 ++ lib.optional (lib.versions.major release_version == "19") (fetchpatch {
133 url = "https://github.com/llvm/llvm-project/pull/99837/commits/14ae0a660a38e1feb151928a14f35ff0f4487351.patch";
134 hash = "sha256-JykABCaNNhYhZQxCvKiBn54DZ5ZguksgCHnpdwWF2no=";
135 relative = "compiler-rt";
136 });
137
138 nativeBuildInputs =
139 [
140 cmake
141 python3
142 libllvm.dev
143 ]
144 ++ (lib.optional (lib.versionAtLeast release_version "15") ninja)
145 ++ lib.optionals stdenv.hostPlatform.isDarwin [ jq ];
146 buildInputs =
147 lib.optional (stdenv.hostPlatform.isLinux && stdenv.hostPlatform.isRiscV) linuxHeaders
148 ++ lib.optional (stdenv.hostPlatform.isFreeBSD) freebsd.include;
149
150 env = {
151 NIX_CFLAGS_COMPILE = toString (
152 [
153 "-DSCUDO_DEFAULT_OPTIONS=DeleteSizeMismatch=0:DeallocationTypeMismatch=0"
154 ]
155 ++ lib.optionals (!haveLibc) [
156 # The compiler got stricter about this, and there is a usellvm patch below
157 # which patches out the assert include causing an implicit definition of
158 # assert. It would be nicer to understand why compiler-rt thinks it should
159 # be able to #include <assert.h> in the first place; perhaps it's in the
160 # wrong, or perhaps there is a way to provide an assert.h.
161 "-Wno-error=implicit-function-declaration"
162 ]
163 );
164
165 # Work around clang’s trying to invoke unprefixed-ld on Darwin when `-target` is passed.
166 NIX_CFLAGS_LINK = lib.optionalString (stdenv.hostPlatform.isDarwin) "--ld-path=${stdenv.cc.bintools}/bin/${stdenv.cc.targetPrefix}ld";
167 };
168
169 cmakeFlags =
170 [
171 (lib.cmakeBool "COMPILER_RT_DEFAULT_TARGET_ONLY" true)
172 (lib.cmakeFeature "CMAKE_C_COMPILER_TARGET" stdenv.hostPlatform.config)
173 (lib.cmakeFeature "CMAKE_ASM_COMPILER_TARGET" stdenv.hostPlatform.config)
174 ]
175 ++ lib.optionals (haveLibc && stdenv.hostPlatform.libc == "glibc") [
176 (lib.cmakeFeature "SANITIZER_COMMON_CFLAGS" "-I${libxcrypt}/include")
177 ]
178 ++ lib.optionals (useLLVM && haveLibc && stdenv.cc.libcxx == libcxx) [
179 (lib.cmakeFeature "SANITIZER_CXX_ABI" "libcxxabi")
180 (lib.cmakeFeature "SANITIZER_CXX_ABI_LIBNAME" "libcxxabi")
181 (lib.cmakeBool "COMPILER_RT_USE_BUILTINS_LIBRARY" true)
182 ]
183 ++
184 lib.optionals
185 ((!haveLibc || bareMetal || isMusl || isAarch64) && (lib.versions.major release_version == "13"))
186 [
187 (lib.cmakeBool "COMPILER_RT_BUILD_LIBFUZZER" false)
188 ]
189 ++ lib.optionals (useLLVM && haveLibc) [
190 (lib.cmakeBool "COMPILER_RT_BUILD_SANITIZERS" true)
191 (lib.cmakeBool "COMPILER_RT_BUILD_PROFILE" true)
192 ]
193 ++ lib.optionals (noSanitizers) [
194 (lib.cmakeBool "COMPILER_RT_BUILD_SANITIZERS" false)
195 ]
196 ++ lib.optionals ((useLLVM && !haveLibcxx) || !haveLibc || bareMetal || isMusl || isDarwinStatic) [
197 (lib.cmakeBool "COMPILER_RT_BUILD_XRAY" false)
198 (lib.cmakeBool "COMPILER_RT_BUILD_LIBFUZZER" false)
199 (lib.cmakeBool "COMPILER_RT_BUILD_MEMPROF" false)
200 (lib.cmakeBool "COMPILER_RT_BUILD_ORC" false) # may be possible to build with musl if necessary
201 ]
202 ++ lib.optionals (!haveLibc || bareMetal) [
203 (lib.cmakeBool "COMPILER_RT_BUILD_PROFILE" false)
204 (lib.cmakeBool "CMAKE_C_COMPILER_WORKS" true)
205 (lib.cmakeBool "COMPILER_RT_BAREMETAL_BUILD" true)
206 (lib.cmakeFeature "CMAKE_SIZEOF_VOID_P" (toString (stdenv.hostPlatform.parsed.cpu.bits / 8)))
207 ]
208 ++ lib.optionals (!haveLibc || bareMetal || isDarwinStatic) [
209 (lib.cmakeBool "CMAKE_CXX_COMPILER_WORKS" true)
210 ]
211 ++ lib.optionals (!haveLibc) [
212 (lib.cmakeFeature "CMAKE_C_FLAGS" "-nodefaultlibs")
213 ]
214 ++ lib.optionals (useLLVM) [
215 (lib.cmakeBool "COMPILER_RT_BUILD_BUILTINS" true)
216 #https://stackoverflow.com/questions/53633705/cmake-the-c-compiler-is-not-able-to-compile-a-simple-test-program
217 (lib.cmakeFeature "CMAKE_TRY_COMPILE_TARGET_TYPE" "STATIC_LIBRARY")
218 ]
219 ++ lib.optionals (bareMetal) [
220 (lib.cmakeFeature "COMPILER_RT_OS_DIR" "baremetal")
221 ]
222 ++ lib.optionals (stdenv.hostPlatform.isDarwin) (
223 lib.optionals (lib.versionAtLeast release_version "16") [
224 (lib.cmakeFeature "CMAKE_LIPO" "${lib.getBin stdenv.cc.bintools.bintools}/bin/${stdenv.cc.targetPrefix}lipo")
225 ]
226 ++ lib.optionals (!haveLibcxx) [
227 # Darwin fails to detect that the compiler supports the `-g` flag when there is no libc++ during the
228 # compiler-rt bootstrap, which prevents compiler-rt from building. The `-g` flag is required by the
229 # Darwin support, so force it to be enabled during the first stage of the compiler-rt bootstrap.
230 (lib.cmakeBool "COMPILER_RT_HAS_G_FLAG" true)
231 ]
232 ++ [
233 (lib.cmakeFeature "DARWIN_osx_ARCHS" stdenv.hostPlatform.darwinArch)
234 (lib.cmakeFeature "DARWIN_osx_BUILTIN_ARCHS" stdenv.hostPlatform.darwinArch)
235 (lib.cmakeFeature "SANITIZER_MIN_OSX_VERSION" stdenv.hostPlatform.darwinMinVersion)
236 ]
237 ++ lib.optionals (lib.versionAtLeast release_version "15") [
238 # `COMPILER_RT_DEFAULT_TARGET_ONLY` does not apply to Darwin:
239 # https://github.com/llvm/llvm-project/blob/27ef42bec80b6c010b7b3729ed0528619521a690/compiler-rt/cmake/base-config-ix.cmake#L153
240 (lib.cmakeBool "COMPILER_RT_ENABLE_IOS" false)
241 ]
242 )
243 ++ lib.optionals (noSanitizers && lib.versionAtLeast release_version "19") [
244 (lib.cmakeBool "COMPILER_RT_BUILD_CTX_PROFILE" false)
245 ]
246 ++ devExtraCmakeFlags;
247
248 outputs = [
249 "out"
250 "dev"
251 ];
252
253 postPatch =
254 lib.optionalString (!stdenv.hostPlatform.isDarwin) ''
255 substituteInPlace cmake/builtin-config-ix.cmake \
256 --replace-fail 'set(X86 i386)' 'set(X86 i386 i486 i586 i686)'
257 ''
258 + lib.optionalString (!haveLibc) (
259 (lib.optionalString (lib.versions.major release_version == "18") ''
260 substituteInPlace lib/builtins/aarch64/sme-libc-routines.c \
261 --replace-fail "<stdlib.h>" "<stddef.h>"
262 '')
263 + ''
264 substituteInPlace lib/builtins/int_util.c \
265 --replace-fail "#include <stdlib.h>" ""
266 ''
267 + (lib.optionalString (!stdenv.hostPlatform.isFreeBSD)
268 # On FreeBSD, assert/static_assert are macros and allowing them to be implicitly declared causes link errors.
269 # see description above for why we're nuking assert.h normally but that doesn't work here.
270 # instead, we add the freebsd.include dependency explicitly
271 ''
272 substituteInPlace lib/builtins/clear_cache.c \
273 --replace-fail "#include <assert.h>" ""
274 substituteInPlace lib/builtins/cpu_model${lib.optionalString (lib.versionAtLeast release_version "18") "/x86"}.c \
275 --replace-fail "#include <assert.h>" ""
276 ''
277 )
278 )
279 +
280 lib.optionalString
281 (lib.versionAtLeast release_version "13" && lib.versionOlder release_version "14")
282 ''
283 # https://github.com/llvm/llvm-project/blob/llvmorg-14.0.6/libcxx/utils/merge_archives.py
284 # Seems to only be used in v13 though it's present in v12 and v14, and dropped in v15.
285 substituteInPlace ../libcxx/utils/merge_archives.py \
286 --replace-fail "import distutils.spawn" "from shutil import which as find_executable" \
287 --replace-fail "distutils.spawn." ""
288 ''
289 +
290 lib.optionalString (lib.versionAtLeast release_version "19")
291 # codesign in sigtool doesn't support the various options used by the build
292 # and is present in the bootstrap-tools. Removing find_program prevents the
293 # build from trying to use it and failing.
294 ''
295 substituteInPlace cmake/Modules/AddCompilerRT.cmake \
296 --replace-fail 'find_program(CODESIGN codesign)' ""
297 '';
298
299 preConfigure =
300 lib.optionalString (lib.versionOlder release_version "16" && !haveLibc) ''
301 cmakeFlagsArray+=(-DCMAKE_C_FLAGS="-nodefaultlibs -ffreestanding")
302 ''
303 + lib.optionalString stdenv.hostPlatform.isDarwin ''
304 cmakeFlagsArray+=(
305 "-DDARWIN_macosx_CACHED_SYSROOT=$SDKROOT"
306 "-DDARWIN_macosx_OVERRIDE_SDK_VERSION=$(jq -r .Version "$SDKROOT/SDKSettings.json")"
307 )
308 '';
309
310 # Hack around weird upstream RPATH bug
311 postInstall =
312 lib.optionalString (stdenv.hostPlatform.isDarwin) ''
313 ln -s "$out/lib"/*/* "$out/lib"
314 ''
315 + lib.optionalString (useLLVM && stdenv.hostPlatform.isLinux) ''
316 ln -s $out/lib/*/clang_rt.crtbegin-*.o $out/lib/crtbegin.o
317 ln -s $out/lib/*/clang_rt.crtend-*.o $out/lib/crtend.o
318 # Note the history of crt{begin,end}S in previous versions of llvm in nixpkg:
319 # The presence of crtbegin_shared has been added and removed; it's possible
320 # people have added/removed it to get it working on their platforms.
321 # Try each in turn for now.
322 ln -s $out/lib/*/clang_rt.crtbegin-*.o $out/lib/crtbeginS.o
323 ln -s $out/lib/*/clang_rt.crtend-*.o $out/lib/crtendS.o
324 ln -s $out/lib/*/clang_rt.crtbegin_shared-*.o $out/lib/crtbeginS.o
325 ln -s $out/lib/*/clang_rt.crtend_shared-*.o $out/lib/crtendS.o
326 ''
327 + lib.optionalString doFakeLibgcc ''
328 ln -s $out/lib/*/libclang_rt.builtins-*.a $out/lib/libgcc.a
329 ''
330 + lib.optionalString forceLinkCompilerRt ''
331 ln -s $out/lib/*/libclang_rt.builtins-*.a $out/lib/libcompiler_rt.a
332 '';
333
334 meta = llvm_meta // {
335 homepage = "https://compiler-rt.llvm.org/";
336 description = "Compiler runtime libraries";
337 longDescription = ''
338 The compiler-rt project provides highly tuned implementations of the
339 low-level code generator support routines like "__fixunsdfdi" and other
340 calls generated when a target doesn't have a short sequence of native
341 instructions to implement a core IR operation. It also provides
342 implementations of run-time libraries for dynamic testing tools such as
343 AddressSanitizer, ThreadSanitizer, MemorySanitizer, and DataFlowSanitizer.
344 '';
345 # "All of the code in the compiler-rt project is dual licensed under the MIT
346 # license and the UIUC License (a BSD-like license)":
347 license = with lib.licenses; [
348 mit
349 ncsa
350 ];
351 broken =
352 # compiler-rt requires a Clang stdenv on 32-bit RISC-V:
353 # https://reviews.llvm.org/D43106#1019077
354 (stdenv.hostPlatform.isRiscV32 && !stdenv.cc.isClang)
355 # emutls wants `<pthread.h>` which isn't available (without experimental WASM threads proposal).
356 # `enable_execute_stack.c` Also doesn't sound like something WASM would support.
357 || (stdenv.hostPlatform.isWasm && haveLibc);
358 };
359})