Repository navigation
Node should run on Debian/Ubuntu-based images without having to manually install libatomic first #60790
Description
Activity
- addedfeature requestIssues requesting new Node.js features.Issues requesting new Node.js features.
on Nov 20, 2025 Ref: #37219 (comment)
Upstream V8 avoids this by providing a custom libcxx which includes atomic functions. There is reference in an upstream V8 issue with a desire to retire the option to not use the custom libcxx (which Node.js is currently using), so we may need to switch eventually.
This will absolutely break reasonable assumptions for single-executable-application deployments using the official node runtime binaries if not rectified.
Reacted by Denis Zavershinskiy, Rose Bouchayer, Pieter Develtere and Aral BalkanShould the documentation of NodeJS mention somewhere that in common Linux distributions, what command should be used to install
libatomic.so.1? In the amd64 architecture of Ubuntu 24.04, there are 57 system dependencies that contain this file. For reference, see https://packages.ubuntu.com/search?suite=noble&arch=amd64&searchon=contents&keywords=libatomic.so.1 .The current error logs of
node --versiondo not show this.node: error while loading shared libraries: libatomic.so.1: cannot open shared object file: No such file or directoryReacted by Olivier Mourlevat, Corentin Girard and Tam JordanI am not familiar enough with linux or node to tell whether or not node could include libatomic.
But if that was possible and practical then that would allow debian and ubuntu based images to run node again without having to install libatomic first.TL;DR: If building Node with
zig cc/zig c++this should remove the dependency IIRC, that compiler specifically special cases libatomic regardless of static/shared link request, as it builds it's own on-demand for the build target and bundles that in statically AFAIK.A similar dependency issue is with
python-build-standaloneproject's Python distribution, although they statically linklibatomicinto their binary instead of a dynamic link. The problem over there is some other project's like Nuitka read in build metadata to link the dep, even when it shouldn't be necessary as it was a static dep, not dynamic. That project has built their binaries for distribution on rather old build environments wherelibatomicwas needed for a dependency, and discusses if that's really still necessary.libatomicis it needed for modern hardware? If so how feasible is static linking?I'm not too familiar with using libatomic myself. I have heard that there might be a concern with not linking to a shared library at runtime? But that might depend on what else is running?:
SchrodingerZhu/snmalloc-rs#187 (comment)
I remember
snmallocemits references to certain__atomic*symbols.
Many platforms does not ship a static version oflibatomicdue to its nature (there is some datum inside libatomic that ought to be shared by processes).Apparently it's also not likely to be needed on modern systems, but rather for hardware/architectures well over a decade old?
SchrodingerZhu/snmalloc-rs#187 (comment)
Ideally, I don't think we should even link against it if users know that their program is to run only on modern enough hardware.
libatomicis a portability support library.
The compiler emits function call to symbols insidelibatomicinstead of raw atomic instruction to make sure that the produced binary can be run with different hardware capabilities.Clearly that's more of a difficult call for NodeJS, but such platforms could perhaps have alternative legacy build support? 🤷♂️
Zig via
zig cc/zig c++could solve this?With Zig building NodeJS you can avoid the hassle of building in a rather dated environment to reduce glibc (I see it's targeting glibc
2.28on the copy I have installed fromprotoCLI).Zig can specify a glibc version in it's
-gnutargets, whilst also providing the convenience of omittinglibatomicandlibgcc_slibraries (if you raise the glibc target up to2.34from around Aug 2021, you'd additionally have other glibc related libraries omitted which isn't zig specific but a change from glibc itself).This Dec 2024 commit for Zig
0.14.0onwards documents how Zig is handlinglibatomic:compiler: Classify
libatomicas an alias forcompiler-rt.This is a library that ships with GCC and provides fallback implementations of atomic intrinsics where necessary.
Since we do the same in ourcompiler-rtimplementation, and since some build systems insist on passing-latomiceven for Clang (whichzig ccmasquerades as), just satisfy this dependency by way ofcompiler-rt.Which implies Clang doesn't need this either? I haven't checked, it may be an opt-in feature there for
compiler-rt?The associated Zig issue that was resolved by that referenced commit:
It makes sense for us to recognize and treat
libatomicspecially as it's a compiler-provided library.
Ourcompiler-rtimplementation should be able to satisfy itRelated reference that covers gcc libs handled by Zig too:
I'm pretty sure we can (and should) satisfy
libgcc_ehby linking Zig's bundledlibunwind, just as we do forlibgcc_s.I personally think the current issue is actually a duplicate of nodejs/build#4091 . Will this bug automatically disappear once all builds are migrated to gcc 13.1+? I don't believe that switching to
zig cc/zig c++halfway through the Clang migration will enable support for platforms that clang doesn't support.Reacted by Brennan KinneyI personally think the current issue is actually a duplicate of nodejs/build#4091 .
I don't see how that's related? There isn't a discussion there about libatomic? Could you please clarify?
Your prior comment references Ubuntu and a package to install, but I don't think you're familiar with the convention (see the Fedora example below), you just need
apt-get install libatomic1in your runtime environment which will resolve to the correct package for your architecture.
I don't believe that switching to
zig cc/zig c++halfway through the Clang migration will enable support for platforms that clang doesn't supportI've not looked into if Clang has the same behaviour as Zig to avoid an explicit
libatomiclink when it's not necessary for the platform target, is that something you can confirm?EDIT: I'm pretty sure you still have to explicitly link by default for Clang, and depending on distro, like with GCC you'd need
libatomic.apresent which may need a separate package installed.Will this bug automatically disappear once all builds are migrated to gcc 13.1+?
Is that a release that does the same as I described with Zig but with GCC?Nope.EDIT: See my next comment, I cover both Ubuntu and Fedora since they differ a tad. Short version is I don't think GCC or Clang provide the same convenience I described that Zig offers for
libatomic.I just checked in Fedora and it has GCC 15 with only a
libatomic.sobundled (as a linker script) for linking to/usr/lib64/libatomic.so.1(the runtime dep linked based onDT_SONAMEvalue, which should resolve a symlink to the full versioned lib in a runtime environment).- To get the
libatomic.ayou'd need to installlibatomic-static. Ideal as drops the runtime requirement. - To get the
libatomic.so.1you'd need to installlibatomic. This the current situation users have an issue with.
Here's an example for Fedora
# Reproduction environment via a Fedora 43 container with GCC installed: $ docker run --rm -it fedora:43 $ dnf instally -yq gcc # 32-bit is available: $ ls /usr/lib/gcc/x86_64-redhat-linux/15/32/libatomic* /usr/lib/gcc/x86_64-redhat-linux/15/32/libatomic.a /usr/lib/gcc/x86_64-redhat-linux/15/32/libatomic.so # Otherwise only a linker script stub: $ ls /usr/lib/gcc/x86_64-redhat-linux/15/libatomic* /usr/lib/gcc/x86_64-redhat-linux/15/libatomic.so $ cat /usr/lib/gcc/x86_64-redhat-linux/15/libatomic* INPUT ( /usr/lib64/libatomic.so.1.2.0 ) $ ls /usr/lib64/libatomic.so.1.2.0 ls: cannot access '/usr/lib64/libatomic.so.1.2.0': No such file or directory # Dynamic link: $ dnf provides '*/libatomic.so*' libatomic-15.2.1-2.fc43.x86_64 : The GNU Atomic library Repo : updates-testing Matched From : Filename : /usr/lib64/libatomic.so.1 Filename : /usr/lib64/libatomic.so.1.2.0 # Static link: $ dnf provides '*/libatomic.a' libatomic-static-15.2.1-7.fc43.x86_64 : The GNU Atomic static library Repo : updates Matched From : Filename : /usr/lib/gcc/x86_64-redhat-linux/15/libatomic.a
Clang (at least in Fedora) is configured to include the GCC paths, such that it gets the
libatomic.aavailable in the same manner as GCC.So I don't think anything has changed there from what I've said in my previous comment?
- Whereas if you
dnf install -yq zigyou do not need the separatelibatomic/libatomic-staticlibrary and can usezig ccorzig c++as the compiler and it'll handle thelibatomicfor you, no need to-l libatomiceither (although AFAIK that'd be expected for GCC/Clang). - This was the point I was trying to make, that it was simpler for a build environment to use zig, but explicitly static linking
libatomicwith GCC/Clang with a separate package works too.
For reference, here is GCC 13 on Ubuntu 24.04 with only the
libgcc-13-devpackage (dep ofgccpackage) installed, which includes the mentionedlibatomic1runtime package andlibatomic.a(_as part oflibgcc-13-dev):$ docker run --rm -it ubuntu:24.04 $ apt-get -qq update && apt-get -qq install libgcc-13-dev $ ls -l /usr/lib/gcc/x86_64-linux-gnu/13/libatomic* -rw-r--r-- 1 root root 139488 Dec 18 20:59 /usr/lib/gcc/x86_64-linux-gnu/13/libatomic.a lrwxrwxrwx 1 root root 40 Dec 18 20:59 /usr/lib/gcc/x86_64-linux-gnu/13/libatomic.so -> ../../../x86_64-linux-gnu/libatomic.so.1 # Symlink of a symlink (not a linker script like on Fedora): $ readlink --canonicalize /usr/lib/gcc/x86_64-linux-gnu/13/libatomic.so /usr/lib/x86_64-linux-gnu/libatomic.so.1.2.0 # View the `DT_SONAME` that will get linked and required at runtime (`libatomic.so.1`) # `libatomic.so` is only relevant for link time during builds (but some devs get confused and think it's required for runtime) $ apt-get -qq install patchelf $ patchelf --print-soname /usr/lib/gcc/x86_64-linux-gnu/13/libatomic.so libatomic.so.1
There's nothing special about GCC 13 in Ubuntu there, go back to Ubuntu 20.04 with GCC 9 and it's the same.
So in a build environment you'd have
libatomic.aalready with thegccpackage installed. You just need to indicate to static link thatlibatomic.aas a preference overlibatomic.so(dynamic is preferred by default when available), so that'd be handled by either:- Direct linker flags:
-Bstatic -l atomic -Bdynamic - Linker flags for the compiler to pass on:
-Wl,-Bstatic -l atomic -Wl,-Bdynamic(there is also-l:libatomic.aas an alternative but Zig's C/C++ linker isn't compatible with it)
The link you provided talked about RHEL, so I'd assume it's similar to Fedora more than Ubuntu, but I've not looked. Most likely scenario is the dependency is just
-l atomicinstead of advised above to ensure the static lib is linked instead.Hopefully that better clarifies why I suggested Zig.
- With Zig you don't have to think about your distro as much, what version of glibc your build environment is linking, or the libatomic linking issues above.
- Zig will sort you out nicely there as it's a self-contained toolchain. It does have 100% parity in linker option support though, I have had some software fail to link as a result but that's generally rare.
- I ran into an
libatomicissue withpython-build-standalone+ Nuitka + Zig due to-l:libatomic.a, so this topic is quite familiar for me 😅
- To get the
- added a commit that references this issue
on Apr 28, 2026 - addedv26.xIssues that can be reproduced on v26.x or PRs targeting the v26.x-staging branch.Issues that can be reproduced on v26.x or PRs targeting the v26.x-staging branch.and removed
on May 1, 2026 This would be a blocker for v26 LTS, right?
This would be a blocker for v26 LTS, right?
I don't think this will hinder the release of the new LTS version, because I don't even know which git to put the PR that solves this problem into.
I made PR: #63270
it's more of a POC with compiling with clang on LinuxReacted by Hengqian Ling, Rose Bouchayer, awa-xima, shwu-jt and Pieter DeveltereI'm a bit confused by this one. I'm seeing on the v8 lists that the node team is still supporting gcc compilation, since the v8 team officially dropped support for it. But it looks like the distributed nodejs binaries are now being built with clang.
There is a long-standing issue in clang where std::atomic generates runtime calls under libstdc++. gcc doesn't emit the same runtime calls.
root[15:09:39] [/workspace] $ clang++ --version Debian clang version 22.1.4 (1) Target: aarch64-unknown-linux-gnu Thread model: posix InstalledDir: /usr/lib/llvm-22/binroot[15:11:14] [/workspace] $ cat a.cc #include <atomic> struct foo_t { uint32_t left, right; }; int main() { std::atomic<foo_t> foo; foo_t one, two; foo.compare_exchange_strong(one, two); }root[15:11:18] [/workspace] $ clang++ -stdlib=libc++ a.cc root[15:11:21] [/workspace] $ clang++ -stdlib=libstdc++ a.cc /usr/bin/aarch64-linux-gnu-ld.bfd: /tmp/a-e6eab6.o: in function `std::atomic<foo_t>::compare_exchange_strong(foo_t&, foo_t, std::memory_order, std::memory_order)': a.cc:(.text._ZNSt6atomicI5foo_tE23compare_exchange_strongERS0_S0_St12memory_orderS3_[_ZNSt6atomicI5foo_tE23compare_exchange_strongERS0_S0_St12memory_orderS3_]+0x204): undefined reference to `__atomic_compare_exchange' /usr/bin/aarch64-linux-gnu-ld.bfd: a.cc:(.text._ZNSt6atomicI5foo_tE23compare_exchange_strongERS0_S0_St12memory_orderS3_[_ZNSt6atomicI5foo_tE23compare_exchange_strongERS0_S0_St12memory_orderS3_]+0x24c): undefined reference to `__atomic_compare_exchange' /usr/bin/aarch64-linux-gnu-ld.bfd: a.cc:(.text._ZNSt6atomicI5foo_tE23compare_exchange_strongERS0_S0_St12memory_orderS3_[_ZNSt6atomicI5foo_tE23compare_exchange_strongERS0_S0_St12memory_orderS3_]+0x294): undefined reference to `__atomic_compare_exchange' /usr/bin/aarch64-linux-gnu-ld.bfd: a.cc:(.text._ZNSt6atomicI5foo_tE23compare_exchange_strongERS0_S0_St12memory_orderS3_[_ZNSt6atomicI5foo_tE23compare_exchange_strongERS0_S0_St12memory_orderS3_]+0x334): undefined reference to `__atomic_compare_exchange' /usr/bin/aarch64-linux-gnu-ld.bfd: a.cc:(.text._ZNSt6atomicI5foo_tE23compare_exchange_strongERS0_S0_St12memory_orderS3_[_ZNSt6atomicI5foo_tE23compare_exchange_strongERS0_S0_St12memory_orderS3_]+0x37c): undefined reference to `__atomic_compare_exchange' /usr/bin/aarch64-linux-gnu-ld.bfd: /tmp/a-e6eab6.o:a.cc:(.text._ZNSt6atomicI5foo_tE23compare_exchange_strongERS0_S0_St12memory_orderS3_[_ZNSt6atomicI5foo_tE23compare_exchange_strongERS0_S0_St12memory_orderS3_]+0x3c4): more undefined references to `__atomic_compare_exchange' follow clang++: error: linker command failed with exit code 1 (use -v to see invocation)You can get around it by statically linking against libatomic but the intrinsics that gcc emits are better. I've just been using gcc to avoid the runtime calls.
Any update on this? Are there plans to have a "custom libcxx which includes atomic functions"
Reacted by shwu-jt and Aral BalkanReacted by Rose BouchayerThis basically means that the standalone Node binaries are broken on major Linux distributions and this PR fixes it:
This should really be implemented before 26 hits LTS.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsAwaiting Triage
What is the problem this feature will solve?
Summary
Node 25.0.0 requires the libatomic library, it's in the docs since 25.2.0.
I've tried some current official Ubuntu images (24.04, 25.10, 26.04) and Debian images (12.12, 13.12) and none comes with libatomic installed.
Consequently installing node on Debian or Ubuntu will work, but running any commands will fail.
Why should this be supported
I assume that having a seamless installation experience, at least on major linux distros, is something Node would like to provide. I'm thinking a) install nvm, b) install node via nvm, c) done, you can use node now.
This is also how, for example, the npm docs tell you to install npm. And it no longer works on Debian or Ubuntu based images unless you also install "libatomic".
Debian and Ubuntu are two of the major linux distros. Many projects are using one of their images as the basis for their official docker images. For example, the official Jenkins image is debian based and the latest version (
jenkins/jenkins:2.538-jdk21) can not run node 25+, unless you first install "libatomic" into the container that is.What is the feature you are proposing to solve the problem?
I am not familiar enough with linux or node to tell whether or not node could include libatomic. But if that was possible and practical then that would allow debian and ubuntu based images to run node again without having to install libatomic first.
What alternatives have you considered?
Out of these I've only really considered 1 and 4 real possibilities, though with the folks at nvm saying it's not their job it's either on Node itself or the end user, probably.