1name: CI
2
3on:
4  merge_group:
5  pull_request:
6    branches:
7      - libc-0.2
8
9env:
10  CARGO_TERM_COLOR: always
11  CARGO_TERM_VERBOSE: true
12  LIBC_CI: 1
13  RUSTDOCFLAGS: -Dwarnings
14  RUSTFLAGS: -Dwarnings
15  RUST_BACKTRACE: full
16
17defaults:
18  run:
19    shell: bash
20
21jobs:
22  style_check:
23    name: Style check
24    runs-on: ubuntu-24.04
25    timeout-minutes: 10
26    steps:
27      - uses: actions/checkout@v4
28      - name: Setup Rust toolchain
29        run: ./ci/install-rust.sh && rustup component add rustfmt
30      - name: Check style
31        run: ./ci/style.sh
32
33  # This runs `cargo build --target ...` for all T1 and T2 targets`
34  verify_build:
35    name: Verify build
36    strategy:
37      matrix:
38        toolchain: [stable, nightly, 1.63.0]
39        os: [ubuntu-24.04, macos-14, windows-2022]
40        include:
41          - toolchain: beta
42            os: ubuntu-24.04
43    runs-on: ${{ matrix.os }}
44    timeout-minutes: 25
45    env:
46      TOOLCHAIN: ${{ matrix.toolchain }}
47    steps:
48      - uses: actions/checkout@v4
49      # Remove `-Dwarnings` at the MSRV since lints may be different or buffier
50      - name: Update RUSTFLAGS
51        run: |
52          set -eux
53          [ "${{ matrix.toolchain }}" = "1.63.0" ] && echo 'RUSTFLAGS=' >> "$GITHUB_ENV" || true
54
55      - name: Setup Rust toolchain
56        run: ./ci/install-rust.sh
57
58      # FIXME(ci): These `du` statements are temporary for debugging cache
59      - name: Target size before restoring cache
60        run: du -sh target | sort -k 2 || true
61      - uses: Swatinem/rust-cache@v2
62        with:
63          key: ${{ matrix.os }}-${{ matrix.toolchain }}
64      - name: Target size after restoring cache
65        run: du -sh target | sort -k 2 || true
66
67      - name: Execute build.sh
68        run: ./ci/verify-build.sh
69      - name: Target size after job completion
70        run: du -sh target | sort -k 2
71
72  test_tier1:
73    name: Test tier1
74    strategy:
75      matrix:
76        include:
77          - target: i686-unknown-linux-gnu
78            docker: true
79            os: ubuntu-24.04
80          - target: i686-unknown-linux-gnu
81            docker: true
82            os: ubuntu-24.04
83            artifact-tag: offset-bits64
84            env:
85              RUST_LIBC_UNSTABLE_GNU_FILE_OFFSET_BITS: 64
86          - target: x86_64-unknown-linux-gnu
87            docker: true
88            os: ubuntu-24.04
89          - target: aarch64-apple-darwin
90            os: macos-14
91          - target: x86_64-pc-windows-gnu
92            os: windows-2022
93            env:
94              ARCH_BITS: 64
95              ARCH: x86_64
96          - target: x86_64-pc-windows-msvc
97            os: windows-2022
98          # FIXME: It currently causes segfaults.
99          #- target: i686-pc-windows-gnu
100          #  env:
101          #    ARCH_BITS: 32
102          #    ARCH: i686
103          - target: i686-pc-windows-msvc
104            os: windows-2022
105    runs-on: ${{ matrix.os }}
106    timeout-minutes: 25
107    env:
108      TARGET: ${{ matrix.target }}
109    steps:
110      - uses: actions/checkout@v4
111      - name: Setup Rust toolchain
112        run: ./ci/install-rust.sh
113      - uses: Swatinem/rust-cache@v2
114        with:
115          key: ${{ matrix.target }}
116
117      - name: Add matrix env variables to the environment
118        if: matrix.env
119        run: |
120          echo '${{ toJson(matrix.env) }}' |
121            jq -r 'to_entries | map("\(.key)=\(.value|tostring)") | .[]' >>$GITHUB_ENV
122        shell: bash
123
124      - name: Run natively
125        if: "!matrix.docker"
126        run: ./ci/run.sh ${{ matrix.target }}
127      - name: Run in Docker
128        if: "matrix.docker"
129        run: ./ci/run-docker.sh ${{ matrix.target }}
130
131      - name: Create CI artifacts
132        id: create_artifacts
133        if: always()
134        run: ./ci/create-artifacts.py
135      - uses: actions/upload-artifact@v4
136        if: always() && steps.create_artifacts.outcome == 'success'
137        with:
138          name: ${{ env.ARCHIVE_NAME }}-${{ matrix.target }}${{ matrix.artifact-tag && format('-{0}', matrix.artifact-tag) }}
139          path: ${{ env.ARCHIVE_PATH }}
140          retention-days: 5
141
142  test_tier2:
143    name: Test tier2
144    needs: [test_tier1, style_check]
145    runs-on: ubuntu-24.04
146    strategy:
147      fail-fast: true
148      max-parallel: 12
149      matrix:
150        target:
151          # FIXME(sparc): this takes much longer to run than any other job, put
152          # it first to make sure it gets a head start.
153          - sparc64-unknown-linux-gnu
154          - aarch64-linux-android
155          - aarch64-unknown-linux-gnu
156          - aarch64-unknown-linux-musl
157          - arm-linux-androideabi
158          - arm-unknown-linux-musleabihf
159          - i686-linux-android
160          - i686-unknown-linux-musl
161          - loongarch64-unknown-linux-gnu
162          - loongarch64-unknown-linux-musl
163          - powerpc64-unknown-linux-gnu
164          - powerpc64le-unknown-linux-gnu
165          - riscv64gc-unknown-linux-gnu
166          - s390x-unknown-linux-gnu
167          - wasm32-unknown-emscripten
168          - wasm32-wasip1
169          - wasm32-wasip2
170          - x86_64-linux-android
171          # FIXME: Exec format error (os error 8)
172          # - x86_64-unknown-linux-gnux32
173          - x86_64-unknown-linux-musl
174          # FIXME: It seems some items in `src/unix/mod.rs`
175          # aren't defined on redox actually.
176          # - x86_64-unknown-redox
177        include:
178          - target: arm-unknown-linux-gnueabihf
179          - target: arm-unknown-linux-gnueabihf
180            env:
181              RUST_LIBC_UNSTABLE_GNU_FILE_OFFSET_BITS: 64
182            artifact-tag: offset-bits64
183          # FIXME(ppc): SIGILL running tests, see
184          # https://github.com/rust-lang/libc/pull/4254#issuecomment-2636288713
185          # - target: powerpc-unknown-linux-gnu
186          # - target: powerpc-unknown-linux-gnu
187          #   env:
188          #     RUST_LIBC_UNSTABLE_GNU_FILE_OFFSET_BITS: 64
189          #   artifact-tag: offset-bits64
190    timeout-minutes: 25
191    env:
192      TARGET: ${{ matrix.target }}
193    steps:
194      - uses: actions/checkout@v4
195      - name: Setup Rust toolchain
196        run: ./ci/install-rust.sh
197      - uses: Swatinem/rust-cache@v2
198        with:
199          key: ${{ matrix.target }}
200
201      - name: Add matrix env variables to the environment
202        if: matrix.env
203        run: |
204          echo '${{ toJson(matrix.env) }}' |
205            jq -r 'to_entries | map("\(.key)=\(.value|tostring)") | .[]' >>$GITHUB_ENV
206        shell: bash
207
208      - name: Execute run-docker.sh
209        run: ./ci/run-docker.sh ${{ matrix.target }}
210
211      - name: Create CI artifacts
212        id: create_artifacts
213        if: always()
214        run: ./ci/create-artifacts.py
215      - uses: actions/upload-artifact@v4
216        if: always() && steps.create_artifacts.outcome == 'success'
217        with:
218          name: ${{ env.ARCHIVE_NAME }}-${{ matrix.target }}${{ matrix.artifact-tag && format('-{0}', matrix.artifact-tag) }}
219          path: ${{ env.ARCHIVE_PATH }}
220          retention-days: 5
221
222  test_tier2_vm:
223    name: Test tier2 VM
224    needs: [test_tier1, style_check]
225    runs-on: ubuntu-latest
226    strategy:
227      fail-fast: true
228      matrix:
229        target:
230          - x86_64-pc-solaris
231    timeout-minutes: 25
232    steps:
233      - uses: actions/checkout@v4
234      - name: test on Solaris
235        uses: vmactions/solaris-vm@v1
236        with:
237          release: "11.4-gcc"
238          usesh: true
239          mem: 4096
240          copyback: false
241          prepare: |
242            set -x
243            source <(curl -s https://raw.githubusercontent.com/psumbera/solaris-rust/refs/heads/main/sh.rust-web-install)
244            rustc --version
245            uname -a
246          run: |
247            export PATH=$HOME/.rust_solaris/bin:$PATH
248            ./ci/run.sh ${{ matrix.target }}
249
250  # One job that "summarizes" the success state of this pipeline. This can then be added to branch
251  # protection, rather than having to add each job separately.
252  success:
253    name: success
254    runs-on: ubuntu-24.04
255    needs:
256      - style_check
257      - test_tier1
258      - test_tier2
259      - test_tier2_vm
260      - verify_build
261    # Github branch protection is exceedingly silly and treats "jobs skipped because a dependency
262    # failed" as success. So we have to do some contortions to ensure the job fails if any of its
263    # dependencies fails.
264    if: always() # make sure this is never "skipped"
265    steps:
266      # Manually check the status of all dependencies. `if: failure()` does not work.
267      - name: check if any dependency failed
268        run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
269