Home / Alt manpages / x86_64-linux-gnu-python3.12-config(1)

  • x86_64-linux-gnu-python3.12-config(1)
  • User command
  • linux

Use python3.12-config to Build Extensions and Embedded Python

x86_64-linux-gnu-python3.12-config hands you the exact compiler and linker flags for Python 3.12's development files. You will use it to build two small things: a loadable C extension and a program that embeds Python. The aliases python3.12-config and x86_64-linux-gnu-python3-config select the same installed configuration on this machine.

Allow 15 to 20 minutes if the development packages are already installed. You need a shell, a C compiler and the development packages, but no elevated privileges for the checks or examples below. Everything writes only to temporary files under /tmp; skip sudo unless your own source or destination directory is protected.

1. Confirm the interpreter and configuration script

The installed package set is Python 3.12.3, from python3.12-dev 3.12.3-1ubuntu0.17 and python3-dev 3.12.3-0ubuntu2.1. Check the command you actually intend to use rather than assuming an unqualified python3-config belongs to the system Python:

$ command -v x86_64-linux-gnu-python3.12-config
/usr/bin/x86_64-linux-gnu-python3.12-config
$ x86_64-linux-gnu-python3.12-config --help
Usage: /usr/bin/x86_64-linux-gnu-python3.12-config --prefix|--exec-prefix|--includes|--libs|--cflags|--ldflags|--extension-suffix|--help|--abiflags|--configdir|--embed

The local manual page lists only the traditional reporting options, while this installed script also accepts --configdir and --embed. That gap is version and packaging specific. Capture path and version together when a build must be reproducible:

$ python3.12 --version
Python 3.12.3
$ x86_64-linux-gnu-python3.12-config --configdir
/usr/lib/python3.12/config-3.12-x86_64-linux-gnu

Checkpoint

If command -v finds a different prefix, stop and inspect that installation before mixing its flags with /usr/bin/python3.12.

2. Inspect the flags before putting them in a build

  • --includes supplies header search paths.
  • --cflags adds the installed compiler settings on top of the includes.
  • --ldflags supplies library search paths and ordinary link libraries.
  • --libs prints just the library portion, without the search paths.
  • --extension-suffix gives the filename ending a binary extension needs.
$ x86_64-linux-gnu-python3.12-config --includes
-I/usr/include/python3.12 -I/usr/include/python3.12
$ x86_64-linux-gnu-python3.12-config --cflags
-I/usr/include/python3.12 -I/usr/include/python3.12  -fno-strict-overflow -Wsign-compare  -DNDEBUG -g -O2 -Wall
$ x86_64-linux-gnu-python3.12-config --ldflags
-L/usr/lib/python3.12/config-3.12-x86_64-linux-gnu -L/usr/lib/x86_64-linux-gnu  -ldl  -lm
$ x86_64-linux-gnu-python3.12-config --extension-suffix
.cpython-312-x86_64-linux-gnu.so

Do not hard-code these values as constants. The include directory, ABI suffix, library directory and optimisation flags can all shift with the Python build, architecture and distribution. Let command substitution fetch them at build time instead. The empty output from --abiflags here is normal for this Python 3.12 build.

Do not confuse --libs with what an embedding application actually needs. On this installation it prints -ldl -lm, whereas --embed adds the Python library itself to the link flags.

3. Build and import a small extension

A CPython extension is a shared library with an initialisation function named after the module. This example uses a module called check and writes the ABI-specific filename into /tmp. It reads from standard input, so there is no source file left to clean up:

$ printf '%s\n' \
    '#include <Python.h>' \
    'static struct PyModuleDef module = { PyModuleDef_HEAD_INIT, "check", 0, -1, 0 };' \
    'PyMODINIT_FUNC PyInit_check(void) { return PyModule_Create(&module); }' |
    gcc -x c - $(x86_64-linux-gnu-python3.12-config --cflags --ldflags) \
    -shared -fPIC \
    -o /tmp/check$(x86_64-linux-gnu-python3.12-config --extension-suffix)
$ python3.12 -c 'import sys; sys.path.insert(0, "/tmp"); import check; print(check.__name__)'
check

-shared and -fPIC are compiler choices for a loadable Unix shared object, python3.12-config will not add them for you. The filename matters too: Python looks for the module name followed by the right suffix, so using the reported suffix saves you guessing the ABI tag.

Checkpoint

An import error mentioning PyInit_check usually means the module name, initialisation function or output filename disagree with each other. An error for Python.h means the development headers are missing, or the flags came from a different Python install entirely.

Embedding flips the arrangement: your C program is the main executable, and it starts the Python runtime itself. Ask for --embed alongside the ordinary flags. The option only changes the library list, it does not initialise Python and grants no extra operating-system privilege:

$ printf '%s\n' \
    '#include <Python.h>' \
    'int main(void) { Py_Initialize(); Py_Finalize(); return 0; }' |
    gcc -x c - $(x86_64-linux-gnu-python3.12-config --cflags --embed --ldflags) \
    -o /tmp/python-embed-check
$ /tmp/python-embed-check
$ printf '%s\n' "$?"
0

Without --embed, the installed --ldflags output holds no -lpython3.12, so a program calling the Python C API can fail at link time with undefined references. That is deliberate: extension modules get loaded by an existing interpreter, while an embedded application has to link the interpreter library itself.

These examples leave two test binaries sitting in /tmp. Remove those exact files once you have finished testing, or keep them for inspection. Do not paper over a real project output with shell redirection or a guessed filename without checking first: redirection truncates an existing destination before compilation even starts.

5. Handle common failures without changing system state

  • No command found. Install or select the matching development package through your normal package-management process. Diagnosis here needs no sudo.
  • Headers found but linking fails. Compare command -v python3.12 with the configuration script path. Do not accidentally combine Homebrew or virtual-environment tooling with Debian or Ubuntu system flags.
  • The extension imports under another Python. Check python3.12 --version, python3.12 -c 'import sys; print(sys.executable)' and the reported suffix. Binary extensions are tied to the interpreter ABI and platform.
  • Only --libs was used for embedding. Rebuild with --embed --ldflags instead. Do not paper over missing symbols by bolting on arbitrary system libraries.
  • The command prints usage and exits non-zero. It received no option, or an unknown one. Check spelling against --help; status 1 is expected for that input.

Warning

The configuration command itself is read-only, but building can overwrite an output path, and running an embedded program can execute arbitrary Python code. Review source and destinations before adapting the example for a real project.

Done means

  • Resolved the right install. x86_64-linux-gnu-python3.12-config and python3.12 point at the installation you intended.
  • Pulled flags live. --cflags, --ldflags and --extension-suffix came from the installed tool, not from another machine.
  • Built the extension. A test extension compiled and imported as check.
  • Linked the embed. An embedding test linked with --embed and exited with status 0.
  • Cleaned up. Temporary binaries were reviewed and removed, or deliberately kept.