Skip to content

libatomic.a dependency causes issues when building on Arch Linux #616

Open

Description

@csd4ni3l

Nuitka (and probably other py-to-exe software) tries to use libatomic.a instead of libatomic.so, which crashes gcc or other compilers.
In Arch Linux, libatomic.a does not exist anymore.
replacing compiler flags from -l:libatomic.a to -latomic fixes the issue, the dynamic version of libatomic is always available.

Example error:

gcc -o /home/csd4ni3l/Documents/Python3/shatterstack/test.dist/test -s -z noexecstack -export-dynamic -Wl,-R,'$ORIGIN' -Wl,--disable-new-dtags @"./@link_input.txt" -L/home/csd4ni3l/.local/share/uv/python/cpython-3.11.11-linux-x86_64-gnu/lib -ldl -lm -lpython3.11 -ldl -lpthread -lutil -lrt -lm -l:libatomic.a -l:libatomic.a
/usr/bin/ld: cannot find -l:libatomic.a: No such file or directory
/usr/bin/ld: cannot find -l:libatomic.a: No such file or directory
collect2: error: ld returned 1 exit status

Activity

  1. csd4ni3l commented on May 18, 2025

    @csd4ni3l
    Author

    Nuitka issue: Nuitka/Nuitka#3474

  2. self-assigned this
    on May 18, 2025
  3. geofft commented on May 18, 2025

    @geofft
    Collaborator

    I think this is leaking out from our internal use of -l:libatomic.a (see cpython-unix/extension-modules.yml), the original purpose of which was to avoid needing libatomic on end user systems, but unfortunately the Python extension build process leaks flags from how Python itself was built, which is probably why you're getting that on your build command line.

    We have since started also using libatomic.so on some platforms; see #410. It may be the case that we can actually assume there's a platform libatomic.so everywhere.

    Alternatively, we should be able to stop leaking this command line flag.

  4. csd4ni3l commented on Jun 5, 2025

    @csd4ni3l
    Author

    Any updates?

  5. zanieb commented on Jun 5, 2025

    @zanieb
    Member

    While we could add filtering for this to sysconfig, I don't think it's necessarily reasonable for us to remove every flag we use.

    It seems like Nuitka should provide a way to filter what it pulls from sysconfig?

  6. WilliamStam commented on Sep 30, 2025

    @WilliamStam

    getting this on redhat as well.

    is this a dependency for UV? (using nuitka 2.7.16). tried installing sudo dnf install libatomic and running nuitka with the flags

    env LDFLAGS="-L/usr/lib/gcc/x86_64-redhat-linux/8/32/libatomic.a -latomic"

            run: |
              env LDFLAGS="-L/usr/lib/gcc/x86_64-redhat-linux/8/32/libatomic.a -latomic" uv run python -m nuitka src/main.py \
                --standalone \
                --onefile \
                --msvc=latest \
                --output-filename=argus-redhat \
                --output-dir=build 
    
    

    but no such luck. which project is actually responsible for it? anyone found a way past it?

  7. kayhayen commented on Sep 30, 2025

    @kayhayen

    I might be wrong, but I believe at this time Nuitka works with the Standalone Python Build, albeit in a non-optimal way. My exchange with UV developers has revealed that the static link libraries it contains are tied to the specific compiler that is however not shipped, while Nuitka expects to be able to use any clang or gcc with them. Hence --static-libpython=auto defaults to --static-libpython=no with that Python flavor. Using a managed Python, e.g. Debian/Ubuntu Pythons gives a better result, so does Anaconda, and probably a lot more. This is of course no issue on Windows, where static linking of Python is not possible.

  8. WilliamStam commented on Oct 1, 2025

    @WilliamStam

    just fired up an ubuntu VM and tried in there. can confirm it works great after installing patchelf

    FATAL: Error, standalone mode on Linux requires 'patchelf' to be installed. Use 'apt/dnf/yum install patchelf' first.
    

    after sudo apt install patchelf and voila..

    steps:

    install uv
    curl -LsSf https://astral.sh/uv/install.sh | sh

    get python
    uv python install

    setup venv
    uv venv

    run build.sh

    uv sync
    
    uv build
    
    uv run python -m nuitka src/main.py \
    --standalone \
    --onefile \
    --output-filename=testing \
    --output-dir=build
    
    

    worked perfectly (ubuntu server 24.04)


    the same on red hat (8.9) tho fails with

    /usr/bin/ld: cannot find -l:libatomic.a
    /usr/bin/ld: cannot find -l:libatomic.a
    collect2: error: ld returned 1 exit status
    scons: *** [/home/munsys_william__bk/testing/build/main.dist/argus.bin] Error 1
    FATAL: Failed unexpectedly in Scons C backend compilation.
    Nuitka:WARNING:     Complex topic! More information can be found at https://nuitka.net/info/scons-backend-failure.html
    Nuitka-Reports: Compilation crash report written to file 'nuitka-crash-report.xml'.
    
  9. WilliamStam commented on Oct 1, 2025

    @WilliamStam

    after trying to pinpoint if the problem is nuitka or uv side and this thread Nuitka/Nuitka#3474 i went with trying it on vanila python. im copying the results here


    can confirm that in my case (red hat 8.9) using uv python leads to the error /usr/bin/ld: cannot find -l:libatomic.a but if you install python normally (or in my case used the old install - python3.6) it works fine.

    $ python3 --version
    Python 3.6.8
    
    
    $ source .venv/bin/activate
    $ python --version
    Python 3.6.8
    
    $ pip install nuitka
    ...
    $ python -m nuitka src/main.py --standalone --onefile --output-filename=testing --output-dir=build
    ...
    
    $ ll build
    total 16328
    drwxr-xr-x 3     4096 Oct  1 11:26 main.build
    drwxr-xr-x 2     4096 Oct  1 11:26 main.dist
    drwxr-xr-x 3     166 Oct  1 11:26 main.onefile-build
    -rwxr-xr-x 1  12700058 Oct  1 11:26 testing <--- YES!
    
    
  10. kayhayen commented on Oct 2, 2025

    @kayhayen

    Self compiled Python of course can make the same mistakes as the standalone Python build there, and the solution would be the same. Build it correctly or use a supported Python. For Fedora Python I believe that static libpython also defaults to "no" because they don't know how to provide a usable libpython either. Debian and others can do it. Although for Ubuntu I recently needed to give up with Python 3.14, or so it seems. These things are typically very neglected. I might describe more publically how to achieve it, but I lack the time and am out of here for now.

  11. indygreg commented on Oct 2, 2025

    @indygreg
    Collaborator

    The libatomic dependency is coming from OpenSSL. We could potentially change our OpenSSL build script to statically link libatomic. And then if libssl.a / libssl.so (or libcrypto) have the atomic symbols, we should be able to purge references to libatomic from CPython's build system, eliminating the possibility that sysconfig will leak implementation details.

    Assuming CPython itself doesn't direct depend on the symbols in libatomic, removing all references to libatomic from sysconfig could also work.

  12. polarathene commented on Oct 11, 2025

    @polarathene

    Short and sweet: Honestly quick and easy fix in this scenario (should libatomic.a not be acceptable, but libatomic.so is), just switch to -l atomic and ensure preference in your container build still selects the libatomic.a, matching the same behaviour as the other link args?

    Read on if that was not clear, I think I've covered everything relevant?

    This comment follows after a similar one I posted at Nuitka on the topic: Nuitka/Nuitka#3331 (comment)


    eliminating the possibility that sysconfig will leak implementation details.

    I am perhaps lacking the expertise here, is the only concern the presence of -l:libatomic.a?

    • I assume other libs there are also statically linked, but by not enforcing static/dynamic linking any build environment that would care about these link args is free to prioritize static libs ahead of dynamic libs?
    • If static libs are not relevant in this sysconfig metadata, shouldn't they be filtered out? (including those that are not explicitly static but still linked in statically?)

    I'm a tad confused to what exactly is leaked in this scenario (I understand the discussion is focused on -l:libatomic.a, but that aside the two parties involved it is unclear why this is considered a leak given how both have implemented this).

    • python-build-standalone has a workaround to prioritize static libs, but for some reason has chosen to have an explicit libatomic.a
    • Projects like Nuitka are reading the sysconfig MODLIBS and only filtering for the explicitly static linked libs. This seems questionable on their end, and they could just as easily fix it there too if that's the case.

    "Leaked" flags concern

    unfortunately the Python extension build process leaks flags from how Python itself was built, which is probably why you're getting that on your build command line.

    I don't think it's necessarily reasonable for us to remove every flag we use.

    The flags in sysconfig MODLIBS entry is only really relevant for linking a new .so of libpython (or to some degree creating a .a static lib), so I don't think there's any need to hide any of that through filtering/removal? 🤷‍♂️ (NOTE: I don't know much about the Python ecosystem, it would be good to clarify relevance 😅)

    There is a bit of duplicates listed, so filtering that to unique items might be nice at least?:

    -lbz2 -lffi -ldl -lncursesw -lpanelw -lncursesw -ldb -lmpdec -lexpat -lcrypto -l:libatomic.a -llzma -lrt -lsqlite3 -lssl -lcrypto -l:libatomic.a -luuid -lm -lm -lexpat -ledit -lncursesw -lz
    

    Inspecting symbols in the lib sure enough confirms the libs being statically linked:

    $ nm --defined-only --no-weak /root/.local/share/uv/python/cpython-3.10.18-linux-x86_64-gnu/lib/libpython3.10.so.1.0 | less
    
    # Dynamically linked libs:
    $ patchelf --print-needed /root/.local/share/uv/python/cpython-3.10.18-linux-x86_64-gnu/lib/libpython3.10.so.1.0
    libdl.so.2
    librt.so.1
    libm.so.6
    libpthread.so.0
    libutil.so.1
    libc.so.6

    NOTE: Some users at #275 are querying about the size of the library, either unaware of all the extra deps linked statically or stating the bundling is a bit more excessive and requesting a minimal version (Ubuntu packages a minimal Python variant for example).


    Presently only reported as a problem for Nuitka?

    The Nuitka maintainer @kayhayen is interested in a libpython.a instead of a libpython.so output.

    The above indicates what deps were linked in, but is only explicit about a static link for libatomic, yet a good portion of those deps appear to be static linked into the library itself, so the build system either lacked dynamic lib copies, or the static libs were in a search path with higher precedence than the .so equivalents.

    IIRC I saw in the python-build-standalone source there was some logic to remove the .so equivalents for most of those listed above from system lib paths, as a way to get the linker to favor the static libs, and justifying that as an acceptable workaround because it was a container build.

    When in control of how the link args are invoked, you could enforce static lib selection via -Bstatic and switch back to dynamic libs with -Bdyamic.

    Alternatively just add "-l:lib${LIB_NAME}.a" (easy enough transform to do), and you'll also prefer static lib selection if you prefer that over the -B flags. If taking the latter approach you can likewise specifically link libs dynamically by using .so instead of .a. Otherwise place your custom built static libs in a new search path and give that priority (preferred IMO).

    Nuitka to my knowledge presently mistakenly reads this Python's build sysconfig MODLIBS to carry over any .a links it finds into link args for the output binary it produces (this is handled in Nuitka source via getModuleLinkerLibs(), see "Investigation" section of this comment for more info).

    Seems unnecessary though? Nuitka seems to have done this because at the time they had come across a python-build-standalone supplied libpython.a (3.7) rather than a .so. Since creating a static lib would only bundle any built .o objects and defers linking, I'm not sure why only explicit static libs were of interest for Nuitka to capture? 🤷‍♂️


    Drop the explicit static link?

    I'm sure I'm missing something... otherwise if Nuitka is still carrying support around a libpython.a assumption, it could instead autodetect that easily enough for -lpython3.10 (ambiguous preference). In Nuitka's case, this is linking to the output binary, where libpython.so shouldn't need any of it's deps carried over AFAIK, it is only doing so for the libpython.a scenario? (where static libs like libatomic could technically be merged IIRC, but -l atomic should work just as well at Nuitka's side?)

    Here's an example of preferring ambiguous link args when that makes sense (otherwise explicitly static/dynamic linking as demonstrated here):

    $ docker run --rm -it fedora:42 bash
    $ dnf install -yq gcc libatomic libatomic-static
    
    $ mkdir /tmp/prefer-static
    $ ln --symbolic "$(gcc -print-search-dirs | grep ^install: | cut -d' ' -f2)libatomic.a" /tmp/prefer-static/libatomic.a
    
    $ gcc -shared -nodefaultlibs -L /tmp/prefer-static/ -l atomic -o /tmp/example
    # No dynamic link, `/tmp/prefer-static` only contained a `libatomic.a` and was found first:
    $ ldd /tmp/example
            statically linked
    Extra reference context (collapsed for brevity)
    # With default glibc link by GCC:
    $ gcc -shared -L /tmp/prefer-static/ -l atomic -o /tmp/example
    $ ldd /tmp/example
            linux-vdso.so.1 (0x00007ffe51715000)
            libc.so.6 => /lib64/libc.so.6 (0x0000773962f12000)
            /lib64/ld-linux-x86-64.so.2 (0x000077396310d000)
    
    $ gcc -shared -nodefaultlibs -l atomic -o /tmp/example
    $ ldd /tmp/example
            linux-vdso.so.1 (0x00007ffc57aa8000)
            libatomic.so.1 => /lib64/libatomic.so.1 (0x0000712712c7a000)
            libc.so.6 => /lib64/libc.so.6 (0x0000712712a88000)
            /lib64/ld-linux-x86-64.so.2 (0x0000712712c8e000)
    
    $ patchelf --print-needed /tmp/example
    libatomic.so.1
    
    $ gcc -shared -l atomic -o /tmp/example
    $ patchelf --print-needed /tmp/example
    libatomic.so.1
    libc.so.6

    Static vs Dynamic choice

    @kayhayen since you're linking with Nuitka, you should have the choice here how Nuitka passes these link args to the compiler/linker. Normalize -l:lib<name>.a to -l <name> and problem solved? A user could still link libs statically if they wanted.

    My exchange with UV developers has revealed that the static link libraries it contains are tied to the specific compiler that is however not shipped, while Nuitka expects to be able to use any clang or gcc with them.

    libatomic is a system library. If you were to link dynamically, GCC provides libatomic.so which is just a linker script to the system versioned library (eg: /usr/lib64/libatomic.so.1.2.0) which has the common DT_SONAME entry of libatomic.so.1, which is the actual lib linked and queried for at runtime (the .so is purely a placeholder for dev convenience at build/link-time).

    On Fedora Clang depends on GCC and implicitly includes the GCC search paths, so it will also find libatomic.so at link-time. Other compilers like Zig would need to be given the extra search dir via -L. Same scenario for libatomic.a (via libatomic-static package).

    This shouldn't be any different to linking libgcc_s.so.1? (something Rust built software commonly links to, but is not present if compiling with Zig instead)


    For Fedora Python I believe that static libpython also defaults to "no" because they don't know how to provide a usable libpython either.

    A shared library is still usable, a static lib can be convenient/beneficial but is not always available in a build environment (if depending only on system packages to source that static lib).

    Rust *-sys crates often offer support for static builds, but you can look at the issues open on a few of those to see the various headaches that users can run into from offering such, whereas a shared library is much more accessible for them to get a successful build.

    I'm not familiar enough with building Python, but the following may be of interest to you:

    So they probably do know how to provide what you'd like, but for whatever reason Fedora doesn't offer a python-static package or similar. Debian/Ubuntu might make you happy in this situation, but they're not without their own caveats in my experiences with using those distros 😓

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions