lol
1# https://nim-lang.github.io/Nim/packaging.html
2# https://nim-lang.org/docs/nimc.html
3
4{ lib, callPackage, buildPackages, stdenv, fetchurl, fetchgit, fetchFromGitHub
5, makeWrapper, openssl, pcre, readline, boehmgc, sqlite, Security, nim-unwrapped
6, nim-unwrapped-2, nim }:
7
8let
9 parseCpu = platform:
10 with platform;
11 # Derive a Nim CPU identifier
12 if isAarch32 then
13 "arm"
14 else if isAarch64 then
15 "arm64"
16 else if isAlpha then
17 "alpha"
18 else if isAvr then
19 "avr"
20 else if isMips && is32bit then
21 "mips"
22 else if isMips && is64bit then
23 "mips64"
24 else if isMsp430 then
25 "msp430"
26 else if isPower && is32bit then
27 "powerpc"
28 else if isPower && is64bit then
29 "powerpc64"
30 else if isRiscV && is64bit then
31 "riscv64"
32 else if isSparc then
33 "sparc"
34 else if isx86_32 then
35 "i386"
36 else if isx86_64 then
37 "amd64"
38 else
39 abort "no Nim CPU support known for ${config}";
40
41 parseOs = platform:
42 with platform;
43 # Derive a Nim OS identifier
44 if isAndroid then
45 "Android"
46 else if isDarwin then
47 "MacOSX"
48 else if isFreeBSD then
49 "FreeBSD"
50 else if isGenode then
51 "Genode"
52 else if isLinux then
53 "Linux"
54 else if isNetBSD then
55 "NetBSD"
56 else if isNone then
57 "Standalone"
58 else if isOpenBSD then
59 "OpenBSD"
60 else if isWindows then
61 "Windows"
62 else if isiOS then
63 "iOS"
64 else
65 abort "no Nim OS support known for ${config}";
66
67 parsePlatform = p: {
68 cpu = parseCpu p;
69 os = parseOs p;
70 };
71
72 nimHost = parsePlatform stdenv.hostPlatform;
73 nimTarget = parsePlatform stdenv.targetPlatform;
74
75in {
76
77 nim-unwrapped = stdenv.mkDerivation (finalAttrs: {
78 pname = "nim-unwrapped";
79 version = "1.6.14";
80 strictDeps = true;
81
82 src = fetchurl {
83 url = "https://nim-lang.org/download/nim-${finalAttrs.version}.tar.xz";
84 hash = "sha256-0HDS8oriQA33/kpJ7OufRc1TmQaxB0gYVqCveo+oLck=";
85 };
86
87 buildInputs = [ boehmgc openssl pcre readline sqlite ]
88 ++ lib.optional stdenv.isDarwin Security;
89
90 patches = [
91 ./NIM_CONFIG_DIR.patch
92 # Override compiler configuration via an environmental variable
93
94 ./nixbuild.patch
95 # Load libraries at runtime by absolute path
96
97 ./extra-mangling.patch
98 # Mangle store paths of modules to prevent runtime dependence.
99 ] ++ lib.optional (!stdenv.hostPlatform.isWindows) ./toLocation.patch;
100
101 configurePhase = let
102 bootstrapCompiler = stdenv.mkDerivation {
103 pname = "nim-bootstrap";
104 inherit (finalAttrs) version src preBuild;
105 enableParallelBuilding = true;
106 installPhase = ''
107 runHook preInstall
108 install -Dt $out/bin bin/nim
109 runHook postInstall
110 '';
111 };
112 in ''
113 runHook preConfigure
114 cp ${bootstrapCompiler}/bin/nim bin/
115 echo 'define:nixbuild' >> config/nim.cfg
116 runHook postConfigure
117 '';
118
119 kochArgs = [
120 "--cpu:${nimHost.cpu}"
121 "--os:${nimHost.os}"
122 "-d:release"
123 "-d:useGnuReadline"
124 ] ++ lib.optional (stdenv.isDarwin || stdenv.isLinux) "-d:nativeStacktrace";
125
126 preBuild = lib.optionalString (stdenv.isDarwin && stdenv.isAarch64) ''
127 substituteInPlace makefile \
128 --replace "aarch64" "arm64"
129 '';
130
131 buildPhase = ''
132 runHook preBuild
133 local HOME=$TMPDIR
134 ./bin/nim c --parallelBuild:$NIX_BUILD_CORES koch
135 ./koch boot $kochArgs --parallelBuild:$NIX_BUILD_CORES
136 ./koch toolsNoExternal $kochArgs --parallelBuild:$NIX_BUILD_CORES
137 ./bin/nim js -d:release tools/dochack/dochack.nim
138 runHook postBuild
139 '';
140
141 installPhase = ''
142 runHook preInstall
143 install -Dt $out/bin bin/*
144 ln -sf $out/nim/bin/nim $out/bin/nim
145 ln -sf $out/nim/lib $out/lib
146 ./install.sh $out
147 cp -a tools $out/nim/
148 runHook postInstall
149 '';
150
151 meta = with lib; {
152 description = "Statically typed, imperative programming language";
153 homepage = "https://nim-lang.org/";
154 license = licenses.mit;
155 mainProgram = "nim";
156 maintainers = with maintainers; [ ehmry ];
157 };
158 });
159
160 nim-unwrapped-2 = nim-unwrapped.overrideAttrs (finalAttrs: rec {
161 version = "2.0.0";
162 src = fetchurl {
163 url = "https://nim-lang.org/download/nim-${version}.tar.xz";
164 hash = "sha256-vWEB2EADb7eOk6ad9s8/n9DCHNdUtpX/hKO0rdjtCvc=";
165 };
166
167 patches = [
168 ./NIM_CONFIG_DIR.patch
169 # Override compiler configuration via an environmental variable
170
171 ./nixbuild.patch
172 # Load libraries at runtime by absolute path
173
174 ./extra-mangling.patch
175 # Mangle store paths of modules to prevent runtime dependence.
176
177 ./openssl.patch
178 # dlopen is widely used by Python, Ruby, Perl, ... what you're really telling me here is that your OS is fundamentally broken. That might be news for you, but it isn't for me.
179 ];
180 });
181
182} // (let
183 wrapNim = { nim', patches }:
184 let
185 targetPlatformConfig = stdenv.targetPlatform.config;
186 self = stdenv.mkDerivation (finalAttrs: {
187 name = "${targetPlatformConfig}-nim-wrapper-${nim'.version}";
188 inherit (nim') version;
189 preferLocalBuild = true;
190 strictDeps = true;
191
192 nativeBuildInputs = [ makeWrapper ];
193
194 # Needed for any nim package that uses the standard library's
195 # 'std/sysrand' module.
196 depsTargetTargetPropagated = lib.optional stdenv.isDarwin Security;
197
198 inherit patches;
199
200 unpackPhase = ''
201 runHook preUnpack
202 tar xf ${nim'.src} nim-$version/config
203 cd nim-$version
204 runHook postUnpack
205 '';
206
207 dontConfigure = true;
208
209 buildPhase =
210 # Configure the Nim compiler to use $CC and $CXX as backends
211 # The compiler is configured by two configuration files, each with
212 # a different DSL. The order of evaluation matters and that order
213 # is not documented, so duplicate the configuration across both files.
214 ''
215 runHook preBuild
216 cat >> config/config.nims << WTF
217
218 switch("os", "${nimTarget.os}")
219 switch("cpu", "${nimTarget.cpu}")
220 switch("define", "nixbuild")
221
222 # Configure the compiler using the $CC set by Nix at build time
223 import strutils
224 let cc = getEnv"CC"
225 if cc.contains("gcc"):
226 switch("cc", "gcc")
227 elif cc.contains("clang"):
228 switch("cc", "clang")
229 WTF
230
231 mv config/nim.cfg config/nim.cfg.old
232 cat > config/nim.cfg << WTF
233 os = "${nimTarget.os}"
234 cpu = "${nimTarget.cpu}"
235 define:"nixbuild"
236 WTF
237
238 cat >> config/nim.cfg < config/nim.cfg.old
239 rm config/nim.cfg.old
240
241 cat >> config/nim.cfg << WTF
242
243 clang.cpp.exe %= "\$CXX"
244 clang.cpp.linkerexe %= "\$CXX"
245 clang.exe %= "\$CC"
246 clang.linkerexe %= "\$CC"
247 gcc.cpp.exe %= "\$CXX"
248 gcc.cpp.linkerexe %= "\$CXX"
249 gcc.exe %= "\$CC"
250 gcc.linkerexe %= "\$CC"
251 WTF
252
253 runHook postBuild
254 '';
255
256 wrapperArgs = lib.optionals (!(stdenv.isDarwin && stdenv.isAarch64)) [
257 "--prefix PATH : ${lib.makeBinPath [ buildPackages.gdb ]}:${
258 placeholder "out"
259 }/bin"
260 # Used by nim-gdb
261
262 "--prefix LD_LIBRARY_PATH : ${lib.makeLibraryPath [ openssl pcre ]}"
263 # These libraries may be referred to by the standard library.
264 # This is broken for cross-compilation because the package
265 # set will be shifted back by nativeBuildInputs.
266
267 "--set NIM_CONFIG_PATH ${placeholder "out"}/etc/nim"
268 # Use the custom configuration
269 ];
270
271 installPhase = ''
272 runHook preInstall
273
274 mkdir -p $out/bin $out/etc
275
276 cp -r config $out/etc/nim
277
278 for binpath in ${nim'}/bin/nim?*; do
279 local binname=`basename $binpath`
280 makeWrapper \
281 $binpath $out/bin/${targetPlatformConfig}-$binname \
282 $wrapperArgs
283 ln -s $out/bin/${targetPlatformConfig}-$binname $out/bin/$binname
284 done
285
286 makeWrapper \
287 ${nim'}/nim/bin/nim $out/bin/${targetPlatformConfig}-nim \
288 --set-default CC $(command -v $CC) \
289 --set-default CXX $(command -v $CXX) \
290 $wrapperArgs
291 ln -s $out/bin/${targetPlatformConfig}-nim $out/bin/nim
292
293 makeWrapper \
294 ${nim'}/bin/testament $out/bin/${targetPlatformConfig}-testament \
295 $wrapperArgs
296 ln -s $out/bin/${targetPlatformConfig}-testament $out/bin/testament
297
298 '' + ''
299 runHook postInstall
300 '';
301
302 passthru = { nim = nim'; };
303
304 meta = nim'.meta // {
305 description = nim'.meta.description
306 + " (${targetPlatformConfig} wrapper)";
307 platforms = with lib.platforms; unix ++ genode;
308 };
309 });
310 in self // {
311 pkgs = callPackage ../../../top-level/nim-packages.nix { nim = self; };
312 };
313in {
314
315 nim = wrapNim {
316 nim' = buildPackages.nim-unwrapped;
317 patches = [ ./nim.cfg.patch ];
318 };
319
320 nim2 = wrapNim {
321 nim' = buildPackages.nim-unwrapped-2;
322 patches = [ ./nim2.cfg.patch ];
323 };
324
325})