Code explanation for absence of stdatomic.h for python build

Hi,

Let’s say I am compiling Python-3.13.5 with a non GCC compiler. This leads to inclusion of pyatomic_std.h in the header file. pyatomic_std.h file has the following code,

#ifdef __cplusplus
extern "C++" {
#  include <atomic>
}
#  define _Py_USING_STD using namespace std
#  define _Atomic(tp) atomic<tp>
#else
#  define  _Py_USING_STD
#  include <stdatomic.h>
#endif
```


I am unable to understand the #ifdef __cplusplus part. CPython is compiled with c11 standards, and if stdatomic.h were not to be present would the above code mean we need to compile python with c++11?

While answering assume the following things, let’s say my platform doesn’t have stdatomic.h but supports in C++. I just want to see how the above code would make any sense for CPython.

AFAIK, C++ atomics support also the C functions - I read that code as “if you’re compiling in C++ mode, use the C++ atomics support instead of the C one”

That would require compiling entire python with C++, correct? Issues will pop up like implicit conversion of (void *). C allows implicit conversion, but C++ doesn’t allow it.

I don’t think so. But AIUI you can include the Python headers in a C++ program, and thus build an extension library in C++.

The rules for the Python C source code include:

“The public C API should be compatible with C++.”

Please correct me if I am interpreting it wrongly, so what you are suggesting is to compile the C API of python with C++ and the rest of python Modules with C? wouldn’t linking be an issue? Let’s assume I am trying to build Python-3.13.5 with the limitation of not having stdatomic.h but I have in C++. What would be the approach then?

You would need to build it in C instead. The point of being C++ compatible is to allow you to write an extension module.

Thank you @Rosuav, I get it now. So, for building python with a non-GNU(non-windows) compiler we need stdatomic.h(without this build will fail). the atomic header is only for C++ extensions compatibility.

1 Like

Yes, I believe that is correct.

What platform and what compiler are you using? What C standards is it compatible with?

Hmm. The plot thickens. Atomics are an optional part of C11 (see Wikipedia), and according to PEP 11, CPython should build using C11 “without optional features”. Looking at pyatomic.h though, it does seem that this is mandatory. There are several options (one GCC-specific which is preferred even if it supports C11 atomics, one MSC-specific, and then one that tests for a C version and ensures that the flag __STDC_NO_ATOMICS__ isn’t set), but one of them MUST be available or it errors out. However, if that had been what happened, you wouldn’t have mentioned pyatomic_std.h, but would simply have reported that pyatomic.h had thrown a compilation error. So something must have thought that your compiler supported them.

But also, and I’m not 100% sure here, this might be a question of platform support. Might need a core dev to weigh in on the exact meaning here and whether any supported platform can slip through the cracks there.

Regarding your first question, my platform is NonStop(Non-Standard but similar to IBM AIX). Our compilers support C11 standards.

Regarding the second part, yes, my build errors out at pyatomic_std.h with error of stdatomic.h not being present. However, configure goes through with the following message at the end,

configure: Your compiler or platform does have a working C11 stdatomic.h. A future version of Python may require stdatomic.h.

so, if the configure says this, then I assumed that stdatomic.h is optional for compilation of CPython.

checking for stdatomic.h… no

The above is returned correctly in my configure, however once it finishes, I get this,

configure: Your compiler or platform does have a working C11 stdatomic.h. A future version of Python may require stdatomic.h.

should the message be “doesn’t have stdatomic.h” and instead a typo came in? That is one part, second being if stdatomic.h is compulsory configure should fail there itself.

Yeah, I think that’s a straight-forward mistake of language; I’m looking at configure.ac and it makes a lot more sense as “does not have”. However, that does still imply that it’s currently optional. A more serious concern is whether that’s true, or if we have now reached that “future version” when it becomes required - if we have, the configure script needs to be updated.

Yes, I agree. This needs to be brought to attention. If stdatomic.h is not present and mandatory for build, then configure itself should not go through.

Yeah, I agree. I’m not sure whether it’s meant to be optional or required, but all three (compilation, configuration, and documentation) should say the same thing.

I opened a thread where the core devs are more likely to see it.

1 Like

Presumably it isn’t GCC though, as there’s separate support for GCC’s atomics.

Can you tell us anything more about the compiler toolchain you’re using?

It’s possible that this is an error of wording in the configure script, and as of CPython 3.13, stdatomic is in fact required. If that’s the case, you’ll need to get compiler support for atomics, or downgrade to CPython 3.12, which was the last version before that became an error.

It’s a x86 based in house compiler currently on C and C++11 standards. It is not supported by Python(but as said earlier, to an extent mimics AIX). So atomics support need to be brought in then. This should answer my question. Inclusion of atomics doesn’t violate PEP 11?(as mentioned earlier)

I think it probably should? I’m not sure. This isn’t my decision to make, there are two distinct approaches possible.

What happens if you remove the #include "pyatomic.h" line in Python.h? Can you get most/all of Python to build, and if so, what parts don’t work?

I need to try this out. Let me check and get back.

1 Like

I tried compilation after removing pyatomic.h

 “/home/Python-3.13.5/Include/cpython/lock.h”, line 48: error(114):identifier “_Py_atomic_compare_exchange_uint8” is undefined    if 
(!_Py_atomic_compare_exchange_uint8(&m->_bits, &expected, _Py_UNLOCKED)) {        ^ “/home/Python-3.13.5/Include/cpython/lock.h”, line 59: error(114):identifier “_Py_atomic_compare_exchange_uint8” is undefined

I am hitting undefined symbol errors, and in the beginning of compilation. So atomics are important then, there is no other option than to get those on our platform for C.

Does NonStop support GCC-style __atomic builtins? If so, we just need to adjust the guards in pyatomic.h. If not, does it support the legacy __sync extensions?

For example, do either of these two programs compile?

#include <stdio.h>

int main(void) {
    int x = 0;
    int old = __atomic_fetch_add(&x, 1, __ATOMIC_SEQ_CST);
    printf("__atomic_fetch_add %d %d\n", old, x);
    return 0;
}
#include <stdio.h>

int main(void) {
    int x = 0;
    __sync_fetch_and_add(&x, 1);
    printf("legacy __sync_fetch_and_add: %d\n", x);
    return 0;
}

The only documentation I found online is this: https://support.hpe.com/hpesc/public/docDisplay?docId=c02128447&docLocale=en_US and I can’t find definitive answers.