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 = stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isStatic;
45 inherit (stdenv.hostPlatform) isMusl isAarch64 isWindows;
46 noSanitizers = !haveLibc || bareMetal || isMusl || isDarwinStatic || isWindows;
47in
48
49stdenv.mkDerivation (finalAttrs: {
50 pname = "compiler-rt${lib.optionalString (haveLibc) "-libc"}";
51 inherit version;
52
53 src =
54 if monorepoSrc != null then
55 runCommand "compiler-rt-src-${version}" { inherit (monorepoSrc) passthru; } (
56 ''
57 mkdir -p "$out"
58 cp -r ${monorepoSrc}/cmake "$out"
59 ''
60 + lib.optionalString (lib.versionAtLeast release_version "21") ''
61 cp -r ${monorepoSrc}/third-party "$out"
62 ''
63 + ''
64 cp -r ${monorepoSrc}/compiler-rt "$out"
65 ''
66 )
67 else
68 src;
69
70 sourceRoot = "${finalAttrs.src.name}/compiler-rt";
71
72 patches = [
73 (getVersionFile "compiler-rt/X86-support-extension.patch") # Add support for i486 i586 i686 by reusing i386 config
74 # ld-wrapper dislikes `-rpath-link //nix/store`, so we normalize away the
75 # extra `/`.
76 (getVersionFile "compiler-rt/normalize-var.patch")
77 # Fix build on armv6l
78 ./armv6-no-ldrexd-strexd.patch
79 # See: https://github.com/NixOS/nixpkgs/pull/186575
80 ./darwin-plistbuddy-workaround.patch
81 ]
82 ++ [
83 (getVersionFile "compiler-rt/armv6-scudo-libatomic.patch")
84 ]
85 ++ lib.optional (lib.versions.major release_version == "19") (fetchpatch {
86 url = "https://github.com/llvm/llvm-project/pull/99837/commits/14ae0a660a38e1feb151928a14f35ff0f4487351.patch";
87 hash = "sha256-JykABCaNNhYhZQxCvKiBn54DZ5ZguksgCHnpdwWF2no=";
88 relative = "compiler-rt";
89 });
90
91 nativeBuildInputs = [
92 cmake
93 python3
94 libllvm.dev
95 ninja
96 ]
97 ++ lib.optionals stdenv.hostPlatform.isDarwin [ jq ];
98 buildInputs =
99 lib.optional (stdenv.hostPlatform.isLinux && stdenv.hostPlatform.isRiscV) linuxHeaders
100 ++ lib.optional (stdenv.hostPlatform.isFreeBSD) freebsd.include;
101
102 env = {
103 NIX_CFLAGS_COMPILE = toString (
104 [
105 "-DSCUDO_DEFAULT_OPTIONS=DeleteSizeMismatch=0:DeallocationTypeMismatch=0"
106 ]
107 ++ lib.optionals (!haveLibc) [
108 # The compiler got stricter about this, and there is a usellvm patch below
109 # which patches out the assert include causing an implicit definition of
110 # assert. It would be nicer to understand why compiler-rt thinks it should
111 # be able to #include <assert.h> in the first place; perhaps it's in the
112 # wrong, or perhaps there is a way to provide an assert.h.
113 "-Wno-error=implicit-function-declaration"
114 ]
115 );
116
117 # Work around clang’s trying to invoke unprefixed-ld on Darwin when `-target` is passed.
118 NIX_CFLAGS_LINK = lib.optionalString (stdenv.hostPlatform.isDarwin) "--ld-path=${stdenv.cc.bintools}/bin/${stdenv.cc.targetPrefix}ld";
119 };
120
121 cmakeFlags = [
122 (lib.cmakeBool "COMPILER_RT_DEFAULT_TARGET_ONLY" true)
123 (lib.cmakeFeature "CMAKE_C_COMPILER_TARGET" stdenv.hostPlatform.config)
124 (lib.cmakeFeature "CMAKE_ASM_COMPILER_TARGET" stdenv.hostPlatform.config)
125 ]
126 ++ lib.optionals (haveLibc && stdenv.hostPlatform.libc == "glibc") [
127 (lib.cmakeFeature "SANITIZER_COMMON_CFLAGS" "-I${libxcrypt}/include")
128 ]
129 ++ lib.optionals (useLLVM && haveLibc && stdenv.cc.libcxx == libcxx) [
130 (lib.cmakeFeature "SANITIZER_CXX_ABI" "libcxxabi")
131 (lib.cmakeFeature "SANITIZER_CXX_ABI_LIBNAME" "libcxxabi")
132 (lib.cmakeBool "COMPILER_RT_USE_BUILTINS_LIBRARY" true)
133 ]
134 ++ lib.optionals (useLLVM && haveLibc) [
135 (lib.cmakeBool "COMPILER_RT_BUILD_SANITIZERS" true)
136 (lib.cmakeBool "COMPILER_RT_BUILD_PROFILE" true)
137 ]
138 ++ lib.optionals (noSanitizers) [
139 (lib.cmakeBool "COMPILER_RT_BUILD_SANITIZERS" false)
140 ]
141 ++ lib.optionals ((useLLVM && !haveLibcxx) || !haveLibc || bareMetal || isMusl || isDarwinStatic) [
142 (lib.cmakeBool "COMPILER_RT_BUILD_XRAY" false)
143 (lib.cmakeBool "COMPILER_RT_BUILD_LIBFUZZER" false)
144 (lib.cmakeBool "COMPILER_RT_BUILD_MEMPROF" false)
145 (lib.cmakeBool "COMPILER_RT_BUILD_ORC" false) # may be possible to build with musl if necessary
146 ]
147 ++ lib.optionals (!haveLibc || bareMetal) [
148 (lib.cmakeBool "COMPILER_RT_BUILD_PROFILE" false)
149 (lib.cmakeBool "CMAKE_C_COMPILER_WORKS" true)
150 (lib.cmakeBool "COMPILER_RT_BAREMETAL_BUILD" true)
151 (lib.cmakeFeature "CMAKE_SIZEOF_VOID_P" (toString (stdenv.hostPlatform.parsed.cpu.bits / 8)))
152 ]
153 ++ lib.optionals (!haveLibc || bareMetal || isDarwinStatic) [
154 (lib.cmakeBool "CMAKE_CXX_COMPILER_WORKS" true)
155 ]
156 ++ lib.optionals (!haveLibc) [
157 (lib.cmakeFeature "CMAKE_C_FLAGS" "-nodefaultlibs")
158 ]
159 ++ lib.optionals (useLLVM) [
160 (lib.cmakeBool "COMPILER_RT_BUILD_BUILTINS" true)
161 #https://stackoverflow.com/questions/53633705/cmake-the-c-compiler-is-not-able-to-compile-a-simple-test-program
162 (lib.cmakeFeature "CMAKE_TRY_COMPILE_TARGET_TYPE" "STATIC_LIBRARY")
163 ]
164 ++ lib.optionals (bareMetal) [
165 (lib.cmakeFeature "COMPILER_RT_OS_DIR" "baremetal")
166 ]
167 ++ lib.optionals (stdenv.hostPlatform.isDarwin) (
168 [
169 (lib.cmakeFeature "CMAKE_LIPO" "${lib.getBin stdenv.cc.bintools.bintools}/bin/${stdenv.cc.targetPrefix}lipo")
170 ]
171 ++ lib.optionals (!haveLibcxx) [
172 # Darwin fails to detect that the compiler supports the `-g` flag when there is no libc++ during the
173 # compiler-rt bootstrap, which prevents compiler-rt from building. The `-g` flag is required by the
174 # Darwin support, so force it to be enabled during the first stage of the compiler-rt bootstrap.
175 (lib.cmakeBool "COMPILER_RT_HAS_G_FLAG" true)
176 ]
177 ++ [
178 (lib.cmakeFeature "DARWIN_osx_ARCHS" stdenv.hostPlatform.darwinArch)
179 (lib.cmakeFeature "DARWIN_osx_BUILTIN_ARCHS" stdenv.hostPlatform.darwinArch)
180 (lib.cmakeFeature "SANITIZER_MIN_OSX_VERSION" stdenv.hostPlatform.darwinMinVersion)
181 # `COMPILER_RT_DEFAULT_TARGET_ONLY` does not apply to Darwin:
182 # https://github.com/llvm/llvm-project/blob/27ef42bec80b6c010b7b3729ed0528619521a690/compiler-rt/cmake/base-config-ix.cmake#L153
183 (lib.cmakeBool "COMPILER_RT_ENABLE_IOS" false)
184 ]
185 )
186 ++ lib.optionals (noSanitizers && lib.versionAtLeast release_version "19") [
187 (lib.cmakeBool "COMPILER_RT_BUILD_CTX_PROFILE" false)
188 ]
189 ++ devExtraCmakeFlags;
190
191 outputs = [
192 "out"
193 "dev"
194 ];
195
196 postPatch =
197 lib.optionalString (!stdenv.hostPlatform.isDarwin) ''
198 substituteInPlace cmake/builtin-config-ix.cmake \
199 --replace-fail 'set(X86 i386)' 'set(X86 i386 i486 i586 i686)'
200 ''
201 + lib.optionalString (!haveLibc) (
202 (lib.optionalString (lib.versions.major release_version == "18") ''
203 substituteInPlace lib/builtins/aarch64/sme-libc-routines.c \
204 --replace-fail "<stdlib.h>" "<stddef.h>"
205 '')
206 + ''
207 substituteInPlace lib/builtins/int_util.c \
208 --replace-fail "#include <stdlib.h>" ""
209 ''
210 + (lib.optionalString (!stdenv.hostPlatform.isFreeBSD)
211 # On FreeBSD, assert/static_assert are macros and allowing them to be implicitly declared causes link errors.
212 # see description above for why we're nuking assert.h normally but that doesn't work here.
213 # instead, we add the freebsd.include dependency explicitly
214 ''
215 substituteInPlace lib/builtins/clear_cache.c \
216 --replace-fail "#include <assert.h>" ""
217 substituteInPlace lib/builtins/cpu_model/x86.c \
218 --replace-fail "#include <assert.h>" ""
219 ''
220 )
221 )
222 +
223 lib.optionalString (lib.versionAtLeast release_version "19")
224 # codesign in sigtool doesn't support the various options used by the build
225 # and is present in the bootstrap-tools. Removing find_program prevents the
226 # build from trying to use it and failing.
227 ''
228 substituteInPlace cmake/Modules/AddCompilerRT.cmake \
229 --replace-fail 'find_program(CODESIGN codesign)' ""
230 '';
231
232 preConfigure = lib.optionalString stdenv.hostPlatform.isDarwin ''
233 cmakeFlagsArray+=(
234 "-DDARWIN_macosx_CACHED_SYSROOT=$SDKROOT"
235 "-DDARWIN_macosx_OVERRIDE_SDK_VERSION=$(jq -r .Version "$SDKROOT/SDKSettings.json")"
236 )
237 '';
238
239 # Hack around weird upstream RPATH bug
240 postInstall =
241 lib.optionalString (stdenv.hostPlatform.isDarwin) ''
242 ln -s "$out/lib"/*/* "$out/lib"
243 ''
244 + lib.optionalString (useLLVM && stdenv.hostPlatform.isLinux) ''
245 ln -s $out/lib/*/clang_rt.crtbegin-*.o $out/lib/crtbegin.o
246 ln -s $out/lib/*/clang_rt.crtend-*.o $out/lib/crtend.o
247 # Note the history of crt{begin,end}S in previous versions of llvm in nixpkg:
248 # The presence of crtbegin_shared has been added and removed; it's possible
249 # people have added/removed it to get it working on their platforms.
250 # Try each in turn for now.
251 ln -s $out/lib/*/clang_rt.crtbegin-*.o $out/lib/crtbeginS.o
252 ln -s $out/lib/*/clang_rt.crtend-*.o $out/lib/crtendS.o
253 ln -s $out/lib/*/clang_rt.crtbegin_shared-*.o $out/lib/crtbeginS.o
254 ln -s $out/lib/*/clang_rt.crtend_shared-*.o $out/lib/crtendS.o
255 ''
256 + lib.optionalString doFakeLibgcc ''
257 ln -s $out/lib/*/libclang_rt.builtins-*.a $out/lib/libgcc.a
258 ''
259 + lib.optionalString forceLinkCompilerRt ''
260 ln -s $out/lib/*/libclang_rt.builtins-*.a $out/lib/libcompiler_rt.a
261 '';
262
263 meta = llvm_meta // {
264 homepage = "https://compiler-rt.llvm.org/";
265 description = "Compiler runtime libraries";
266 longDescription = ''
267 The compiler-rt project provides highly tuned implementations of the
268 low-level code generator support routines like "__fixunsdfdi" and other
269 calls generated when a target doesn't have a short sequence of native
270 instructions to implement a core IR operation. It also provides
271 implementations of run-time libraries for dynamic testing tools such as
272 AddressSanitizer, ThreadSanitizer, MemorySanitizer, and DataFlowSanitizer.
273 '';
274 # "All of the code in the compiler-rt project is dual licensed under the MIT
275 # license and the UIUC License (a BSD-like license)":
276 license = with lib.licenses; [
277 mit
278 ncsa
279 ];
280 broken =
281 # compiler-rt requires a Clang stdenv on 32-bit RISC-V:
282 # https://reviews.llvm.org/D43106#1019077
283 (stdenv.hostPlatform.isRiscV32 && !stdenv.cc.isClang)
284 # emutls wants `<pthread.h>` which isn't available (without experimental WASM threads proposal).
285 # `enable_execute_stack.c` Also doesn't sound like something WASM would support.
286 || (stdenv.hostPlatform.isWasm && haveLibc);
287 };
288})