How to compile python in termux

I try to use 3.13.7 in termux. However, it failed:

Python/fileutils.c:2992:9: error: call to undeclared function ‘close_range’; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
2992 | if (close_range(first, last, 0) == 0) {
| ^
1 error generated.
make: *** [Makefile:3032: Python/fileutils.o] Error 1

I’d look at how the package manager for Termux builds Python. They provide an official build environment, so I suspect it’s cross compiled..

Otherwise it’s really easy to break a Python build. I don’t recommend trying to compile it on an unusual environment or with an unusual compiler for no good reason. And that applies even when not building Python for Android (or embedding it in an app) at all.

Nonetheless, if you’re going to persist with this, close_range is relatively recent Linux sys call added to Python as an optimisation
If close_range is available in Termux, make sure all the headers are available, e.g. installing build-essential etc. to avoid linker errors. Otherwise double check the config step was carried out correctly that tests for close_range support, cpython/configure at 7909b304931ddbded5140985fc51999f4b0c7e42 · python/cpython · GitHub. If not, it’s a hack, but it would be worth trying to set HAVE_CLOSE_RANGE in the make file (to the same end as adding #define HAVE_CLOSE_RANGE=0 or removing the directive defining that name altogether). fileutils.c is intended to be able to skip the block that uses close_range is needs be.

:hammer_and_wrench: Initial Setup

To begin, you need to build Python correctly:

make distclean
bash configure --prefix=$PREFIX --enable-optimizations

  • $PREFIX is needed so that make install knows where to place the build output.

  • --enable-optimizations is always used throughout this guide.


:high_voltage: Use Parallel Compilation

It’s useful to run:

make -j$(nproc)

This distributes the load across all 8 of my CPU cores, instead of funneling everything into a single thread.


:brick: Missing ar Archiver

If you encounter an error about a missing ar archiver, install the appropriate package:

  • For GCC builds:

    pkg install binutils
    
    
  • For Clang builds:

    pkg install binutils-is-llvm
    
    

:gear: Fixing Platform-Specific Issues

In the working directory of the CPython repository, there’s a file called pyconfig.h.

Just append the following lines to the end (or, like I did, search for each parameter manually and comment out the corresponding #define):

#undef HAVE_SEM_CLOCKWAIT
#undef HAVE_PTHREAD_GETNAME_NP
#undef HAVE_PTHREAD_SETNAME_NP
// These errors were mostly triggered by Modules/posixmodule.c:
#undef HAVE_STATX
#undef HAVE_FEXECVE
#undef HAVE_GETLOGIN_R
#undef HAVE_GETLOADAVG
#undef HAVE_PWRITEV2
#undef HAVE_PREADV2
#undef HAVE_GETPWENT

This is a Termux-specific issue: the GCC compiler simply lacks these functions :sweat_smile:
If you run into problems, inspect the code and look for #if or #ifdef blocks — usually the missing symbol name is mirrored in a HAVE_ macro.


:warning: Gotcha: #define ... 0 Doesn’t Work

#define HAVE_PTHREAD_GETNAME_NP 0  // ❌ Doesn't work
#undef HAVE_PTHREAD_GETNAME_NP     // ✅ Works

I thought the developers messed up, but in reality, you need to check the comment ending with:
", and to 0 if you don't." — which precedes the #define.
Still, this isn’t always reliable, since different developers interpret it differently.


:snake: Running Python from the CPython Repo

To run the freshly built Python:

./python

If you just type python, it will launch Termux’s default version — currently 3.12.9 at the time of writing.


:test_tube: Crude but Working Override (No make install, no PGO, no symlinks)

export PATH="$PWD:$PATH"
python --version
# Output: Python 3.15.0a1+

This works only for the current session and doesn’t support pip.


:test_tube: Testing Notes

During testing, some modules failed. Test 41/43 even crashed the test runner due to Android security restrictions.

Example: testing re

>>> import re
>>> dir(re)
['A', 'ASCII', 'DEBUG', 'DOTALL', 'I', ...]
>>> print(re.findall(r'\d+', 'abc123def456'))
['123', '456']

As you can see, re works fine. The test failure was due to a fork() or similar system call not supported on Android — so we can safely ignore it.


:broom: Cleaning Up PGO Tests Before make install

Before running make install, go to:

Lib/test/libregrtest/pgo.py

Delete all tests that fail. In particular, 'test_time' crashes the process entirely.
You can remove all tests, but it’s better to leave the first 7 — they run quickly and pass.

This lets you keep --pgo mode (enabled via --enable-optimizations) while still installing Python properly.

Yes, the build will repeat… and without the -j flag :sweat_smile:
But the resulting Python will be well optimized :wink:


:link: Symlinks

ln -sf $PREFIX/bin/python3.15 $PREFIX/bin/python
ln -sf $PREFIX/bin/pip3.15 $PREFIX/bin/pip


:white_check_mark: Final Check (Outside the CPython Repo)

python --version
pip --version

At the time of writing, I built Python 3.15.0a1 (Works for any version of python, can only change HAVE_*).

1 Like

You’re absolutely right that compiling Python in Termux is fragile and not officially supported. However, the package manager in Termux currently ships Python 3.12.9, which is significantly behind upstream CPython (e.g. 3.15.0a1). For users who need bleeding-edge features or want to test future releases, manual compilation becomes necessary — even if it’s tricky.

Regarding #define HAVE_CLOSE_RANGE=0:
This syntax is invalid in C. The correct form is:

#define HAVE_CLOSE_RANGE 0

That said, defining a macro to zero doesn’t prevent it from being picked up by #ifdef HAVE_CLOSE_RANGE blocks — which still evaluate as true. As I noted in my build notes, the only reliable way to disable such macros is to either comment out the line in pyconfig.h, or explicitly add:

#undef HAVE_CLOSE_RANGE

at the end of the file. This ensures the macro is truly undefined and avoids conditional compilation paths that rely on it.

In Termux, many syscalls like close_range, getlogin_r, getloadavg, etc. are unavailable or stubbed, and GCC/Clang headers may not expose them cleanly. You’ll often need to manually patch pyconfig.h to avoid linker errors. I’ve documented a working build of CPython 3.15 with --enable-optimizations and PGO, including which tests to disable and how to safely install without breaking the build.

1 Like