imports that enforce themselves: unused is an error, missing suggests… #38
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # builds and tests every push and pull request, on gcc and clang. | |
| # the sanitizers are the point. a build that only passes -O2 is not verified. | |
| name: ci | |
| on: | |
| push: | |
| branches: [ main ] | |
| pull_request: | |
| branches: [ main ] | |
| jobs: | |
| build: | |
| name: build and test | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| compiler: [gcc, clang] | |
| env: | |
| # The clang-tidy major version CI installs. Must be >= 19 for the | |
| # KeepEmptyLines block in .clang-format, and must currently exist in | |
| # apt.llvm.org for the runner's codename. See the install step. | |
| LLVM_MAJOR: '24' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: set compiler | |
| run: | | |
| echo "CC=${{ matrix.compiler }}" >> $GITHUB_ENV | |
| # flint compiles in a fraction of a second, so ccache buys almost nothing | |
| # here. kept because the matrix runs the same build several times over. | |
| - name: configure ccache | |
| run: | | |
| sudo apt-get update && sudo apt-get install -y ccache | |
| ccache --max-size=50M | |
| ccache -z | |
| - name: release build | |
| run: make clean && make release | |
| - name: language tests | |
| run: make test | |
| - name: unit tests | |
| run: make unit | |
| - name: debug build and disassembler | |
| run: make clean && make debug | |
| # gc on every allocation plus asan and ubsan. slow, catches everything. | |
| - name: gc stress and sanitizers | |
| run: make clean && make stress | |
| # The computed-goto interpreter. It is a separate binary and a separate | |
| # build script, so nothing else in this workflow exercises it, and a | |
| # transformation bug in scripts/to_computed_goto.py shows up as a crash at | |
| # run time rather than as a compile error. | |
| - name: computed-goto interpreter | |
| run: | | |
| make flint-goto | |
| sh tests/run_tests.sh ./flint-goto | |
| # clang-tidy, which reports include-hygiene problems the compiler does not. | |
| # | |
| # The LLVM apt packages are the point. The runner's preinstalled | |
| # clang-format/tidy are whatever Ubuntu shipped, and .clang-format uses | |
| # KeepEmptyLines as a nested block, which only exists in clang 19+. On the | |
| # runner's version clang-tidy aborted before checking a single line, so | |
| # this step had never actually run -- it just exited 2 and was marked | |
| # continue-on-error. | |
| # | |
| # Pinning the toolchain is what makes it run. The --depth=1 packages are | |
| # from the LLVM apt repo and always current. | |
| - name: install llvm | |
| run: | | |
| set -euo pipefail | |
| sudo apt-get update | |
| sudo apt-get install -y wget apt-transport-https gpg | |
| wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key \ | |
| | sudo gpg --dearmor -o /usr/share/keyrings/llvm.gpg | |
| codename=$(lsb_release -cs) | |
| echo "deb [signed-by=/usr/share/keyrings/llvm.gpg]" \ | |
| "http://apt.llvm.org/${codename}/ llvm-toolchain-${codename} main" \ | |
| | sudo tee /etc/apt/sources.list.d/llvm.list | |
| sudo apt-get update | |
| # The major version is pinned rather than left to float. | |
| # | |
| # Asking for bare `clang-tidy` makes apt resolve to clang-tidy-<N> for | |
| # whatever N it judges newest, and the snapshot repo carries one major | |
| # per distro release. When that resolution picks a version the repo | |
| # does not have, apt fails with "not installable" and the step dies | |
| # before linting anything -- the same silent failure as before, only | |
| # louder. | |
| # | |
| # The apt.llvm.org llvm-toolchain repo carries exactly one major | |
| # version per distro release, so the only safe pin is one that is | |
| # currently published. Verified against the noble package index: | |
| # clang-tidy and clang-tidy-24, and nothing else. Pinning to 20 -- | |
| # which is what this was first written as -- fails the same way the | |
| # unpinned version did, with 'clang-tidy-20 is not installable'. | |
| # | |
| # Bump it when a new major lands, and check the index first. | |
| sudo apt-get install -y "clang-tidy-${LLVM_MAJOR}" | |
| # clang-format runs first, on its own. clang-tidy loads .clang-format for | |
| # every file it processes, and an unrecognised key there aborts the whole | |
| # run before it checks anything -- silently, with exit 2, which reads | |
| # exactly like a clean run. Splitting this into its own step means the | |
| # failure is attributable. | |
| # | |
| # It is expected to fail on older toolchains, which is why it is | |
| # continue-on-error. Its job here is to make a mismatch visible, not to | |
| # gate the build. | |
| - name: clang-format config check | |
| run: make fmt-check | |
| continue-on-error: true | |
| - name: clang-tidy | |
| run: make lint | |
| # Advisory by design: the target says so, and a lint policy change | |
| # should not be able to block a push. The annotations it produces are | |
| # the report, not a gate. | |
| continue-on-error: true | |
| # A file with no trailing newline is a compile error under clang | |
| # (-Wnewline-eof) and accepted by gcc. That asymmetry cost a CI run before | |
| # it was noticed, and it is trivially checkable. | |
| - name: files end with a newline | |
| run: | | |
| bad=0 | |
| for f in $(git ls-files '*.c' '*.h' '*.fl' '*.md' '*.py' '*.sh'); do | |
| if [ -s "$f" ] && [ -n "$(tail -c 1 "$f")" ]; then | |
| echo "no newline at end of file: $f" | |
| bad=1 | |
| fi | |
| done | |
| if [ "$bad" -ne 0 ]; then | |
| echo | |
| echo "gcc accepts these; clang rejects them under -Werror." | |
| echo "the usual cause is a whole-file rewrite that did not append" | |
| echo "a trailing newline: printf '\n' >> the file fixes it." | |
| fi | |
| exit $bad | |
| - name: ccache stats | |
| run: ccache -s |