diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 54425e3..b6c8127 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,734 +1,63 @@ -name: Tests +name: CMake on: - workflow_dispatch: push: - branches: - - 'main' - - '3.*' + branches: [main, "3.*"] pull_request: - branches: - - 'main' - - '3.*' + branches: [main, "3.*"] + workflow_dispatch: permissions: contents: read -concurrency: - # https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#concurrency - # 'group' must be a key uniquely representing a PR or push event. - # github.workflow is the workflow name - # github.actor is the user invoking the workflow - # github.head_ref is the source branch of the PR or otherwise blank - # github.run_id is a unique number for the current run - group: ${{ github.workflow }}-${{ github.actor }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -env: - FORCE_COLOR: 1 - jobs: - build-context: - name: Change detection - # To use boolean outputs from this job, parse them as JSON. - # Here's some examples: - # - # if: fromJSON(needs.build-context.outputs.run-docs) - # - # ${{ - # fromJSON(needs.build-context.outputs.run-tests) - # && 'truthy-branch' - # || 'falsy-branch' - # }} - # - uses: ./.github/workflows/reusable-context.yml - - check-docs: - name: Docs - needs: build-context - if: fromJSON(needs.build-context.outputs.run-docs) - uses: ./.github/workflows/reusable-docs.yml - - check-abi: - name: 'Check if the ABI has changed' - runs-on: ubuntu-22.04 # 24.04 causes spurious errors - needs: build-context - if: needs.build-context.outputs.run-tests == 'true' - steps: - - uses: actions/checkout@v5 - with: - persist-credentials: false - - uses: actions/setup-python@v5 - with: - python-version: '3.x' - - name: Install dependencies - run: | - sudo ./.github/workflows/posix-deps-apt.sh - sudo apt-get install -yq abigail-tools - - name: Build CPython - env: - CFLAGS: -g3 -O0 - run: | - # Build Python with the libpython dynamic library - ./configure --enable-shared - make -j4 - - name: Check for changes in the ABI - id: check - run: | - if ! make check-abidump; then - echo "Generated ABI file is not up to date." - echo "Please add the release manager of this branch as a reviewer of this PR." - echo "" - echo "The up to date ABI file should be attached to this build as an artifact." - echo "" - echo "To learn more about this check: https://devguide.python.org/getting-started/setup-building/index.html#regenerate-the-abi-dump" - echo "" - exit 1 - fi - - name: Generate updated ABI files - if: ${{ failure() && steps.check.conclusion == 'failure' }} - run: | - make regen-abidump - - uses: actions/upload-artifact@v4 - name: Publish updated ABI files - if: ${{ failure() && steps.check.conclusion == 'failure' }} - with: - name: abi-data - path: ./Doc/data/*.abi - - check-autoconf-regen: - name: 'Check if Autoconf files are up to date' - # Don't use ubuntu-latest but a specific version to make the job - # reproducible: to get the same tools versions (autoconf, aclocal, ...) + build: runs-on: ubuntu-24.04 - container: - image: ghcr.io/python/autoconf:2025.01.02.12581854023 - timeout-minutes: 60 - needs: build-context - if: needs.build-context.outputs.run-tests == 'true' + defaults: + run: + shell: bash steps: - - name: Install Git - run: | - apt update && apt install git -yq - git config --global --add safe.directory "$GITHUB_WORKSPACE" - uses: actions/checkout@v5 - with: - fetch-depth: 1 - persist-credentials: false - - name: Check Autoconf and aclocal versions - run: | - grep "Generated by GNU Autoconf 2.72" configure - grep "aclocal 1.16.5" aclocal.m4 - grep -q "runstatedir" configure - grep -q "PKG_PROG_PKG_CONFIG" aclocal.m4 - - name: Regenerate autoconf files - # Same command used by Tools/build/regen-configure.sh ($AUTORECONF) - run: autoreconf -ivf -Werror - - name: Check for changes - run: | - git add -u - changes=$(git status --porcelain) - # Check for changes in regenerated files - if test -n "$changes"; then - echo "Generated files not up to date." - echo "Perhaps you forgot to run make regen-configure ;)" - echo "configure files must be regenerated with a specific version of autoconf." - echo "$changes" - echo "" - git diff --staged || true - exit 1 - fi - check-generated-files: - name: 'Check if generated files are up to date' - # Don't use ubuntu-latest but a specific version to make the job - # reproducible: to get the same tools versions (autoconf, aclocal, ...) - runs-on: ubuntu-24.04 - timeout-minutes: 60 - needs: build-context - if: needs.build-context.outputs.run-tests == 'true' - steps: - - uses: actions/checkout@v5 + - name: Set up Python + uses: actions/setup-python@v5 with: - persist-credentials: false - - uses: actions/setup-python@v5 - with: - python-version: '3.x' - - name: Runner image version - run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV" - - name: Restore config.cache + python-version: "3.12" + + - name: Install build tooling + run: | + python -m pip install --upgrade pip + python -m pip install "conan==2.5.0" + sudo apt-get update + sudo apt-get install -y ninja-build + + - name: Cache Conan downloads uses: actions/cache@v4 with: - path: config.cache - # Include env.pythonLocation in key to avoid changes in environment when setup-python updates Python - key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ needs.build-context.outputs.config-hash }}-${{ env.pythonLocation }} - - name: Install dependencies - run: sudo ./.github/workflows/posix-deps-apt.sh - - name: Add ccache to PATH - run: echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV" - - name: Configure ccache action - uses: hendrikmuhs/ccache-action@v1.2 - with: - save: false - - name: Configure CPython + path: ~/.conan2 + key: conan-${{ runner.os }}-${{ hashFiles('conanfile.txt') }} + restore-keys: | + conan-${{ runner.os }}- + + - name: Prepare Conan profile + run: conan profile detect --force + + - name: Install Conan toolchain + run: conan install . --output-folder=build --build=missing + + - name: Configure CMake (Ninja) run: | - # Build Python with the libpython dynamic library - ./configure --config-cache --with-pydebug --enable-shared - - name: Build CPython + source build/conanrun.sh + cmake -S . -B build -G Ninja \ + -DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake \ + -DCMAKE_BUILD_TYPE=Release + + - name: Build run: | - make -j4 regen-all - make regen-stdlib-module-names regen-sbom regen-unicodedata - - name: Check for changes + source build/conanrun.sh + cmake --build build --config Release + + - name: Test run: | - git add -u - changes=$(git status --porcelain) - # Check for changes in regenerated files - if test -n "$changes"; then - echo "Generated files not up to date." - echo "Perhaps you forgot to run make regen-all or build.bat --regen. ;)" - echo "configure files must be regenerated with a specific version of autoconf." - echo "$changes" - echo "" - git diff --staged || true - exit 1 - fi - - name: Check exported libpython symbols - run: make smelly - - name: Check limited ABI symbols - run: make check-limited-abi - - name: Check for unsupported C global variables - if: github.event_name == 'pull_request' # $GITHUB_EVENT_NAME - run: make check-c-globals - - build-windows: - name: >- - Windows - ${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }} - needs: build-context - if: fromJSON(needs.build-context.outputs.run-windows-tests) - strategy: - fail-fast: false - matrix: - arch: - - x64 - - Win32 - - arm64 - free-threading: - - false - - true - exclude: - # Skip Win32 on free-threaded builds - - { arch: Win32, free-threading: true } - uses: ./.github/workflows/reusable-windows.yml - with: - arch: ${{ matrix.arch }} - free-threading: ${{ matrix.free-threading }} - - build-windows-msi: - name: >- # ${{ '' } is a hack to nest jobs under the same sidebar category - Windows MSI${{ '' }} - needs: build-context - if: fromJSON(needs.build-context.outputs.run-windows-msi) - strategy: - fail-fast: false - matrix: - arch: - - x86 - - x64 - - arm64 - uses: ./.github/workflows/reusable-windows-msi.yml - with: - arch: ${{ matrix.arch }} - - build-macos: - name: >- - macOS - ${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }} - needs: build-context - if: needs.build-context.outputs.run-tests == 'true' - strategy: - fail-fast: false - matrix: - # Cirrus and macos-14 are M1, macos-13 is default GHA Intel. - # macOS 13 only runs tests against the GIL-enabled CPython. - # Cirrus used for upstream, macos-14 for forks. - os: - - ghcr.io/cirruslabs/macos-runner:sonoma - - macos-14 - - macos-13 - is-fork: # only used for the exclusion trick - - ${{ github.repository_owner != 'python' }} - free-threading: - - false - - true - exclude: - - os: ghcr.io/cirruslabs/macos-runner:sonoma - is-fork: true - - os: macos-14 - is-fork: false - - os: macos-13 - free-threading: true - uses: ./.github/workflows/reusable-macos.yml - with: - config_hash: ${{ needs.build-context.outputs.config-hash }} - free-threading: ${{ matrix.free-threading }} - os: ${{ matrix.os }} - - build-ubuntu: - name: >- - Ubuntu - ${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }} - ${{ fromJSON(matrix.bolt) && '(bolt)' || '' }} - needs: build-context - if: needs.build-context.outputs.run-tests == 'true' - strategy: - fail-fast: false - matrix: - bolt: - - false - - true - free-threading: - - false - - true - os: - - ubuntu-24.04 - - ubuntu-24.04-arm - exclude: - # Do not test BOLT with free-threading, to conserve resources - - bolt: true - free-threading: true - # BOLT currently crashes during instrumentation on aarch64 - - os: ubuntu-24.04-arm - bolt: true - uses: ./.github/workflows/reusable-ubuntu.yml - with: - config_hash: ${{ needs.build-context.outputs.config-hash }} - bolt-optimizations: ${{ matrix.bolt }} - free-threading: ${{ matrix.free-threading }} - os: ${{ matrix.os }} - - build-ubuntu-ssltests: - name: 'Ubuntu SSL tests with OpenSSL' - runs-on: ${{ matrix.os }} - timeout-minutes: 60 - needs: build-context - if: needs.build-context.outputs.run-tests == 'true' - strategy: - fail-fast: false - matrix: - os: [ubuntu-24.04] - openssl_ver: [3.0.16, 3.1.8, 3.2.4, 3.3.3, 3.4.1] - # See Tools/ssl/make_ssl_data.py for notes on adding a new version - env: - OPENSSL_VER: ${{ matrix.openssl_ver }} - MULTISSL_DIR: ${{ github.workspace }}/multissl - OPENSSL_DIR: ${{ github.workspace }}/multissl/openssl/${{ matrix.openssl_ver }} - LD_LIBRARY_PATH: ${{ github.workspace }}/multissl/openssl/${{ matrix.openssl_ver }}/lib - steps: - - uses: actions/checkout@v5 - with: - persist-credentials: false - - name: Runner image version - run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV" - - name: Restore config.cache - uses: actions/cache@v4 - with: - path: config.cache - key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ needs.build-context.outputs.config-hash }} - - name: Register gcc problem matcher - run: echo "::add-matcher::.github/problem-matchers/gcc.json" - - name: Install dependencies - run: sudo ./.github/workflows/posix-deps-apt.sh - - name: Configure OpenSSL env vars - run: | - echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> "$GITHUB_ENV" - echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> "$GITHUB_ENV" - echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> "$GITHUB_ENV" - - name: 'Restore OpenSSL build' - id: cache-openssl - uses: actions/cache@v4 - with: - path: ./multissl/openssl/${{ env.OPENSSL_VER }} - key: ${{ matrix.os }}-multissl-openssl-${{ env.OPENSSL_VER }} - - name: Install OpenSSL - if: steps.cache-openssl.outputs.cache-hit != 'true' - run: python3 Tools/ssl/multissltests.py --steps=library --base-directory "$MULTISSL_DIR" --openssl "$OPENSSL_VER" --system Linux - - name: Add ccache to PATH - run: | - echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV" - - name: Configure ccache action - uses: hendrikmuhs/ccache-action@v1.2 - with: - save: false - - name: Configure CPython - run: ./configure CFLAGS="-fdiagnostics-format=json" --config-cache --enable-slower-safety --with-pydebug --with-openssl="$OPENSSL_DIR" - - name: Build CPython - run: make -j4 - - name: Display build info - run: make pythoninfo - - name: SSL tests - run: ./python Lib/test/ssltests.py - - build-wasi: - name: 'WASI' - needs: build-context - if: needs.build-context.outputs.run-tests == 'true' - uses: ./.github/workflows/reusable-wasi.yml - with: - config_hash: ${{ needs.build-context.outputs.config-hash }} - - test-hypothesis: - name: "Hypothesis tests on Ubuntu" - runs-on: ubuntu-24.04 - timeout-minutes: 60 - needs: build-context - if: needs.build-context.outputs.run-tests == 'true' - env: - OPENSSL_VER: 3.0.16 - PYTHONSTRICTEXTENSIONBUILD: 1 - steps: - - uses: actions/checkout@v5 - with: - persist-credentials: false - - name: Register gcc problem matcher - run: echo "::add-matcher::.github/problem-matchers/gcc.json" - - name: Install dependencies - run: sudo ./.github/workflows/posix-deps-apt.sh - - name: Configure OpenSSL env vars - run: | - echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> "$GITHUB_ENV" - echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> "$GITHUB_ENV" - echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> "$GITHUB_ENV" - - name: 'Restore OpenSSL build' - id: cache-openssl - uses: actions/cache@v4 - with: - path: ./multissl/openssl/${{ env.OPENSSL_VER }} - key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }} - - name: Install OpenSSL - if: steps.cache-openssl.outputs.cache-hit != 'true' - run: python3 Tools/ssl/multissltests.py --steps=library --base-directory "$MULTISSL_DIR" --openssl "$OPENSSL_VER" --system Linux - - name: Add ccache to PATH - run: | - echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV" - - name: Configure ccache action - uses: hendrikmuhs/ccache-action@v1.2 - with: - save: false - - name: Setup directory envs for out-of-tree builds - run: | - echo "CPYTHON_RO_SRCDIR=$(realpath -m "${GITHUB_WORKSPACE}"/../cpython-ro-srcdir)" >> "$GITHUB_ENV" - echo "CPYTHON_BUILDDIR=$(realpath -m "${GITHUB_WORKSPACE}"/../cpython-builddir)" >> "$GITHUB_ENV" - - name: Create directories for read-only out-of-tree builds - run: mkdir -p "$CPYTHON_RO_SRCDIR" "$CPYTHON_BUILDDIR" - - name: Bind mount sources read-only - run: sudo mount --bind -o ro "$GITHUB_WORKSPACE" "$CPYTHON_RO_SRCDIR" - - name: Runner image version - run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV" - - name: Restore config.cache - uses: actions/cache@v4 - with: - path: ${{ env.CPYTHON_BUILDDIR }}/config.cache - key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ needs.build-context.outputs.config-hash }} - - name: Configure CPython out-of-tree - working-directory: ${{ env.CPYTHON_BUILDDIR }} - run: | - ../cpython-ro-srcdir/configure \ - --config-cache \ - --with-pydebug \ - --enable-slower-safety \ - --with-openssl="$OPENSSL_DIR" - - name: Build CPython out-of-tree - working-directory: ${{ env.CPYTHON_BUILDDIR }} - run: make -j4 - - name: Display build info - working-directory: ${{ env.CPYTHON_BUILDDIR }} - run: make pythoninfo - - name: Remount sources writable for tests - # some tests write to srcdir, lack of pyc files slows down testing - run: sudo mount "$CPYTHON_RO_SRCDIR" -oremount,rw - - name: Setup directory envs for out-of-tree builds - run: | - echo "CPYTHON_BUILDDIR=$(realpath -m "${GITHUB_WORKSPACE}"/../cpython-builddir)" >> "$GITHUB_ENV" - - name: "Create hypothesis venv" - working-directory: ${{ env.CPYTHON_BUILDDIR }} - run: | - VENV_LOC=$(realpath -m .)/hypovenv - VENV_PYTHON=$VENV_LOC/bin/python - echo "HYPOVENV=${VENV_LOC}" >> "$GITHUB_ENV" - echo "VENV_PYTHON=${VENV_PYTHON}" >> "$GITHUB_ENV" - ./python -m venv "$VENV_LOC" && "$VENV_PYTHON" -m pip install -r "${GITHUB_WORKSPACE}/Tools/requirements-hypothesis.txt" - - name: 'Restore Hypothesis database' - id: cache-hypothesis-database - uses: actions/cache@v4 - with: - path: ${{ env.CPYTHON_BUILDDIR }}/.hypothesis/ - key: hypothesis-database-${{ github.head_ref || github.run_id }} - restore-keys: | - hypothesis-database- - - name: "Run tests" - working-directory: ${{ env.CPYTHON_BUILDDIR }} - run: | - # Most of the excluded tests are slow test suites with no property tests - # - # (GH-104097) test_sysconfig is skipped because it has tests that are - # failing when executed from inside a virtual environment. - "${VENV_PYTHON}" -m test \ - -W \ - --slowest \ - -j4 \ - --timeout 900 \ - -x test_asyncio \ - -x test_multiprocessing_fork \ - -x test_multiprocessing_forkserver \ - -x test_multiprocessing_spawn \ - -x test_concurrent_futures \ - -x test_socket \ - -x test_subprocess \ - -x test_signal \ - -x test_sysconfig - - uses: actions/upload-artifact@v4 - if: always() - with: - name: hypothesis-example-db - path: ${{ env.CPYTHON_BUILDDIR }}/.hypothesis/examples/ - - build-asan: - name: 'Address sanitizer' - runs-on: ${{ matrix.os }} - timeout-minutes: 60 - needs: build-context - if: needs.build-context.outputs.run-tests == 'true' - strategy: - fail-fast: false - matrix: - os: [ubuntu-24.04] - env: - OPENSSL_VER: 3.0.16 - PYTHONSTRICTEXTENSIONBUILD: 1 - ASAN_OPTIONS: detect_leaks=0:allocator_may_return_null=1:handle_segv=0 - steps: - - uses: actions/checkout@v5 - with: - persist-credentials: false - - name: Runner image version - run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV" - - name: Restore config.cache - uses: actions/cache@v4 - with: - path: config.cache - key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ needs.build-context.outputs.config-hash }} - - name: Register gcc problem matcher - run: echo "::add-matcher::.github/problem-matchers/gcc.json" - - name: Install dependencies - run: sudo ./.github/workflows/posix-deps-apt.sh - - name: Set up GCC-10 for ASAN - uses: egor-tensin/setup-gcc@v1 - with: - version: 10 - - name: Configure OpenSSL env vars - run: | - echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> "$GITHUB_ENV" - echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> "$GITHUB_ENV" - echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> "$GITHUB_ENV" - - name: 'Restore OpenSSL build' - id: cache-openssl - uses: actions/cache@v4 - with: - path: ./multissl/openssl/${{ env.OPENSSL_VER }} - key: ${{ matrix.os }}-multissl-openssl-${{ env.OPENSSL_VER }} - - name: Install OpenSSL - if: steps.cache-openssl.outputs.cache-hit != 'true' - run: python3 Tools/ssl/multissltests.py --steps=library --base-directory "$MULTISSL_DIR" --openssl "$OPENSSL_VER" --system Linux - - name: Add ccache to PATH - run: | - echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV" - - name: Configure ccache action - uses: hendrikmuhs/ccache-action@v1.2 - with: - save: ${{ github.event_name == 'push' }} - max-size: "200M" - - name: Configure CPython - run: ./configure --config-cache --with-address-sanitizer --without-pymalloc - - name: Build CPython - run: make -j4 - - name: Display build info - run: make pythoninfo - - name: Tests - run: xvfb-run make ci - - build-san: - name: >- # ${{ '' } is a hack to nest jobs under the same sidebar category - Sanitizers${{ '' }} - needs: build-context - if: needs.build-context.outputs.run-tests == 'true' - strategy: - fail-fast: false - matrix: - check-name: - - Thread - free-threading: - - false - - true - sanitizer: - - TSan - include: - - check-name: Undefined behavior - sanitizer: UBSan - free-threading: false - uses: ./.github/workflows/reusable-san.yml - with: - sanitizer: ${{ matrix.sanitizer }} - config_hash: ${{ needs.build-context.outputs.config-hash }} - free-threading: ${{ matrix.free-threading }} - - cross-build-linux: - name: Cross build Linux - runs-on: ubuntu-latest - timeout-minutes: 60 - needs: build-context - if: needs.build-context.outputs.run-tests == 'true' - steps: - - uses: actions/checkout@v5 - with: - persist-credentials: false - - name: Runner image version - run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV" - - name: Restore config.cache - uses: actions/cache@v4 - with: - path: config.cache - key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ needs.build-context.outputs.config-hash }} - - name: Register gcc problem matcher - run: echo "::add-matcher::.github/problem-matchers/gcc.json" - - name: Set build dir - run: - # an absolute path outside of the working directoy - echo "BUILD_DIR=$(realpath ${{ github.workspace }}/../build)" >> "$GITHUB_ENV" - - name: Install dependencies - run: sudo ./.github/workflows/posix-deps-apt.sh - - name: Configure host build - run: ./configure --prefix="$BUILD_DIR/host-python" - - name: Install host Python - run: make -j8 install - - name: Run test subset with host build - run: | - "$BUILD_DIR/host-python/bin/python3" -m test test_sysconfig test_site test_embed - - name: Configure cross build - run: ./configure --prefix="$BUILD_DIR/cross-python" --with-build-python="$BUILD_DIR/host-python/bin/python3" - - name: Install cross Python - run: make -j8 install - - name: Run test subset with host build - run: | - "$BUILD_DIR/cross-python/bin/python3" -m test test_sysconfig test_site test_embed - - # CIFuzz job based on https://google.github.io/oss-fuzz/getting-started/continuous-integration/ - cifuzz: - name: CIFuzz - runs-on: ubuntu-latest - timeout-minutes: 60 - needs: build-context - if: needs.build-context.outputs.run-ci-fuzz == 'true' - permissions: - security-events: write - strategy: - fail-fast: false - matrix: - sanitizer: [address, undefined, memory] - steps: - - name: Build fuzzers (${{ matrix.sanitizer }}) - id: build - uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master - with: - oss-fuzz-project-name: cpython3 - sanitizer: ${{ matrix.sanitizer }} - - name: Run fuzzers (${{ matrix.sanitizer }}) - uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master - with: - fuzz-seconds: 600 - oss-fuzz-project-name: cpython3 - output-sarif: true - sanitizer: ${{ matrix.sanitizer }} - - name: Upload crash - if: failure() && steps.build.outcome == 'success' - uses: actions/upload-artifact@v4 - with: - name: ${{ matrix.sanitizer }}-artifacts - path: ./out/artifacts - - name: Upload SARIF - if: always() && steps.build.outcome == 'success' - uses: github/codeql-action/upload-sarif@v3 - with: - sarif_file: cifuzz-sarif/results.sarif - checkout_path: cifuzz-sarif - - all-required-green: # This job does nothing and is only used for the branch protection - name: All required checks pass - runs-on: ubuntu-latest - timeout-minutes: 5 - needs: - - build-context # Transitive dependency, needed to access `run-tests` value - - check-docs - - check-autoconf-regen - - check-generated-files - - build-windows - - build-windows-msi - - build-macos - - build-ubuntu - - build-ubuntu-ssltests - - build-wasi - - test-hypothesis - - build-asan - - build-san - - cross-build-linux - - cifuzz - if: always() - - steps: - - name: Check whether the needed jobs succeeded or failed - uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe - with: - allowed-failures: >- - build-windows-msi, - build-ubuntu-ssltests, - test-hypothesis, - cifuzz, - allowed-skips: >- - ${{ - !fromJSON(needs.build-context.outputs.run-docs) - && ' - check-docs, - ' - || '' - }} - ${{ - needs.build-context.outputs.run-tests != 'true' - && ' - check-autoconf-regen, - check-generated-files, - build-macos, - build-ubuntu, - build-ubuntu-ssltests, - build-wasi, - test-hypothesis, - build-asan, - build-san, - cross-build-linux, - ' - || '' - }} - ${{ - !fromJSON(needs.build-context.outputs.run-windows-tests) - && ' - build-windows, - ' - || '' - }} - ${{ - !fromJSON(needs.build-context.outputs.run-ci-fuzz) - && ' - cifuzz, - ' - || '' - }} - jobs: ${{ toJSON(needs) }} + source build/conanrun.sh + ctest --test-dir build --output-on-failure --build-config Release diff --git a/.gitignore b/.gitignore index d4a9700..97c3967 100644 --- a/.gitignore +++ b/.gitignore @@ -174,3 +174,8 @@ Python/frozen_modules/MANIFEST # People's custom https://docs.anthropic.com/en/docs/claude-code/memory configs. /.claude/ CLAUDE.local.md +# CMake/Conan build outputs +/build/ +CMakeUserPresets.json +CMakePresets.json +compile_commands.json diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..6205eb0 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,61 @@ +cmake_minimum_required(VERSION 3.22) + +project(Typthon VERSION 3.14.0 LANGUAGES C) + +# Allow using compilers provided by Conan if available +if(EXISTS "${CMAKE_BINARY_DIR}/conan_toolchain.cmake") + include("${CMAKE_BINARY_DIR}/conan_toolchain.cmake") +endif() + +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.h.in + ${CMAKE_CURRENT_BINARY_DIR}/generated/typthon/version.h + @ONLY +) + +add_library(typthon_core STATIC src/runtime.c) +target_include_directories( + typthon_core + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_BINARY_DIR}/generated +) +target_compile_features(typthon_core PUBLIC c_std_11) + +add_executable(typthon src/main.c) +target_link_libraries(typthon PRIVATE typthon_core) + +include(GNUInstallDirs) +install( + TARGETS typthon_core typthon + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) +install( + DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} +) +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/generated/typthon/version.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/typthon +) + +include(CTest) +if(BUILD_TESTING) + add_executable(typthon_smoketest tests/smoke.c) + target_include_directories( + typthon_smoketest + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_BINARY_DIR}/generated + ) + target_link_libraries(typthon_smoketest PRIVATE typthon_core) + + add_test(NAME typthon_cli COMMAND typthon --version) + add_test(NAME typthon_runtime_version COMMAND typthon_smoketest) +endif() diff --git a/cmake/version.h.in b/cmake/version.h.in new file mode 100644 index 0000000..4a7196a --- /dev/null +++ b/cmake/version.h.in @@ -0,0 +1,3 @@ +#pragma once + +#define TYPTHON_VERSION "@PROJECT_VERSION@" diff --git a/conanfile.txt b/conanfile.txt new file mode 100644 index 0000000..f99feb9 --- /dev/null +++ b/conanfile.txt @@ -0,0 +1,7 @@ +[tool_requires] +cmake/3.30.5 +ninja/1.12.1 + +[generators] +CMakeDeps +CMakeToolchain diff --git a/include/typthon/runtime.h b/include/typthon/runtime.h new file mode 100644 index 0000000..8b1a3cf --- /dev/null +++ b/include/typthon/runtime.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +const char *typthon_version(void); +void typthon_print_banner(FILE *output); + +#ifdef __cplusplus +} +#endif + diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..007a21f --- /dev/null +++ b/src/main.c @@ -0,0 +1,40 @@ +#include +#include +#include + +#include "typthon/runtime.h" +#include "typthon/version.h" + +static void print_usage(void) { + printf("Typthon %s\n", typthon_version()); + printf("usage: typthon [--version] [--help]\n"); + printf("This is a lightweight bootstrap for the Typthon runtime.\n"); +} + +int main(int argc, char **argv) { + bool show_help = false; + bool show_version = false; + + for (int i = 1; i < argc; ++i) { + if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { + show_help = true; + } else if (strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-V") == 0) { + show_version = true; + } else { + fprintf(stderr, "unknown option: %s\n", argv[i]); + return 1; + } + } + + if (show_help) { + print_usage(); + return 0; + } + + if (show_version || argc == 1) { + typthon_print_banner(stdout); + return 0; + } + + return 0; +} diff --git a/src/runtime.c b/src/runtime.c new file mode 100644 index 0000000..aa9f40c --- /dev/null +++ b/src/runtime.c @@ -0,0 +1,14 @@ +#include "typthon/runtime.h" +#include "typthon/version.h" + +const char *typthon_version(void) { + return TYPTHON_VERSION; +} + +void typthon_print_banner(FILE *output) { + if (output == NULL) { + return; + } + + fprintf(output, "Typthon %s\n", typthon_version()); +} diff --git a/tests/smoke.c b/tests/smoke.c new file mode 100644 index 0000000..88efc0e --- /dev/null +++ b/tests/smoke.c @@ -0,0 +1,16 @@ +#include +#include +#include + +#include "typthon/runtime.h" +#include "typthon/version.h" + +int main(void) { + const char *version = typthon_version(); + assert(version != NULL); + assert(strlen(version) > 0); + + printf("Typthon runtime version: %s\n", version); + typthon_print_banner(stdout); + return 0; +}