diff --git a/.github/get-py-env.py b/.github/get-py-env.py new file mode 100755 index 00000000..a6c41460 --- /dev/null +++ b/.github/get-py-env.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +# +# Determine info about the Python install and write shell code to stdout, to +# set env variables. This will set the variables PY_LDFLAGS, PY_CFLAGS and +# PY_INC_PATH. +# +# The python3-config tool is used as the source of this info. In theory we +# could use sysconfig as well but the setup-python action from github appears +# to patch python3-config but not patch the sysconfig info. +# +# Usage: +# eval $(python3 get-py-env.py) + +import os +import re +import subprocess + + +def get_output(cmd): + rv = subprocess.run( + cmd, + capture_output=True, # Capture stdout and stderr + text=True, # Decode output as text (UTF-8) + check=True, # Raise an error if the command fails + ) + return rv.stdout + + +def extract_flags(cmd, prefix): + flags = [] + for part in get_output(cmd).split(): + part = part.strip() + if part.startswith(prefix): + flags.append(part) + return ' '.join(flags) + + +def find_python_h(): + """Find the include path that has Python.h contained inside. + We could use INCLUDEPY from sysconfig but github patches + python3-config but not the sysconfig info (after moving the + install). + """ + c_flags = extract_flags(['python3-config', '--cflags'], '-I') + for part in c_flags.split(): + m = re.search(r'-I(\S+)', part) + if not m: + continue + inc_path = m.group(1) + if os.path.exists(os.path.join(inc_path, 'Python.h')): + return inc_path + raise SystemExit('cannot find Python.h') + + +def main(): + ld_flags = extract_flags(['python3-config', '--ldflags'], '-L') + c_flags = extract_flags(['python3-config', '--cflags'], '-I') + include_path = find_python_h() + print(f'PY_LDFLAGS="{ld_flags}"') + print(f'PY_CFLAGS="{c_flags}"') + print(f'PY_INC_PATH="{include_path}"') + + +if __name__ == '__main__': + main() diff --git a/.github/run-faber.sh b/.github/run-faber.sh new file mode 100755 index 00000000..5cb78be6 --- /dev/null +++ b/.github/run-faber.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +set -eu + +echo "cxx version: $CXX $($CXX --version)" +echo "cxx std: $CXX_STD" +echo "python3 path: $(which python3)" +echo "python3 version: $(python3 --version)" + +if ! which faber > /dev/null; then + echo "Installing faber..." + python3 -m pip install --upgrade pip + python3 -m pip install -U faber +fi +echo "faber version: $(faber -v)" + +# find and set PY_LDFLAGS and PY_INC_PATH +eval $(python3 .github/get-py-env.py) + +echo "PY_INC_PATH=$PY_INC_PATH" +echo "PY_LDFLAGS=$PY_LDFLAGS" + +case $(python3-config --abiflags) in + *t*) + # When running with free-threaded, we always want to disable the GIL + # even for extensions without the mod_gil_not_used() flag + export PYTHON_GIL=0 + ;; +esac + +# this could be set by LD_LIBRARY_PATH but faber overrides it +prefix=$(python3-config --prefix) +echo "${prefix}/lib" > /etc/ld.so.conf.d/boost-ci.conf && ldconfig + +sed -e "s/\$PYTHON/python3/g" .ci/faber > $HOME/.faber + +faber \ + --with-boost-include=${BOOST_PY_DEPS} \ + --builddir=build \ + cxx.name="${CXX}" \ + cxxflags="-std=${CXX_STD}" \ + cppflags="-std=${CXX_STD}" \ + include="${PY_INC_PATH}" \ + ldflags="${PY_LDFLAGS}" \ + -j`nproc` \ + "$@" diff --git a/.github/workflows/test-ubuntu.yml b/.github/workflows/test-ubuntu.yml index 6f94c2d1..f07ae75c 100644 --- a/.github/workflows/test-ubuntu.yml +++ b/.github/workflows/test-ubuntu.yml @@ -1,6 +1,10 @@ +# Test on Ubuntu with various compiler and language standard versions. name: Test Ubuntu -on: [push, pull_request] +on: + push: + pull_request: + workflow_dispatch: jobs: build: @@ -9,7 +13,7 @@ jobs: strategy: fail-fast: false matrix: - python: [python, python3] + python-version: ['3.14'] cxx: [g++, clang++] std: [c++11, c++14, c++17] include: @@ -27,31 +31,17 @@ jobs: steps: - uses: actions/checkout@v5 - + - name: setup python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} - name: setup prerequisites run: | - # Warning: this is not necessarily the same Python version as the one configured above ! - python3 -m pip install -U faber --break-system-packages + echo "CXX=${{ matrix.cxx }}" >> "$GITHUB_ENV" + echo "CXX_STD=${{ matrix.std }}" >> "$GITHUB_ENV" - name: build run: | - ${{ matrix.python }} --version - ${{ matrix.cxx }} --version - faber -v - sed -e "s/\$PYTHON/${{ matrix.python }}/g" .ci/faber > ~/.faber - faber \ - --with-boost-include=${BOOST_PY_DEPS} \ - --builddir=build \ - cxx.name=${{ matrix.cxx }} \ - cxxflags=-std=${{ matrix.std }} \ - cppflags=-std=${{ matrix.std }} \ - -j`nproc` + .github/run-faber.sh - name: test run: | - faber \ - --with-boost-include=${BOOST_PY_DEPS} \ - --builddir=build \ - cxx.name=${{ matrix.cxx }} \ - cxxflags=-std=${{ matrix.std }} \ - cppflags=-std=${{ matrix.std }} \ - -j`nproc` \ - test.report + .github/run-faber.sh test.report