Skip to content

cpython ./configure's -pthread detection is misbehaving on some variants #599

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
geofft opened this issue May 2, 2025 · 1 comment
Open

Comments

@geofft
Copy link
Collaborator

geofft commented May 2, 2025

I am getting CI failures on #592 on some variants because of missing pthread symbols because of a missing -pthread on the compiler command line. Compare, for instance, x86_64_v2-unknown-linux-gnu / 3.9 / debug which fails with

2025-04-28T21:36:18.8638916Z cpython-3.9> clang -L/tools/deps/lib -Wl,--exclude-libs,ALL    -Xlinker -export-dynamic -o Programs/_testembed Programs/_testembed.o -L. -lpython3.9d -lpthread -ldl  -lutil -lm -lbz2          -lffi -ldl  -lm  -lncursesw  -lpanelw -lncursesw   -ldb  -lmpdec  -lexpat  -lcrypto -l:libatomic.a     -llzma       -lrt          -lsqlite3  -lssl -lcrypto -l:libatomic.a        -ltcl8.6 -ltk8.6 -lX11 -lxcb -lXau  -luuid        -lm    -lm     -lexpat  -ledit -lncursesw         -lz                         -lm
2025-04-28T21:36:19.1392376Z cpython-3.9> /tools/host/bin/ld: /tools/deps/lib/libtcl8.6.a(tclUnixNotfy.o): in function `Tcl_InitNotifier
2025-04-28T21:36:19.1394260Z cpython-3.9> ':
2025-04-28T21:36:19.1395858Z cpython-3.9> tclUnixNotfy.c:(.text+0x7d): undefined reference to `pthread_atfork'
2025-04-28T21:36:19.1910841Z cpython-3.9> clang: error: linker command failed with exit code 1 (use -v to see invocation)

versus x86_64-unknown-linux-gnu / 3.9 / debug which succeeds with the corresponding build line being

2025-04-28T21:37:46.4684015Z cpython-3.9> clang -pthread -L/tools/deps/lib -Wl,--exclude-libs,ALL    -Xlinker -export-dynamic -o Programs/_testembed Programs/_testembed.o -L. -lpython3.9d -lpthread -ldl  -lutil -lm -lbz2          -lffi -ldl  -lm  -lncursesw  -lpanelw -lncursesw   -ldb  -lmpdec  -lexpat  -lcrypto -l:libatomic.a     -llzma       -lrt          -lsqlite3  -lssl -lcrypto -l:libatomic.a        -ltcl8.6 -ltk8.6 -lX11 -lxcb -lXau  -luuid        -lm    -lm     -lexpat  -ledit -lncursesw         -lz                         -lm

If you dig a bit earlier in the build logs, the x86_64_v2 (unsuccessful) build does

2025-04-28T21:35:49.0615195Z cpython-3.9> checking whether pthreads are available without options...
2025-04-28T21:35:49.0616630Z cpython-3.9> no
2025-04-28T21:35:49.0618854Z cpython-3.9> checking whether clang accepts -Kpthread...
2025-04-28T21:35:49.0619625Z cpython-3.9> no
2025-04-28T21:35:49.0622574Z cpython-3.9> checking whether clang accepts -Kthread... no
2025-04-28T21:35:49.0622969Z cpython-3.9> checking whether clang accepts -pthread...
2025-04-28T21:35:49.0623276Z cpython-3.9> no
2025-04-28T21:35:49.0623591Z cpython-3.9> checking whether clang++ also accepts flags for thread support...
2025-04-28T21:35:49.0623927Z cpython-3.9> no

while the x86_64 (successful) build does

2025-04-28T21:37:20.2180518Z cpython-3.9> checking whether pthreads are available without options...
2025-04-28T21:37:20.2551345Z cpython-3.9> no
2025-04-28T21:37:20.2552261Z cpython-3.9> checking whether clang accepts -Kpthread...
2025-04-28T21:37:20.2676725Z cpython-3.9> no
2025-04-28T21:37:20.2677100Z cpython-3.9> checking whether clang accepts -Kthread...
2025-04-28T21:37:20.2800777Z cpython-3.9> no
2025-04-28T21:37:20.2804876Z cpython-3.9> checking whether clang accepts -pthread...
2025-04-28T21:37:20.3187186Z cpython-3.9> yes
2025-04-28T21:37:20.3187607Z cpython-3.9> checking whether clang++ also accepts flags for thread support...
2025-04-28T21:37:20.3793651Z cpython-3.9> yes

This does not appear to have been introduced by my PR; the same ./configure discrepancy happens on HEAD (compare this run and this run, for instance), though the fact that ./configure decides not to pass -pthread does not fail the build on HEAD. I do not know if it has any unwanted side effects.

Almost certainly what is going on is that the test program is failing to run for some other reason, and ./configure is getting confused.

We need to resolve this as it blocks #592, and I'm a little bit uncomfortable with the fact that this discrepancy is happening and I'd like to think a bit about noticing and detecting discrepancies like this in the general case.

@geofft
Copy link
Collaborator Author

geofft commented May 6, 2025

Oh, I think what's going on is that these are the runs where we're cross-compiling (in the sense of "telling autoconf that we are cross-compiling"), and AC_RUN_IFELSE does not attempt to run a test program if we are cross-compiling. The last argument is what to default to.

This particular configure check does

if test $ac_cv_kthread = no -a $ac_cv_pthread_is_default = no
then
# -pthread, if available, provides the right #defines
# and linker options to make pthread_create available
# Some compilers won't report that they do not support -pthread,
# so we need to run a program to see whether it really made the
# function available.
AC_CACHE_CHECK([whether $CC accepts -pthread], [ac_cv_pthread],
[ac_save_cc="$CC"
CC="$CC -pthread"
AC_RUN_IFELSE([AC_LANG_SOURCE([[
#include <stdio.h>
#include <pthread.h>

void* routine(void* p){return NULL;}

int main(void){
  pthread_t p;
  if(pthread_create(&p,NULL,routine,NULL)!=0)
    return 1;
  (void)pthread_detach(p);
  return 0;
}
]])],[ac_cv_pthread=yes],[ac_cv_pthread=no],[ac_cv_pthread=no])
CC="$ac_save_cc"])
fi

where the key line is that third-to-last one: if the test program returns success, set ac_cv_pthread=yes, but if it fails, or if we are cross-compiling, set ac_cv_pthread=no.

If you want to play around with this in isolation, you can create a configure.ac file in an empty directory containing something like
AC_PREREQ([2.71])

AC_INIT([python],[3.14],[https://github.com/python/cpython/issues/])

AC_CACHE_CHECK([whether $CC accepts -pthread], [ac_cv_pthread],
[ac_save_cc="$CC"
CC="$CC -pthread"
AC_RUN_IFELSE([AC_LANG_SOURCE([[
#include <stdio.h>
#include <pthread.h>

void* routine(void* p){return NULL;}

int main(void){
  pthread_t p;
  if(pthread_create(&p,NULL,routine,NULL)!=0)
    return 1;
  (void)pthread_detach(p);
  return 0;
}
]])],[ac_cv_pthread=yes],[ac_cv_pthread=no],[ac_cv_pthread=no])
CC="$ac_save_cc"])

and then do

$ autoconf
/usr/share/autoconf/autoconf/trailer.m4:4: warning: AC_OUTPUT was never used
$ ./configure
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables... 
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether the compiler supports GNU C... yes
checking whether gcc accepts -g... yes
checking for gcc option to enable C11 features... none needed
checking whether gcc accepts -pthread... yes
$ ./configure cross_compiling=yes
checking for gcc... gcc
configure: WARNING: using cross tools not prefixed with host triplet
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables... 
checking whether we are cross compiling... yes
checking for suffix of object files... o
checking whether the compiler supports GNU C... yes
checking whether gcc accepts -g... yes
checking for gcc option to enable C11 features... none needed
checking whether gcc accepts -pthread... no

If you examine config.log in the latter case you'll see that no test was run (which is not surprising, this is the documented behavior).

(Incidentally, doing ./configure cross_compiling=yes seems to be equivalent to our patch-force-cross-compile.patch that we apply after autoreconf; see https://savannah.gnu.org/support/?110348 .)

I suspect this is also what was going on with python/cpython#128106, where we also got an unwanted ./configure result, and it looks like this was also an AC_RUN_IFELSE check whose cross-compilation assumption was that it was not supported (cc @zanieb).

This is a little frustrating; there's probably several of these feature detections that we're losing on all cross targets, including the optimized variants. Ideally, what I would like to do is to make autoconf error out on any of these. If you leave off the last argument to AC_RUN_IFELSE it will do that but I want to do that globally somehow.

For now, I guess I'll patch ./configure to assume that our compiler actually does support -pthread to unblock #592.

geofft added a commit to geofft/python-build-standalone that referenced this issue May 6, 2025
geofft added a commit to geofft/python-build-standalone that referenced this issue May 6, 2025
geofft added a commit to geofft/python-build-standalone that referenced this issue May 7, 2025
Also, switch to using cross_compiling=yes instead of patching
./configure in place, which allows us to move rerunning autoconf to
right before running ./configure, avoiding the risk of patching
./configure.ac too late.

See astral-sh#599.
geofft added a commit that referenced this issue May 8, 2025
Also, switch to using cross_compiling=yes instead of patching
./configure in place, which allows us to move rerunning autoconf to
right before running ./configure, avoiding the risk of patching
./configure.ac too late.

See #599.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant