diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 39cdd7de..11ac9ebc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,30 +2,159 @@ on: pull_request: merge_group: workflow_dispatch: + schedule: + # Run every night at 8am UTC + - cron: '0 8 * * SAT' name: cortex-m CI jobs: - ci-linux: - runs-on: ubuntu-latest - continue-on-error: ${{ matrix.experimental || false }} + # Test cortex-m + cortex-m-ci-linux: + runs-on: ubuntu-26.04 + continue-on-error: true strategy: matrix: - # All generated code should be running on stable now - rust: [stable] - test_cortex_m_types: [true] + rust: [nightly, stable, 1.85.0] + steps: + - uses: actions/checkout@v7 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.rust }} + - name: Run tests + run: cargo test --all --exclude cortex-m-rt --features cortex-m/critical-section-single-core - include: - # Test MSRV - - rust: 1.85.0 + # On x86_64-unknown-linux-gnu we can run our special testing shell script + cortex-m-rt-ci-linux: + runs-on: ubuntu-26.04 + continue-on-error: true + strategy: + matrix: + rust: [nightly, stable, 1.85.0] + defaults: + run: + working-directory: cortex-m-rt + steps: + - uses: actions/checkout@v7 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.rust }} + targets: thumbv6m-none-eabi,thumbv7m-none-eabi,thumbv7em-none-eabi,thumbv7em-none-eabihf,thumbv8m.base-none-eabi,thumbv8m.main-none-eabi,thumbv8m.main-none-eabihf + - name: Install qemu and gcc + run: sudo apt-get update && sudo apt-get install qemu-system-arm gcc-arm-none-eabi + - name: Run CI script for x86_64-unknown-linux-gnu under ${{ matrix.rust }} + run: TARGET=x86_64-unknown-linux-gnu CI_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh + - name: Run CI script for thumbv6m-none-eabi under ${{ matrix.rust }} + run: TARGET=thumbv6m-none-eabi CI_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh + - name: Run CI script for thumbv7m-none-eabi under ${{ matrix.rust }} + run: TARGET=thumbv7m-none-eabi CI_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh + - name: Run CI script for thumbv7em-none-eabi under ${{ matrix.rust }} + run: TARGET=thumbv7em-none-eabi CI_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh + - name: Run CI script for thumbv7em-none-eabihf under ${{ matrix.rust }} + run: TARGET=thumbv7em-none-eabihf CI_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh + - name: Run CI script for thumbv8m.base-none-eabi under ${{ matrix.rust }} + run: TARGET=thumbv8m.base-none-eabi CI_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh + - name: Run CI script for thumbv8m.main-none-eabi under ${{ matrix.rust }} + run: TARGET=thumbv8m.main-none-eabi CI_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh + - name: Run CI script for thumbv8m.main-none-eabihf under ${{ matrix.rust }} + run: TARGET=thumbv8m.main-none-eabihf CI_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh - # Test nightly but don't fail - - rust: nightly - experimental: true + # On macOS and Windows, we at least make sure that all examples build and link. + cortex-m-rt-ci-other-os: + strategy: + matrix: + os: [macOS-latest, windows-latest] + rust: [nightly, stable, 1.85.0] + runs-on: ${{ matrix.os }} + continue-on-error: true + defaults: + run: + working-directory: cortex-m-rt steps: - uses: actions/checkout@v7 - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.rust }} - - name: Run tests - run: cargo test --all --exclude cortex-m-rt --exclude testsuite --features cortex-m/critical-section-single-core + targets: thumbv6m-none-eabi,thumbv7m-none-eabi,thumbv7em-none-eabi,thumbv7em-none-eabihf,thumbv8m.base-none-eabi,thumbv8m.main-none-eabi,thumbv8m.main-none-eabihf + - name: Remove examples that pass by failing + run: rm examples/data_overflow.rs + - name: Build examples for thumbv6m-none-eabi + run: cargo build --target=thumbv6m-none-eabi --examples + - name: Build examples for thumbv7m-none-eabi + run: cargo build --target=thumbv7m-none-eabi --examples + - name: Build examples for thumbv7em-none-eabi + run: cargo build --target=thumbv7em-none-eabi --examples + - name: Build examples for thumbv7em-none-eabihf + run: cargo build --target=thumbv7em-none-eabihf --examples + - name: Build examples for thumbv8m.base-none-eabi + run: cargo build --target=thumbv8m.base-none-eabi --examples + - name: Build examples for thumbv8m.main-none-eabi + run: cargo build --target=thumbv8m.main-none-eabi --examples + - name: Build examples for thumbv8m.main-none-eabihf + run: cargo build --target=thumbv8m.main-none-eabihf --examples + - name: Build crate for host OS + run: cargo build + + # Run examples in QEMU + cortex-m-testsuite: + runs-on: ubuntu-26.04 + continue-on-error: true + strategy: + matrix: + rust: [nightly, stable, 1.85.0] + steps: + - uses: actions/checkout@v7 + - name: Install qemu-run + uses: taiki-e/cache-cargo-install-action@v3 + with: + tool: qemu-run + - name: Install qemu + run: sudo apt-get update && sudo apt-get install qemu-system-arm + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.rust }} + targets: thumbv6m-none-eabi,thumbv7m-none-eabi,thumbv7em-none-eabi,thumbv7em-none-eabihf,thumbv8m.base-none-eabi,thumbv8m.main-none-eabi,thumbv8m.main-none-eabihf + - name: Run testsuite for thumbv8m.main-none-eabihf + run: | + cd testsuite && cargo test --features qemu --target thumbv8m.main-none-eabihf + - name: Run testsuite for thumbv8m.main-none-eabi + run: | + cd testsuite && cargo test --features qemu --target thumbv8m.main-none-eabi + - name: Run testsuite for thumbv8m.base-none-eabi + run: | + cd testsuite && cargo test --features qemu --target thumbv8m.base-none-eabi + - name: Run testsuite for thumbv7em-none-eabi + run: | + cd testsuite && cargo test --features qemu --target thumbv7em-none-eabi + - name: Run testsuite for thumbv7em-none-eabihf + run: | + cd testsuite && cargo test --features qemu --target thumbv7em-none-eabihf + - name: Run testsuite for thumbv7m-none-eabi + run: | + cd testsuite && cargo test --features qemu --target thumbv7m-none-eabi + - name: Run testsuite for thumbv6m-none-eabi + run: | + cd testsuite && cargo test --features qemu --target thumbv6m-none-eabi + + report-issues: + runs-on: ubuntu-26.04 + if: always() + needs: [cortex-m-ci-linux, cortex-m-rt-ci-other-os, cortex-m-rt-ci-linux, cortex-m-testsuite] + steps: + - name: Ensure all required jobs succeed + run: | + echo "Our needs:" + echo '${{ toJSON(needs) }}' + echo "Checking..." + echo '${{ toJSON(needs) }}' | jq -e 'to_entries | all(.value.result == "success")' + - uses: imjohnbo/issue-bot@v3 + if: failure() && github.event_name == 'schedule' + with: + title: CI Failure + labels: ci + body: | + Scheduled CI run failed. Details: + + https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index 036a01c8..526f5f27 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -3,18 +3,41 @@ on: merge_group: workflow_dispatch: -name: Clippy check +name: Clippy + jobs: - clippy: - runs-on: ubuntu-latest + clippy-host: + runs-on: ubuntu-26.04 steps: - uses: actions/checkout@v7 - uses: dtolnay/rust-toolchain@1.85 with: components: clippy - run: cargo clippy --all --features cortex-m/critical-section-single-core -- -D warnings + clippy-target: + runs-on: ubuntu-26.04 + continue-on-error: true + strategy: + matrix: + target: + - thumbv6m-none-eabi + - thumbv7m-none-eabi + - thumbv7em-none-eabi + - thumbv7em-none-eabihf + - thumbv8m.base-none-eabi + - thumbv8m.main-none-eabi + - thumbv8m.main-none-eabihf + steps: + - uses: actions/checkout@v7 - uses: dtolnay/rust-toolchain@1.85 with: components: clippy - targets: thumbv7em-none-eabihf - - run: cd testsuite && cargo clippy --features qemu -- -D warnings + targets: ${{ matrix.target }} + - run: cd cortex-m && cargo clippy --target ${{ matrix.target }} --features critical-section-single-core -- -D warnings + - run: cd cortex-m-rt && cargo clippy --target ${{ matrix.target }} -- -D warnings + - run: cd testsuite && cargo clippy --target ${{ matrix.target }} --features qemu -- -D warnings + - run: cd testsuite && cargo clippy --target ${{ matrix.target }} --features hardware -- -D warnings + - run: cd cortex-m-semihosting && cargo clippy --target ${{ matrix.target }} -- -D warnings + - run: cd panic-semihosting && cargo clippy --target ${{ matrix.target }} -- -D warnings + - if: ${{ matrix.target != 'thumbv6m-none-eabi' && matrix.target != 'thumbv8m.base-none-eabi' }} + run: cd panic-itm && cargo clippy --target ${{ matrix.target }} -- -D warnings diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml deleted file mode 100644 index 436ba372..00000000 --- a/.github/workflows/cron.yml +++ /dev/null @@ -1,68 +0,0 @@ -on: - schedule: - # Run every week at 8am UTC Saturday. - - cron: '0 8 * * SAT' - workflow_dispatch: - -name: Cron CI - -jobs: - ci-linux: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v7 - - uses: dtolnay/rust-toolchain@stable - - name: Run tests - run: cargo test --all --exclude cortex-m-rt --exclude testsuite - - uses: imjohnbo/issue-bot@v3 - if: failure() - with: - title: CI Failure - labels: ci - body: | - Scheduled CI run failed. Details: - - https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - rt-ci-linux: - runs-on: ubuntu-latest - continue-on-error: ${{ matrix.experimental || false }} - defaults: - run: - working-directory: cortex-m-rt - steps: - - uses: actions/checkout@v7 - - uses: dtolnay/rust-toolchain@stable - - name: Install all Rust targets for stable - run: rustup target install --toolchain=stable thumbv6m-none-eabi thumbv7m-none-eabi thumbv7em-none-eabi thumbv7em-none-eabihf thumbv8m.base-none-eabi thumbv8m.main-none-eabi thumbv8m.main-none-eabihf - - name: Install qemu and gcc - run: sudo apt-get update && sudo apt-get install qemu-system-arm gcc-arm-none-eabi - - name: Run CI script for x86_64-unknown-linux-gnu under stable - run: TARGET=x86_64-unknown-linux-gnu TRAVIS_RUST_VERSION=stable bash ci/script.sh - - name: Run CI script for thumbv6m-none-eabi under stable - run: TARGET=thumbv6m-none-eabi TRAVIS_RUST_VERSION=stable bash ci/script.sh - - name: Run CI script for thumbv7m-none-eabi under stable - run: TARGET=thumbv7m-none-eabi TRAVIS_RUST_VERSION=stable bash ci/script.sh - - name: Run CI script for thumbv7em-none-eabi under stable - run: TARGET=thumbv7em-none-eabi TRAVIS_RUST_VERSION=stable bash ci/script.sh - - name: Run CI script for thumbv7em-none-eabihf under stable - run: TARGET=thumbv7em-none-eabihf TRAVIS_RUST_VERSION=stable bash ci/script.sh - - name: Run CI script for thumbv8m.base-none-eabi under stable - run: TARGET=thumbv8m.base-none-eabi TRAVIS_RUST_VERSION=stable bash ci/script.sh - - name: Run CI script for thumbv8m.main-none-eabi under stable - run: TARGET=thumbv8m.main-none-eabi TRAVIS_RUST_VERSION=stable bash ci/script.sh - - name: Run CI script for thumbv8m.main-none-eabihf under stable - run: TARGET=thumbv8m.main-none-eabihf TRAVIS_RUST_VERSION=stable bash ci/script.sh - - uses: imjohnbo/issue-bot@v3 - if: failure() - with: - title: CI Failure - labels: ci - body: | - Scheduled CI run failed. Details: - - https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/on-target.yml b/.github/workflows/on-target.yml deleted file mode 100644 index 90aa552a..00000000 --- a/.github/workflows/on-target.yml +++ /dev/null @@ -1,36 +0,0 @@ -on: - pull_request: - merge_group: - # allows manual triggering - workflow_dispatch: - -name: cortex-m on-target tests - -jobs: - - hil-qemu: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v7 - - name: Install qemu-run - uses: taiki-e/cache-cargo-install-action@v3 - with: - tool: qemu-run - - name: Install QEMU Dependencies - run: | - sudo apt-get -y update - sudo apt-get -y install libpixman-1-0 libfdt1 libglib2.0-0t64 - - name: Install custom QEMU into /opt - run: | - curl -sSL https://github.com/jonathanpallant/qemu9-for-ubuntu-2404/releases/download/qemu-9.2.3%2Bbuild0/qemu-9.2.3-ubuntu-24.04.tar.gz | sudo tar xvzf - -C / - echo "/opt/qemu/bin" >> "$GITHUB_PATH" - - name: Install toolchains - uses: dtolnay/rust-toolchain@stable - with: - targets: thumbv7em-none-eabihf, thumbv6m-none-eabi - - name: Run testsuite Cortex-M3 - run: | - cd testsuite && cargo test --features qemu --target thumbv7em-none-eabihf - - name: Run testsuite Cortex-M0 - run: | - cd testsuite && cargo test --features qemu --target thumbv6m-none-eabi diff --git a/.github/workflows/rt-ci.yml b/.github/workflows/rt-ci.yml deleted file mode 100644 index 176edb74..00000000 --- a/.github/workflows/rt-ci.yml +++ /dev/null @@ -1,82 +0,0 @@ -on: - pull_request: - merge_group: - workflow_dispatch: - -name: cortex-m-rt CI - -jobs: - rt-ci-linux: - runs-on: ubuntu-latest - continue-on-error: ${{ matrix.experimental || false }} - strategy: - matrix: - rust: [nightly, stable, 1.85.0] - - include: - # Nightly is only for reference and allowed to fail - - rust: nightly - experimental: true - defaults: - run: - working-directory: cortex-m-rt - steps: - - uses: actions/checkout@v7 - - uses: dtolnay/rust-toolchain@master - with: - toolchain: ${{ matrix.rust }} - - name: Install all Rust targets for ${{ matrix.rust }} - run: rustup target install --toolchain=${{ matrix.rust }} thumbv6m-none-eabi thumbv7m-none-eabi thumbv7em-none-eabi thumbv7em-none-eabihf thumbv8m.base-none-eabi thumbv8m.main-none-eabi thumbv8m.main-none-eabihf - - name: Install qemu and gcc - run: sudo apt-get update && sudo apt-get install qemu-system-arm gcc-arm-none-eabi - - name: Run CI script for x86_64-unknown-linux-gnu under ${{ matrix.rust }} - run: TARGET=x86_64-unknown-linux-gnu TRAVIS_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh - - name: Run CI script for thumbv6m-none-eabi under ${{ matrix.rust }} - run: TARGET=thumbv6m-none-eabi TRAVIS_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh - - name: Run CI script for thumbv7m-none-eabi under ${{ matrix.rust }} - run: TARGET=thumbv7m-none-eabi TRAVIS_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh - - name: Run CI script for thumbv7em-none-eabi under ${{ matrix.rust }} - run: TARGET=thumbv7em-none-eabi TRAVIS_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh - - name: Run CI script for thumbv7em-none-eabihf under ${{ matrix.rust }} - run: TARGET=thumbv7em-none-eabihf TRAVIS_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh - - name: Run CI script for thumbv8m.base-none-eabi under ${{ matrix.rust }} - run: TARGET=thumbv8m.base-none-eabi TRAVIS_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh - - name: Run CI script for thumbv8m.main-none-eabi under ${{ matrix.rust }} - run: TARGET=thumbv8m.main-none-eabi TRAVIS_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh - - name: Run CI script for thumbv8m.main-none-eabihf under ${{ matrix.rust }} - run: TARGET=thumbv8m.main-none-eabihf TRAVIS_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh - - # On macOS and Windows, we at least make sure that all examples build and link. - rt-ci-other-os: - strategy: - matrix: - os: - - macOS-latest - - windows-latest - runs-on: ${{ matrix.os }} - defaults: - run: - working-directory: cortex-m-rt - steps: - - uses: actions/checkout@v7 - - uses: dtolnay/rust-toolchain@stable - - name: Install all Rust targets - run: rustup target install thumbv6m-none-eabi thumbv7m-none-eabi thumbv7em-none-eabi thumbv7em-none-eabihf thumbv8m.base-none-eabi thumbv8m.main-none-eabi thumbv8m.main-none-eabihf - - name: Remove examples that pass by failing - run: rm examples/data_overflow.rs - - name: Build examples for thumbv6m-none-eabi - run: cargo build --target=thumbv6m-none-eabi --examples - - name: Build examples for thumbv7m-none-eabi - run: cargo build --target=thumbv7m-none-eabi --examples - - name: Build examples for thumbv7em-none-eabi - run: cargo build --target=thumbv7em-none-eabi --examples - - name: Build examples for thumbv7em-none-eabihf - run: cargo build --target=thumbv7em-none-eabihf --examples - - name: Build examples for thumbv8m.base-none-eabi - run: cargo build --target=thumbv8m.base-none-eabi --examples - - name: Build examples for thumbv8m.main-none-eabi - run: cargo build --target=thumbv8m.main-none-eabi --examples - - name: Build examples for thumbv8m.main-none-eabihf - run: cargo build --target=thumbv8m.main-none-eabihf --examples - - name: Build crate for host OS - run: cargo build diff --git a/.github/workflows/rustfmt.yml b/.github/workflows/rustfmt.yml index 25acbf20..4a2534c4 100644 --- a/.github/workflows/rustfmt.yml +++ b/.github/workflows/rustfmt.yml @@ -6,12 +6,12 @@ on: name: Code formatting check jobs: - fmt: - name: rustfmt - runs-on: ubuntu-latest + rustfmt: + runs-on: ubuntu-26.04 steps: - uses: actions/checkout@v7 - uses: dtolnay/rust-toolchain@stable with: components: rustfmt - run: cargo fmt --all -- --check + - run: cd testsuite && cargo fmt --all -- --check diff --git a/cortex-m-rt/ci/script.sh b/cortex-m-rt/ci/script.sh index b78e0f01..416603cd 100755 --- a/cortex-m-rt/ci/script.sh +++ b/cortex-m-rt/ci/script.sh @@ -2,18 +2,17 @@ set -euxo pipefail -main() { - cargo check --target "$TARGET" +CARGO="cargo +${CI_RUST_VERSION}" - cargo check --target "$TARGET" --features device +main() { + $CARGO check --target "$TARGET" - # A `critical_section` implementation is always needed. - needed_features= + $CARGO check --target "$TARGET" --features device - if [ "$TARGET" = x86_64-unknown-linux-gnu ] && [ "$TRAVIS_RUST_VERSION" = stable ]; then - ( cd macros && cargo check && cargo test ) + if [ "$TARGET" = x86_64-unknown-linux-gnu ] && [ "$CI_RUST_VERSION" = stable ]; then + ( cd macros && $CARGO check && $CARGO test ) - cargo test --features "device,${needed_features}" --test compiletest + $CARGO test --features "device" --test compiletest fi local examples=( @@ -46,38 +45,36 @@ main() { ) if [ "$TARGET" != x86_64-unknown-linux-gnu ]; then # Only test on stable and nightly, not MSRV. - if [ "$TRAVIS_RUST_VERSION" = stable ] || [ "$TRAVIS_RUST_VERSION" = nightly ]; then - RUSTDOCFLAGS="-Cpanic=abort" cargo test --features "${needed_features}" --doc + if [ "$CI_RUST_VERSION" = stable ] || [ "$CI_RUST_VERSION" = nightly ]; then + RUSTDOCFLAGS="-Cpanic=abort" $CARGO test --doc fi for linker in "${linkers[@]}"; do for ex in "${examples[@]}"; do - cargo rustc --target "$TARGET" --example "$ex" --features "${needed_features}" -- $linker - cargo rustc --target "$TARGET" --example "$ex" --features "${needed_features}" --release -- $linker + $CARGO rustc --target "$TARGET" --example "$ex" -- $linker + $CARGO rustc --target "$TARGET" --example "$ex" --release -- $linker done for ex in "${fail_examples[@]}"; do - cargo rustc --target "$TARGET" --example "$ex" --features "${needed_features}" -- $linker && exit 1 - cargo rustc --target "$TARGET" --example "$ex" --features "${needed_features}" --release -- $linker && exit 1 + $CARGO rustc --target "$TARGET" --example "$ex" -- $linker && exit 1 + $CARGO rustc --target "$TARGET" --example "$ex" --release -- $linker && exit 1 done - cargo rustc --target "$TARGET" --example device --features "device,${needed_features}" -- $linker - cargo rustc --target "$TARGET" --example device --features "device,${needed_features}" --release -- $linker + $CARGO rustc --target "$TARGET" --example device --features "device" -- $linker + $CARGO rustc --target "$TARGET" --example device --features "device" --release -- $linker - cargo rustc --target "$TARGET" --example minimal --features "set-sp,${needed_features}" -- $linker - cargo rustc --target "$TARGET" --example minimal --features "set-sp,${needed_features}" --release -- $linker - cargo rustc --target "$TARGET" --example minimal --features "zero-init-ram,${needed_features}" -- $linker - cargo rustc --target "$TARGET" --example minimal --features "zero-init-ram,${needed_features}" --release -- $linker - cargo rustc --target "$TARGET" --example minimal --features "set-vtor,${needed_features}" -- $linker - cargo rustc --target "$TARGET" --example minimal --features "set-vtor,${needed_features}" --release -- $linker + $CARGO rustc --target "$TARGET" --example minimal --features "set-sp" -- $linker + $CARGO rustc --target "$TARGET" --example minimal --features "set-sp" --release -- $linker + $CARGO rustc --target "$TARGET" --example minimal --features "zero-init-ram" -- $linker + $CARGO rustc --target "$TARGET" --example minimal --features "zero-init-ram" --release -- $linker + $CARGO rustc --target "$TARGET" --example minimal --features "set-vtor" -- $linker + $CARGO rustc --target "$TARGET" --example minimal --features "set-vtor" --release -- $linker done fi case $TARGET in thumbv6m-none-eabi|thumbv7m-none-eabi) for linker in "${linkers[@]}"; do - env RUSTFLAGS="$linker -C link-arg=-Tlink.x" cargo run \ - --target "$TARGET" --features "${needed_features}" --example qemu | grep "x = 42" - env RUSTFLAGS="$linker -C link-arg=-Tlink.x" cargo run \ - --target "$TARGET" --features "${needed_features}" --example qemu --release | grep "x = 42" + env RUSTFLAGS="$linker -C link-arg=-Tlink.x" $CARGO run --target "$TARGET" --example qemu | grep "x = 42" + env RUSTFLAGS="$linker -C link-arg=-Tlink.x" $CARGO run --target "$TARGET" --example qemu --release | grep "x = 42" done ;; diff --git a/justfile b/justfile index 0659b1e7..cd9882c7 100644 --- a/justfile +++ b/justfile @@ -1,7 +1,98 @@ +all: testsuite unit-test clippy clippy-test fmt-check + +testsuite: testsuite-thumbv8m-main-none-eabihf testsuite-thumbv8m-main-none-eabi testsuite-thumbv8m-base-none-eabi testsuite-thumbv7em-none-eabihf testsuite-thumbv7em-none-eabi testsuite-thumbv7m-none-eabi testsuite-thumbv6m-none-eabi + +# Run the on-target testsuite on QEMU on thumbv8m.main-none-eabihf +[working-directory: "testsuite"] +testsuite-thumbv8m-main-none-eabihf: + cargo test --features qemu --target thumbv8m.main-none-eabihf --release + +# Run the on-target testsuite on QEMU on thumbv8m.main-none-eabi +[working-directory: "testsuite"] +testsuite-thumbv8m-main-none-eabi: + cargo test --features qemu --target thumbv8m.main-none-eabi --release + +# Run the on-target testsuite on QEMU on thumbv8m.base-none-eabi +[working-directory: "testsuite"] +testsuite-thumbv8m-base-none-eabi: + cargo test --features qemu --target thumbv8m.base-none-eabi --release + +# Run the on-target testsuite on QEMU on thumbv7em-none-eabihf +[working-directory: "testsuite"] +testsuite-thumbv7em-none-eabihf: + cargo test --features qemu --target thumbv7em-none-eabihf --release + +# Run the on-target testsuite on QEMU on thumbv7em-none-eabi +[working-directory: "testsuite"] +testsuite-thumbv7em-none-eabi: + cargo test --features qemu --target thumbv7em-none-eabi --release + +# Run the on-target testsuite on QEMU on thumbv7m-none-eabi [working-directory: "testsuite"] -run-cortex-m3-test: - cargo test --features qemu --target thumbv7em-none-eabihf +testsuite-thumbv7m-none-eabi: + cargo test --features qemu --target thumbv7m-none-eabi --release +# Run the on-target testsuite on QEMU on thumbv6m-none-eabi [working-directory: "testsuite"] -run-cortex-m0-test: +testsuite-thumbv6m-none-eabi: cargo test --features qemu --target thumbv6m-none-eabi --release + +# cortex-m-rt build tests +build-tests: build-test-nightly build-test-stable build-test-msrv + +build-test-nightly: \ + (build-test "thumbv6m-none-eabi" "nightly") \ + (build-test "thumbv7m-none-eabi" "nightly") \ + (build-test "thumbv7em-none-eabi" "nightly") \ + (build-test "thumbv7em-none-eabihf" "nightly") \ + (build-test "thumbv8m.base-none-eabi" "nightly") \ + (build-test "thumbv8m.main-none-eabi" "nightly") \ + (build-test "thumbv8m.main-none-eabihf" "nightly") \ + (build-test "x86_64-unknown-linux-gnu" "nightly") \ + +build-test-stable: \ + (build-test "thumbv6m-none-eabi" "stable") \ + (build-test "thumbv7m-none-eabi" "stable") \ + (build-test "thumbv7em-none-eabi" "stable") \ + (build-test "thumbv7em-none-eabihf" "stable") \ + (build-test "thumbv8m.base-none-eabi" "stable") \ + (build-test "thumbv8m.main-none-eabi" "stable") \ + (build-test "thumbv8m.main-none-eabihf" "stable") \ + (build-test "x86_64-unknown-linux-gnu" "stable") \ + +build-test-msrv: \ + (build-test "thumbv6m-none-eabi" "1.85") \ + (build-test "thumbv7m-none-eabi" "1.85") \ + (build-test "thumbv7em-none-eabi" "1.85") \ + (build-test "thumbv7em-none-eabihf" "1.85") \ + (build-test "thumbv8m.base-none-eabi" "1.85") \ + (build-test "thumbv8m.main-none-eabi" "1.85") \ + (build-test "thumbv8m.main-none-eabihf" "1.85") \ + (build-test "x86_64-unknown-linux-gnu" "1.85") \ + +[working-directory: "cortex-m-rt"] +build-test target rust-version: + TARGET={{target}} CI_RUST_VERSION={{rust-version}} bash ci/script.sh + +# Run the unit tests +unit-test: + cargo test --all --exclude cortex-m-rt --features cortex-m/critical-section-single-core + +# Run clippy on the testsuite +[working-directory: "testsuite"] +clippy-test: + cargo clippy --features qemu -- -D warnings + +# Run clippy on the workspace +clippy: + cargo clippy --all --features cortex-m/critical-section-single-core -- -D warnings + +# Format all the code (the workspace and the testsuite) +fmt: + cargo fmt --all + cd testsuite && cargo fmt --all + +# Check if the code is formatted correctly (the workspace and the testsuite) +fmt-check: + cargo fmt --all -- --check + cd testsuite && cargo fmt --all -- --check diff --git a/testsuite/.cargo/config.toml b/testsuite/.cargo/config.toml index 4be2b8c6..96ead0a1 100644 --- a/testsuite/.cargo/config.toml +++ b/testsuite/.cargo/config.toml @@ -5,7 +5,23 @@ rustflags = [ "-C", "link-arg=-Tdefmt.x", ] +[target.thumbv8m.base-none-eabi] +# We don't have a Cortex-M23 machine, but this should work +runner = "qemu-run --machine mps2-an505 --cpu cortex-m33" + +[target.thumbv8m.main-none-eabi] +runner = "qemu-run --machine mps2-an505 --cpu cortex-m33" + +[target.thumbv8m.main-none-eabihf] +runner = "qemu-run --machine mps2-an505 --cpu cortex-m33" + [target.thumbv7em-none-eabihf] +runner = "qemu-run --machine lm3s6965evb --cpu cortex-m4" + +[target.thumbv7em-none-eabi] +runner = "qemu-run --machine lm3s6965evb --cpu cortex-m4" + +[target.thumbv7m-none-eabi] runner = "qemu-run --machine lm3s6965evb --cpu cortex-m3" [target.thumbv6m-none-eabi] diff --git a/testsuite/Cargo.toml b/testsuite/Cargo.toml index 83ceb07c..6b628223 100644 --- a/testsuite/Cargo.toml +++ b/testsuite/Cargo.toml @@ -23,6 +23,9 @@ defmt = "1" [dev-dependencies] defmt-test = "0.4" +[build-dependencies] +arm-targets = "0.4.2" + # for the library crate (src/lib.rs) [lib] harness = false @@ -39,3 +42,4 @@ cortex-m-rt = { path = "../cortex-m-rt" } opt-level = "z" # Optimize for size lto = true # Enable Link Time Optimization codegen-units = 1 # Better optimization at cost of compile time +debug = 2 diff --git a/testsuite/build.rs b/testsuite/build.rs index 3d65b52a..d034aeed 100644 --- a/testsuite/build.rs +++ b/testsuite/build.rs @@ -1,66 +1,22 @@ +use arm_targets::Arch; use std::{env, path::PathBuf}; -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum MemorySelect { - CortexM0, - CortexM3, -} fn main() { - let target = std::env::var("TARGET").unwrap(); - - println!("cargo:rustc-check-cfg=cfg(armv6m)"); - println!("cargo:rustc-check-cfg=cfg(armv7m)"); - println!("cargo:rustc-check-cfg=cfg(armv7em)"); - println!("cargo:rustc-check-cfg=cfg(armv8m)"); - println!("cargo:rustc-check-cfg=cfg(armv8m_base)"); - println!("cargo:rustc-check-cfg=cfg(armv8m_main)"); - - let mut memory_select = None; - if target.starts_with("thumbv6m-") { - memory_select = Some(MemorySelect::CortexM0); - println!("cargo:rustc-cfg=armv6m"); - } else if target.starts_with("thumbv7m-") { - memory_select = Some(MemorySelect::CortexM3); - println!("cargo:rustc-cfg=armv7m"); - } else if target.starts_with("thumbv7em-") { - memory_select = Some(MemorySelect::CortexM3); - println!("cargo:rustc-cfg=armv7m"); - println!("cargo:rustc-cfg=armv7em"); // (not currently used) - } else if target.starts_with("thumbv8m.base") { - println!("cargo:rustc-cfg=armv8m"); - println!("cargo:rustc-cfg=armv8m_base"); - } else if target.starts_with("thumbv8m.main") { - println!("cargo:rustc-cfg=armv8m"); - println!("cargo:rustc-cfg=armv8m_main"); - } + let target_info = arm_targets::process(); let out = PathBuf::from(env::var_os("OUT_DIR").unwrap()); - let memory_x_file = match memory_select { - Some(MemorySelect::CortexM0) => { - // Put `memory.x` in our output directory and ensure it's - // on the linker search path. - "memory_microbit.x" - } - Some(MemorySelect::CortexM3) => { - // Put `memory.x` in our output directory and ensure it's - // on the linker search path. - "memory_m3.x" - } - // TODO: Copy memory.x if it exists? - None => panic!("Unsupported target architecture: {}", target), + let memory_x_file = match target_info.arch() { + Some(Arch::Armv6M) => "memory_microbit.x", + Some(Arch::Armv7M) | Some(Arch::Armv7EM) => "memory_lm3s6965evb.x", + Some(Arch::Armv8MBase) | Some(Arch::Armv8MMain) => "memory_mps2_an505.x", + _ => panic!("Unsupported target architecture: {:?}", target_info), }; + println!("cargo:rerun-if-changed={}", memory_x_file); let target_path = out.join("memory.x"); // Copy memory.x from parent directory only if it doesn't exist locally - std::fs::copy(memory_x_file, &target_path) - .unwrap_or_else(|e| panic!("Failed to copy memory.x: {}", e)); + std::fs::copy(memory_x_file, &target_path).expect("Failed to copy memory.x for target"); + // Tell linker to look where we just put the file println!("cargo:rustc-link-search={}", out.display()); - - // By default, Cargo will re-run a build script whenever - // any file in the project changes. By specifying `memory.x` - // here, we ensure the build script is only re-run when - // `memory.x` is changed. - println!("cargo:rerun-if-changed=memory_m3.x"); - println!("cargo:rerun-if-changed=memory_microbit.x"); } diff --git a/testsuite/commands.gdb b/testsuite/commands.gdb new file mode 100644 index 00000000..c5cd2564 --- /dev/null +++ b/testsuite/commands.gdb @@ -0,0 +1,7 @@ +target extended-remote :1234 +break main +layout asm +layout regs +set logging file ./target/debug.log +set logging enabled on +stepi diff --git a/testsuite/memory_m3.x b/testsuite/memory_lm3s6965evb.x similarity index 100% rename from testsuite/memory_m3.x rename to testsuite/memory_lm3s6965evb.x diff --git a/testsuite/memory_mps2_an505.x b/testsuite/memory_mps2_an505.x new file mode 100644 index 00000000..9b39fa75 --- /dev/null +++ b/testsuite/memory_mps2_an505.x @@ -0,0 +1,7 @@ +/* Memory map for MPS2-AN505, using Non-Secure memory */ +MEMORY +{ + /* NOTE K = KiBi = 1024 bytes */ + FLASH : ORIGIN = 0x10000000, LENGTH = 4M + RAM : ORIGIN = 0x28000000, LENGTH = 2M +} diff --git a/testsuite/src/lib.rs b/testsuite/src/lib.rs index a684407f..3ec3c9a8 100644 --- a/testsuite/src/lib.rs +++ b/testsuite/src/lib.rs @@ -166,8 +166,8 @@ mod tests { cortex_m::asm::semihosting_syscall(SYS_WRITE0, msg.as_ptr() as usize as u32); } } - - #[cfg(armv8m)] + + #[cfg(any(arm_architecture = "v8-m.base", arm_architecture = "v8-m.main"))] #[test] fn sau_set_get_region(p: &mut cortex_m::Peripherals) { use cortex_m::peripheral::sau::{SauRegion, SauRegionAttribute}; diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs index 23c4aecb..2059a8c9 100644 --- a/xtask/src/lib.rs +++ b/xtask/src/lib.rs @@ -1,19 +1,43 @@ //! `cargo xtask` automation. //! //! Please refer to for an explanation of the concept. -//! -//! Also see the docs in `asm.rs`. use std::process::Command; -pub fn install_targets(targets: &mut dyn Iterator, toolchain: Option<&str>) { +/// List of all compilation targets we support. +/// +/// This should generally list all of the bare-metal thumb targets starting at thumbv6. +pub static ALL_TARGETS: &[&str] = &[ + "thumbv6m-none-eabi", + "thumbv7m-none-eabi", + "thumbv7em-none-eabi", + "thumbv7em-none-eabihf", + "thumbv8m.base-none-eabi", + "thumbv8m.main-none-eabi", + "thumbv8m.main-none-eabihf", +]; + +/// Same as the list above, except with all "base" targets that have a reduced feature set removed. +pub static NON_BASE_TARGETS: &[&str] = &[ + "thumbv7m-none-eabi", + "thumbv7em-none-eabi", + "thumbv7em-none-eabihf", + "thumbv8m.main-none-eabi", + "thumbv8m.main-none-eabihf", +]; + +#[rustfmt::skip] +pub static PACKAGE_FEATURES: &[(&str, &[&str], &[&str])] = &[ + ("cortex-m", ALL_TARGETS, &["cm7-r0p1", "critical-section-single-core"]), // no `linker-plugin-lto` since it's experimental + ("cortex-m-semihosting", ALL_TARGETS, &["no-semihosting", "jlink-quirks"]), + ("panic-semihosting", ALL_TARGETS, &["exit", "jlink-quirks"]), + ("panic-itm", NON_BASE_TARGETS, &[]), +]; + +pub fn install_targets(targets: &[&str]) { let mut rustup = Command::new("rustup"); rustup.arg("target").arg("add").args(targets); - if let Some(toolchain) = toolchain { - rustup.arg("--toolchain").arg(toolchain); - } - let status = rustup.status().unwrap(); assert!(status.success(), "rustup command failed: {:?}", rustup); } @@ -38,3 +62,63 @@ pub fn check_host_side() { assert!(a < b); } } + +pub fn check_crates_build(is_nightly: bool) { + // Build all crates for each supported target. + for (package, targets, all_features) in PACKAGE_FEATURES { + for target in *targets { + // Filters crate features, keeping only those that are supported. + // Relies on all crates in this repo to use the same convention. + let should_use_feature = |feat: &str| { + match feat { + // This is nightly-only, so don't use it on stable. + "inline-asm" => is_nightly, + // This only affects thumbv7em targets. + "cm7-r0p1" => target.starts_with("thumbv7em"), + + _ => true, + } + }; + + // Every crate must build with the default feature set. + build(package, target, &[]); + + let used_features = &*all_features + .iter() + .copied() + .filter(|feat| should_use_feature(feat)) + .collect::>(); + + // (note: we don't test with default features disabled, since we don't use them yet) + + // Every crate must build with each individual feature enabled. + for feat in used_features { + build(package, target, &[*feat]); + } + + // Every crate must build with *all* features enabled. + build(package, target, used_features); + + // (technically we should be checking the powerset of all features if we wanted to be + // *really* sure, but that takes too much time and isn't very easy to implement) + } + } +} + +fn build(package: &str, target: &str, features: &[&str]) { + println!("building {} for {} {:?}", package, target, features); + let mut cargo = Command::new("cargo"); + cargo.args(["build", "-p", package, "--target", target]); + for feat in features { + cargo.args(["--features", *feat]); + } + + // Cargo features don't work right when invoked from the workspace root, so change to the + // package's directory when necessary. + if package != "cortex-m" { + cargo.current_dir(package); + } + + let status = cargo.status().unwrap(); + assert!(status.success(), "failed to execute: {:?}", cargo); +} diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 224be3fe..ebc6b3bf 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -1,18 +1,29 @@ -use std::{env, process}; -use xtask::check_host_side; +use xtask::{ALL_TARGETS, check_crates_build, check_host_side, install_targets}; +#[rustfmt::skip] fn main() { - let subcommand = env::args().nth(1); + let subcommand = std::env::args().nth(1); match subcommand.as_deref() { + Some("install-targets") => install_targets(ALL_TARGETS), Some("check-host-side") => check_host_side(), + Some("check-crates-build") => { + let output = std::process::Command::new("rustc") + .arg("-V") + .output() + .unwrap(); + let is_nightly = std::str::from_utf8(&output.stdout).unwrap().contains("nightly"); + check_crates_build(is_nightly) + } _ => { eprintln!("usage: cargo xtask "); eprintln!(); eprintln!("subcommands:"); - eprintln!( - " check-host-side Build the crate in a non-Cortex-M host application and check host side usage of certain types" - ); - process::exit(1); + eprintln!(" check-host-side Build the crate in a non-Cortex-M host application and check host side usage of certain types"); + eprintln!(" check-crates-build Check the workspace can be built for all known targets"); + eprintln!(" install-targets Use rustup to install all the appropriate targets"); + eprintln!(); + eprintln!("You can also run 'cargo test' in the ./xtask directory"); + std::process::exit(1); } } } diff --git a/xtask/tests/ci.rs b/xtask/tests/ci.rs index 62530e29..6ecec6ee 100644 --- a/xtask/tests/ci.rs +++ b/xtask/tests/ci.rs @@ -1,108 +1,18 @@ use std::process::Command; -use std::{env, str}; -use xtask::{check_host_side, install_targets}; - -/// List of all compilation targets we support. -/// -/// This should generally list all of the bare-metal thumb targets starting at thumbv6. -static ALL_TARGETS: &[&str] = &[ - "thumbv6m-none-eabi", - "thumbv7m-none-eabi", - "thumbv7em-none-eabi", - "thumbv7em-none-eabihf", - "thumbv8m.base-none-eabi", - "thumbv8m.main-none-eabi", - "thumbv8m.main-none-eabihf", -]; - -/// Same as the list above, except with all "base" targets that have a reduced feature set removed. -static NON_BASE_TARGETS: &[&str] = &[ - "thumbv7m-none-eabi", - "thumbv7em-none-eabi", - "thumbv7em-none-eabihf", - "thumbv8m.main-none-eabi", - "thumbv8m.main-none-eabihf", -]; - -fn build(package: &str, target: &str, features: &[&str]) { - println!("building {} for {} {:?}", package, target, features); - let mut cargo = Command::new("cargo"); - cargo.args(&["build", "-p", package, "--target", target]); - for feat in features { - cargo.args(&["--features", *feat]); - } - - // Cargo features don't work right when invoked from the workspace root, so change to the - // package's directory when necessary. - if package != "cortex-m" { - cargo.current_dir(package); - } - - let status = cargo.status().unwrap(); - assert!(status.success(), "failed to execute: {:?}", cargo); -} - -#[rustfmt::skip] -static PACKAGE_FEATURES: &[(&str, &[&str], &[&str])] = &[ - ("cortex-m", ALL_TARGETS, &["cm7-r0p1", "critical-section-single-core"]), // no `linker-plugin-lto` since it's experimental - ("cortex-m-semihosting", ALL_TARGETS, &["no-semihosting", "jlink-quirks"]), - ("panic-semihosting", ALL_TARGETS, &["exit", "jlink-quirks"]), - ("panic-itm", NON_BASE_TARGETS, &[]), -]; - -fn check_crates_build(is_nightly: bool, is_msrv: bool) { - // Build all crates for each supported target. - for (package, targets, all_features) in PACKAGE_FEATURES { - for target in *targets { - // Filters crate features, keeping only those that are supported. - // Relies on all crates in this repo to use the same convention. - let should_use_feature = |feat: &str| { - match feat { - // This is nightly-only, so don't use it on stable. - "inline-asm" => is_nightly, - // This only affects thumbv7em targets. - "cm7-r0p1" => target.starts_with("thumbv7em"), - - _ => true, - } - }; - - // Every crate must build with the default feature set. - build(package, target, &[]); - - let used_features = &*all_features - .iter() - .copied() - .filter(|feat| should_use_feature(*feat)) - .collect::>(); - - // (note: we don't test with default features disabled, since we don't use them yet) - - // Every crate must build with each individual feature enabled. - for feat in used_features { - build(package, target, &[*feat]); - } - - // Every crate must build with *all* features enabled. - build(package, target, used_features); - - // (technically we should be checking the powerset of all features if we wanted to be - // *really* sure, but that takes too much time and isn't very easy to implement) - } - } -} +use xtask::{ALL_TARGETS, check_crates_build, check_host_side, install_targets}; fn main() { // Tests execute in the containing crate's root dir, `cd ..` so that we find `asm` etc. - env::set_current_dir("..").unwrap(); + std::env::set_current_dir("..").unwrap(); - install_targets(&mut ALL_TARGETS.iter().cloned(), None); + install_targets(ALL_TARGETS); let output = Command::new("rustc").arg("-V").output().unwrap(); - let is_nightly = str::from_utf8(&output.stdout).unwrap().contains("nightly"); - let is_msrv = str::from_utf8(&output.stdout).unwrap().contains("1.59"); + let is_nightly = std::str::from_utf8(&output.stdout) + .unwrap() + .contains("nightly"); - check_crates_build(is_nightly, is_msrv); + check_crates_build(is_nightly); // Check host-side applications of the crate. check_host_side();