nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
1{
2 lib,
3 stdenv,
4 fetchurl,
5 fetchpatch2,
6 fetchFromGitHub,
7 python,
8 ada,
9 brotli,
10 c-ares,
11 libuv,
12 llhttp,
13 nghttp2,
14 nghttp3,
15 ngtcp2,
16 openssl,
17 simdjson,
18 simdutf,
19 simdutf_6 ? (
20 simdutf.overrideAttrs {
21 version = "6.5.0";
22
23 src = fetchFromGitHub {
24 owner = "simdutf";
25 repo = "simdutf";
26 rev = "v6.5.0";
27 hash = "sha256-bZ4r62GMz2Dkd3fKTJhelitaA8jUBaDjG6jOysEg8Nk=";
28 };
29 }
30 ),
31 sqlite,
32 uvwasi,
33 zlib,
34 zstd,
35 icu,
36 bash,
37 ninja,
38 pkgconf,
39 unixtools,
40 runCommand,
41 buildPackages,
42 testers,
43 # for `.pkgs` attribute
44 callPackage,
45 # Updater dependencies
46 writeScript,
47 coreutils,
48 gnugrep,
49 jq,
50 curl,
51 common-updater-scripts,
52 runtimeShell,
53 gnupg,
54 installShellFiles,
55 darwin,
56}:
57
58{
59 enableNpm ? true,
60 version,
61 sha256,
62 patches ? [ ],
63}@args:
64
65let
66
67 majorVersion = lib.versions.major version;
68 minorVersion = lib.versions.minor version;
69
70 pname = if enableNpm then "nodejs" else "nodejs-slim";
71
72 canExecute = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
73 emulator = stdenv.hostPlatform.emulator buildPackages;
74 canEmulate = stdenv.hostPlatform.emulatorAvailable buildPackages;
75 buildNode = buildPackages."${pname}_${majorVersion}";
76
77 # See valid_os and valid_arch in configure.py.
78 destOS =
79 let
80 platform = stdenv.hostPlatform;
81 in
82 if platform.isiOS then
83 "ios"
84 else if platform.isAndroid then
85 "android"
86 else if platform.isWindows then
87 "win"
88 else if platform.isDarwin then
89 "mac"
90 else if platform.isLinux then
91 "linux"
92 else if platform.isOpenBSD then
93 "openbsd"
94 else if platform.isFreeBSD then
95 "freebsd"
96 else
97 throw "unsupported os ${platform.uname.system}";
98 destARMFPU =
99 let
100 platform = stdenv.hostPlatform;
101 in
102 if platform.isAarch32 && platform ? gcc.fpu then
103 lib.throwIfNot (builtins.elem platform.gcc.fpu [
104 "vfp"
105 "vfpv2"
106 "vfpv3"
107 "vfpv3-d16"
108 "neon"
109 ]) "unsupported ARM FPU ${platform.gcc.fpu}" platform.gcc.fpu
110 else
111 null;
112 destARMFloatABI =
113 let
114 platform = stdenv.hostPlatform;
115 in
116 if platform.isAarch32 && platform ? gcc.float-abi then
117 lib.throwIfNot (builtins.elem platform.gcc.float-abi [
118 "soft"
119 "softfp"
120 "hard"
121 ]) "unsupported ARM float ABI ${platform.gcc.float-abi}" platform.gcc.float-abi
122 else
123 null;
124 # TODO: also handle MIPS flags (mips_arch, mips_fpu, mips_float_abi).
125
126 useSharedAdaAndSimd = !stdenv.hostPlatform.isStatic && lib.versionAtLeast version "22.2";
127 useSharedSQLite = !stdenv.hostPlatform.isStatic && lib.versionAtLeast version "22.5";
128 useSharedZstd = !stdenv.hostPlatform.isStatic && lib.versionAtLeast version "22.15";
129
130 sharedLibDeps =
131 (lib.optionalAttrs (!stdenv.hostPlatform.isStatic) {
132 inherit
133 brotli
134 libuv
135 nghttp3
136 ngtcp2
137 openssl
138 uvwasi
139 zlib
140 ;
141 cares = c-ares;
142 http-parser = llhttp;
143 nghttp2 = nghttp2.overrideAttrs {
144 patches = [
145 (fetchpatch2 {
146 url = "https://github.com/nghttp2/nghttp2/commit/7784fa979d0bcf801a35f1afbb25fb048d815cd7.patch?full_index=1";
147 hash = "sha256-RG87Qifjpl7HTP9ac2JwHj2XAbDlFgOpAnpZX3ET6gU=";
148 excludes = [ "lib/includes/nghttp2/nghttp2.h" ];
149 revert = true;
150 })
151 ];
152 };
153 })
154 // (lib.optionalAttrs useSharedAdaAndSimd {
155 inherit
156 ada
157 simdjson
158 ;
159 simdutf = if lib.versionAtLeast version "25" then simdutf else simdutf_6;
160 })
161 // (lib.optionalAttrs useSharedSQLite {
162 inherit sqlite;
163 })
164 // (lib.optionalAttrs useSharedZstd {
165 inherit zstd;
166 });
167
168 copyLibHeaders = map (name: "${lib.getDev sharedLibDeps.${name}}/include/*") (
169 builtins.attrNames sharedLibDeps
170 );
171
172 # Currently stdenv sets CC/LD/AR/etc environment variables to program names
173 # instead of absolute paths. If we add cctools to nativeBuildInputs, that
174 # would shadow stdenv’s bintools and potentially break other parts of the
175 # build. The correct behavior is to use absolute paths, and there is a PR for
176 # that, see https://github.com/NixOS/nixpkgs/pull/314920. As a temporary
177 # workaround, we use only a single program we need (and that is not part of
178 # the stdenv).
179 darwin-cctools-only-libtool =
180 # Would be nice to have onlyExe builder similar to onlyBin…
181 runCommand "darwin-cctools-only-libtool" { cctools = lib.getBin buildPackages.cctools; } ''
182 mkdir -p "$out/bin"
183 ln -s "$cctools/bin/libtool" "$out/bin/libtool"
184 '';
185
186 # a script which claims to be a different script but switches to simply touching its output
187 # when an environment variable is set. See CC_host, --cross-compiling, and postConfigure.
188 touchScript =
189 real:
190 writeScript "touch-script" ''
191 #!${stdenv.shell}
192 if [ -z "$FAKE_TOUCH" ]; then
193 exec "${real}" "$@"
194 fi
195 while [ "$#" != "0" ]; do
196 if [ "$1" == "-o" ]; then
197 shift
198 touch "$1"
199 fi
200 shift
201 done
202 '';
203
204 downloadDir = if lib.strings.hasInfix "-rc." version then "download/rc" else "dist";
205
206 package = stdenv.mkDerivation (
207 finalAttrs:
208 let
209 /**
210 the final package fixed point, after potential overrides
211 */
212 self = finalAttrs.finalPackage;
213 in
214 {
215 inherit pname version;
216
217 src = fetchurl {
218 url = "https://nodejs.org/${downloadDir}/v${version}/node-v${version}.tar.xz";
219 inherit sha256;
220 };
221
222 strictDeps = true;
223
224 env = {
225 # Tell ninja to avoid ANSI sequences, otherwise we don’t see build
226 # progress in Nix logs.
227 #
228 # Note: do not set TERM=dumb environment variable globally, it is used in
229 # test-ci-js test suite to skip tests that otherwise run fine.
230 NINJA = "TERM=dumb ninja";
231 }
232 // lib.optionalAttrs (!canExecute && !canEmulate) {
233 # these are used in the --cross-compiling case. see comment at postConfigure.
234 CC_host = touchScript "${buildPackages.stdenv.cc}/bin/cc";
235 CXX_host = touchScript "${buildPackages.stdenv.cc}/bin/c++";
236 AR_host = touchScript "${buildPackages.stdenv.cc}/bin/ar";
237 };
238
239 # NB: technically, we do not need bash in build inputs since all scripts are
240 # wrappers over the corresponding JS scripts. There are some packages though
241 # that use bash wrappers, e.g. polaris-web.
242 buildInputs = [
243 bash
244 icu
245 ]
246 ++ builtins.attrValues sharedLibDeps;
247
248 nativeBuildInputs = [
249 installShellFiles
250 ninja
251 pkgconf
252 python
253 ]
254 ++ lib.optionals stdenv.buildPlatform.isDarwin [
255 # gyp checks `sysctl -n hw.memsize` if `sys.platform == "darwin"`.
256 unixtools.sysctl
257 ]
258 ++ lib.optionals stdenv.hostPlatform.isDarwin [
259 # For gyp-mac-tool if `flavor == "mac"`.
260 darwin-cctools-only-libtool
261 ];
262
263 # We currently rely on Makefile and stdenv for build phases, so do not let
264 # ninja’s setup hook to override default stdenv phases.
265 dontUseNinjaBuild = true;
266 dontUseNinjaCheck = true;
267 dontUseNinjaInstall = true;
268
269 outputs = [
270 "out"
271 "libv8"
272 ]
273 ++ lib.optionals (stdenv.hostPlatform == stdenv.buildPlatform) [ "dev" ];
274 setOutputFlags = false;
275 moveToDev = false;
276
277 configureFlags = [
278 "--ninja"
279 "--with-intl=system-icu"
280 "--openssl-use-def-ca-store"
281 # --cross-compiling flag enables use of CC_host et. al
282 (if canExecute || canEmulate then "--no-cross-compiling" else "--cross-compiling")
283 "--dest-os=${destOS}"
284 "--dest-cpu=${stdenv.hostPlatform.node.arch}"
285 ]
286 ++ lib.optionals (destARMFPU != null) [ "--with-arm-fpu=${destARMFPU}" ]
287 ++ lib.optionals (destARMFloatABI != null) [ "--with-arm-float-abi=${destARMFloatABI}" ]
288 ++ lib.optionals (!canExecute && canEmulate) [
289 # Node.js requires matching bitness between build and host platforms, e.g.
290 # for V8 startup snapshot builder (see tools/snapshot) and some other
291 # tools. We apply a patch that runs these tools using a host platform
292 # emulator and avoid cross-compiling altogether (from the build system’s
293 # perspective).
294 "--emulator=${emulator}"
295 ]
296 ++ lib.optionals (lib.versionOlder version "19") [ "--without-dtrace" ]
297 ++ lib.optionals (!enableNpm) [ "--without-npm" ]
298 ++ lib.concatMap (name: [
299 "--shared-${name}"
300 "--shared-${name}-libpath=${lib.getLib sharedLibDeps.${name}}/lib"
301 /**
302 Closure notes: we explicitly avoid specifying --shared-*-includes,
303 as that would put the paths into bin/nodejs.
304 Including pkg-config in build inputs would also have the same effect!
305
306 FIXME: the statement above is outdated, we have to include pkg-config
307 in build inputs for system-icu.
308 */
309 ]) (builtins.attrNames sharedLibDeps);
310
311 configurePlatforms = [ ];
312
313 dontDisableStatic = true;
314
315 configureScript = writeScript "nodejs-configure" ''
316 exec ${python.executable} configure.py "$@"
317 '';
318
319 # In order to support unsupported cross configurations, we copy some intermediate executables
320 # from a native build and replace all the build-system tools with a script which simply touches
321 # its outfile. We have to indiana-jones-swap the build-system-targeted tools since they are
322 # tested for efficacy at configure time.
323 postConfigure = lib.optionalString (!canEmulate && !canExecute) ''
324 cp ${buildNode.dev}/bin/* out/Release
325 export FAKE_TOUCH=1
326 '';
327
328 enableParallelBuilding = true;
329
330 # Don't allow enabling content addressed conversion as `nodejs`
331 # checksums it's image before conversion happens and image loading
332 # breaks:
333 # $ nix build -f. nodejs --arg config '{ contentAddressedByDefault = true; }'
334 # $ ./result/bin/node
335 # Check failed: VerifyChecksum(blob).
336 __contentAddressed = false;
337
338 passthru.interpreterName = "nodejs";
339
340 passthru.pkgs = callPackage ../../node-packages/default.nix {
341 nodejs = self;
342 };
343
344 setupHook = ./setup-hook.sh;
345
346 pos = builtins.unsafeGetAttrPos "version" args;
347
348 inherit patches;
349
350 postPatch = lib.optionalString stdenv.hostPlatform.isDarwin ''
351 substituteInPlace test/parallel/test-macos-app-sandbox.js \
352 --subst-var-by codesign '${darwin.sigtool}/bin/codesign'
353 '';
354
355 __darwinAllowLocalNetworking = true; # for tests
356
357 doCheck = canExecute;
358
359 # See https://github.com/nodejs/node/issues/22006
360 enableParallelChecking = false;
361
362 # Some dependencies required for tools/doc/node_modules (and therefore
363 # test-addons, jstest and others) target are not included in the tarball.
364 # Run test targets that do not require network access.
365 checkTarget = lib.concatStringsSep " " (
366 [
367 "build-js-native-api-tests"
368 "build-node-api-tests"
369 "tooltest"
370 "cctest"
371 ]
372 ++ lib.optionals (!stdenv.buildPlatform.isDarwin || lib.versionAtLeast version "20") [
373 # There are some test failures on macOS before v20 that are not worth the
374 # time to debug for a version that would be eventually removed in less
375 # than a year (Node.js 18 will be EOL at 2025-04-30). Note that these
376 # failures are specific to Nix sandbox on macOS and should not affect
377 # actual functionality.
378 "test-ci-js"
379 ]
380 );
381
382 checkFlags = [
383 # Do not create __pycache__ when running tests.
384 "PYTHONDONTWRITEBYTECODE=1"
385 ]
386 ++ lib.optionals (stdenv.buildPlatform.isDarwin && stdenv.buildPlatform.isx86_64) [
387 # Python 3.12 introduced a warning for calling `os.fork()` in a
388 # multi‐threaded program. For some reason, the Node.js
389 # `tools/pseudo-tty.py` program used for PTY‐related tests
390 # triggers this warning on Hydra, on `x86_64-darwin` only,
391 # despite not creating any threads itself. This causes the
392 # Node.js test runner to misinterpret the warnings as part of the
393 # test output and fail. It does not reproduce reliably off Hydra
394 # on Intel Macs, or occur on the `aarch64-darwin` builds.
395 #
396 # This seems likely to be related to Rosetta 2, but it could also
397 # be some strange x86‐64‐only threading behaviour of the Darwin
398 # system libraries, or a bug in CPython, or something else
399 # haunted about the Nixpkgs/Hydra build environment. We silence
400 # the warnings in the hope that closing our eyes will make the
401 # ghosts go away.
402 "PYTHONWARNINGS=ignore::DeprecationWarning"
403 ]
404 ++ lib.optionals (!stdenv.buildPlatform.isDarwin || lib.versionAtLeast version "20") [
405 "FLAKY_TESTS=skip"
406 # Skip some tests that are not passing in this context
407 "CI_SKIP_TESTS=${
408 lib.concatStringsSep "," (
409 [
410 # Tests don't work in sandbox.
411 "test-child-process-exec-env"
412 "test-child-process-uid-gid"
413 "test-fs-write-stream-eagain"
414 "test-process-euid-egid"
415 "test-process-initgroups"
416 "test-process-setgroups"
417 "test-process-uid-gid"
418 # This is a bit weird, but for some reason fs watch tests fail with
419 # sandbox.
420 "test-fs-promises-watch"
421 "test-fs-watch"
422 "test-fs-watch-encoding"
423 "test-fs-watch-non-recursive"
424 "test-fs-watch-recursive-add-file"
425 "test-fs-watch-recursive-add-file-to-existing-subfolder"
426 "test-fs-watch-recursive-add-file-to-new-folder"
427 "test-fs-watch-recursive-add-file-with-url"
428 "test-fs-watch-recursive-add-folder"
429 "test-fs-watch-recursive-assert-leaks"
430 "test-fs-watch-recursive-promise"
431 "test-fs-watch-recursive-symlink"
432 "test-fs-watch-recursive-sync-write"
433 "test-fs-watch-recursive-update-file"
434 "test-fs-watchfile"
435 "test-runner-run"
436 "test-runner-watch-mode"
437 "test-watch-mode-files_watcher"
438
439 # fail on openssl 3.6.0
440 "test-http2-server-unknown-protocol"
441 "test-tls-ocsp-callback"
442 ]
443 ++ lib.optionals (!lib.versionAtLeast version "22") [
444 "test-tls-multi-key"
445 ]
446 ++ lib.optionals useSharedAdaAndSimd [
447 # Different versions of Ada affect the WPT tests
448 "test-url"
449 ]
450 ++ lib.optionals stdenv.hostPlatform.is32bit [
451 # utime (actually utimensat) fails with EINVAL on 2038 timestamp
452 "test-fs-utimes-y2K38"
453 ]
454 ++ lib.optionals stdenv.buildPlatform.isDarwin [
455 # Disable tests that don’t work under macOS sandbox.
456 # uv_os_setpriority returned EPERM (operation not permitted)
457 "test-os"
458 "test-os-process-priority"
459
460 # Debugger tests failing on macOS 15.4
461 "test-debugger-extract-function-name"
462 "test-debugger-random-port-with-inspect-port"
463 "test-debugger-launch"
464 "test-debugger-pid"
465
466 # Those are annoyingly flaky, but not enough to be marked as such upstream.
467 "test-wasi"
468
469 # This is failing on newer macOS versions, no fix has yet been provided upstream:
470 "test-cluster-dgram-1"
471 ]
472 ++ lib.optionals stdenv.hostPlatform.isMusl [
473 # Doesn't work in sandbox on x86_64.
474 "test-dns-set-default-order"
475 ]
476 ++ lib.optionals (stdenv.buildPlatform.isDarwin && stdenv.buildPlatform.isx86_64) [
477 # These tests fail on x86_64-darwin (even without sandbox).
478 # TODO: revisit at a later date.
479 "test-fs-readv"
480 "test-fs-readv-sync"
481 "test-vm-memleak"
482
483 # Those are annoyingly flaky, but not enough to be marked as such upstream.
484 "test-tick-processor-arguments"
485 "test-set-raw-mode-reset-signal"
486 ]
487 # Those are annoyingly flaky, but not enough to be marked as such upstream.
488 ++ lib.optional (majorVersion == "22") "test-child-process-stdout-flush-exit"
489 ++ lib.optional (
490 majorVersion == "22" && stdenv.buildPlatform.isDarwin
491 ) "test/sequential/test-http-server-request-timeouts-mixed.js"
492 )
493 }"
494 ];
495
496 sandboxProfile = ''
497 (allow file-read*
498 (literal "/Library/Keychains/System.keychain")
499 (literal "/private/var/db/mds/system/mdsDirectory.db")
500 (literal "/private/var/db/mds/system/mdsObject.db"))
501
502 ; Allow files written by Module Directory Services (MDS), which is used
503 ; by Security.framework: https://apple.stackexchange.com/a/411476
504 ; These rules are based on the system sandbox profiles found in
505 ; /System/Library/Sandbox/Profiles.
506 (allow file-write*
507 (regex #"^/private/var/folders/[^/]+/[^/]+/C/mds/mdsDirectory\.db$")
508 (regex #"^/private/var/folders/[^/]+/[^/]+/C/mds/mdsObject\.db_?$")
509 (regex #"^/private/var/folders/[^/]+/[^/]+/C/mds/mds\.lock$"))
510
511 (allow mach-lookup
512 (global-name "com.apple.FSEvents")
513 (global-name "com.apple.SecurityServer")
514 (global-name "com.apple.system.opendirectoryd.membership"))
515 '';
516
517 postInstall =
518 let
519 # nodejs_18 does not have node_js2c, and we don't want to rebuild the other ones
520 # FIXME: fix this cleanly in staging
521 tools =
522 if majorVersion == "18" then
523 "{bytecode_builtins_list_generator,mksnapshot,torque,gen-regexp-special-case}"
524 else
525 "{bytecode_builtins_list_generator,mksnapshot,torque,node_js2c,gen-regexp-special-case}";
526 in
527 lib.optionalString (stdenv.hostPlatform == stdenv.buildPlatform) ''
528 mkdir -p $dev/bin
529 cp out/Release/${tools} $dev/bin
530 ''
531 + ''
532
533 HOST_PATH=$out/bin patchShebangs --host $out
534
535 ${lib.optionalString canExecute ''
536 $out/bin/node --completion-bash > node.bash
537 installShellCompletion node.bash
538 ''}
539
540 ${lib.optionalString enableNpm ''
541 mkdir -p $out/share/bash-completion/completions
542 ln -s $out/lib/node_modules/npm/lib/utils/completion.sh \
543 $out/share/bash-completion/completions/npm
544 for dir in "$out/lib/node_modules/npm/man/"*; do
545 mkdir -p $out/share/man/$(basename "$dir")
546 for page in "$dir"/*; do
547 ln -rs $page $out/share/man/$(basename "$dir")
548 done
549 done
550 ''}
551
552 # install the missing headers for node-gyp
553 # TODO: use propagatedBuildInputs instead of copying headers.
554 cp -r ${lib.concatStringsSep " " copyLibHeaders} $out/include/node
555
556 # assemble a static v8 library and put it in the 'libv8' output
557 mkdir -p $libv8/lib
558 pushd out/Release/obj
559 find . -path "**/torque_*/**/*.o" -or -path "**/v8*/**/*.o" \
560 -and -not -name "torque.*" \
561 -and -not -name "mksnapshot.*" \
562 -and -not -name "gen-regexp-special-case.*" \
563 -and -not -name "bytecode_builtins_list_generator.*" \
564 | sort -u >files
565 test -s files # ensure that the list is not empty
566 $AR -cqs $libv8/lib/libv8.a @files
567 popd
568
569 # copy v8 headers
570 cp -r deps/v8/include $libv8/
571
572 # create a pkgconfig file for v8
573 major=$(grep V8_MAJOR_VERSION deps/v8/include/v8-version.h | cut -d ' ' -f 3)
574 minor=$(grep V8_MINOR_VERSION deps/v8/include/v8-version.h | cut -d ' ' -f 3)
575 patch=$(grep V8_PATCH_LEVEL deps/v8/include/v8-version.h | cut -d ' ' -f 3)
576 mkdir -p $libv8/lib/pkgconfig
577 cat > $libv8/lib/pkgconfig/v8.pc << EOF
578 Name: v8
579 Description: V8 JavaScript Engine
580 Version: $major.$minor.$patch
581 Libs: -L$libv8/lib -lv8 -pthread -licui18n -licuuc
582 Cflags: -I$libv8/include
583 EOF
584 ''
585 + lib.optionalString (stdenv.hostPlatform == stdenv.buildPlatform) ''
586 cp -r $out/include $dev/include
587 '';
588
589 passthru.tests = {
590 version = testers.testVersion {
591 package = self;
592 version = "v${lib.head (lib.strings.splitString "-rc." version)}";
593 };
594 };
595
596 passthru.updateScript = import ./update.nix {
597 inherit
598 writeScript
599 common-updater-scripts
600 coreutils
601 curl
602 fetchurl
603 gnugrep
604 gnupg
605 jq
606 runtimeShell
607 ;
608 inherit lib;
609 inherit majorVersion;
610 };
611
612 meta = {
613 description = "Event-driven I/O framework for the V8 JavaScript engine";
614 homepage = "https://nodejs.org";
615 changelog = "https://github.com/nodejs/node/releases/tag/v${version}";
616 license = lib.licenses.mit;
617 maintainers = with lib.maintainers; [ aduh95 ];
618 # https://github.com/nodejs/node/blob/732ab9d658e057af5191d4ecd156d38487509462/BUILDING.md#platform-list
619 platforms =
620 (lib.lists.intersectLists (
621 lib.platforms.linux ++ lib.platforms.darwin ++ lib.platforms.freebsd
622 ) lib.platforms.littleEndian)
623 ++ [ "s390x-linux" ];
624 # This broken condition is likely too conservative. Feel free to loosen it if it works.
625 broken =
626 !canExecute && !canEmulate && (stdenv.buildPlatform.parsed.cpu != stdenv.hostPlatform.parsed.cpu);
627 mainProgram = "node";
628 knownVulnerabilities = lib.optional (lib.versionOlder version "18") "This NodeJS release has reached its end of life. See https://nodejs.org/en/about/releases/.";
629 };
630
631 passthru.python = python; # to ensure nodeEnv uses the same version
632 }
633 );
634in
635package