summaryrefslogtreecommitdiff
path: root/.github/workflows/cmake.yml
blob: fd678f1332357348271b703860c4a68330a10315 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
name: Build, lint, and test

on: [push, pull_request]

env:
  # Don't mix these up!
  # runner.workspace = /home/runner/work/serenity
  # github.workspace = /home/runner/work/serenity/serenity
  SERENITY_SOURCE_DIR: ${{ github.workspace }}

concurrency:
  group: ${{ github.head_ref || format('{0}-{1}', github.ref, github.run_number) }}
  cancel-in-progress: true

jobs:
  build_and_test_serenity:
    runs-on: ${{ matrix.os }}
    if: github.repository == 'SerenityOS/serenity'
    strategy:
      fail-fast: false
      matrix:
        debug-options: ['ALL_DEBUG', 'NORMAL_DEBUG']
        os: [ubuntu-20.04]
        arch: ['i686', 'x86_64']
        # If ccache is broken and you would like to bust the ccache cache on Github Actions, increment this:
        ccache-mark: [0]
        exclude:
          # We currently manually disable the ALL_DEBUG build on x86_64 for sake of saving CI time, as it is not our main target right now
          - debug-options: 'ALL_DEBUG'
            arch: 'x86_64'

    steps:
      - uses: actions/checkout@v2
      # Set default Python to python 3.x, and set Python path such that pip install works properly
      - uses: actions/setup-python@v2

      # === OS SETUP ===

      # Do we need to update the package cache first?
      # sudo apt-get update -qq
      - name: "Install Ubuntu dependencies"
        # These packages are already part of the ubuntu-20.04 image:
        # cmake clang-format-11 libgmp-dev npm shellcheck
        # Packages below aren't.
        #
        # We add the canonical-server/server-backports PPA to get updated QEMU releases without having to manage
        #    yet another cache in github actions
        # We add the ubuntu-toolchain-r/test PPA to get gcc-11 on 20.04
        run: |
          sudo add-apt-repository ppa:canonical-server/server-backports
          sudo add-apt-repository ppa:ubuntu-toolchain-r/test
          sudo apt-get update
          sudo apt-get install -y ccache e2fsprogs gcc-11 g++-11 libstdc++-11-dev libmpfr-dev libmpc-dev ninja-build qemu-utils qemu-system-i386 unzip
      - name: Install JS dependencies
        run: sudo npm install -g prettier@2.5.1
      - name: Install Python dependencies
        # The setup-python action set default python to python3.x. Note that we are not using system python here.
        run: |
          python -m pip install --upgrade pip
          pip install flake8 requests
      - name: Check versions
        run: set +e; g++ --version; g++-11 --version; clang-format --version; clang-format-11 --version; prettier --version; python --version; python3 --version; ninja --version; flake8 --version; ccache --version; qemu-system-i386 --version

      # === PREPARE FOR BUILDING ===

      - name: Lint (Phase 1/2)
        run: ${{ github.workspace }}/Meta/lint-ci.sh
      - name: Prepare useful stamps
        id: stamps
        shell: cmake -P {0}
        run: |
          string(TIMESTAMP current_date "%Y_%m_%d_%H_%M_%S" UTC)
          # Output everything twice to make it visible both in the logs
          # *and* as actual output variable, in this order.
          message("  set-output name=time::${current_date}")
          message("::set-output name=time::${current_date}")
          message("  set-output name=libc_headers::${{ hashFiles('Userland/Libraries/LibC/**/*.h', 'Userland/Libraries/LibPthread/**/*.h', 'Toolchain/Patches/[!llvm]*.patch', 'Toolchain/BuildIt.sh') }}")
          message("::set-output name=libc_headers::${{ hashFiles('Userland/Libraries/LibC/**/*.h', 'Userland/Libraries/LibPthread/**/*.h', 'Toolchain/Patches/[!llvm]*.patch', 'Toolchain/BuildIt.sh') }}")

      - name: Toolchain cache
        # TODO: Change the version to the released version when https://github.com/actions/cache/pull/489 (or 571) is merged.
        uses: actions/cache@03e00da99d75a2204924908e1cca7902cafce66b
        env:
          CACHE_SKIP_SAVE: ${{ github.event_name == 'pull_request' }}
        with:
          path: ${{ github.workspace }}/Toolchain/Cache/
          # This assumes that *ALL* LibC and LibPthread headers have an impact on the Toolchain.
          # This is wrong, and causes more Toolchain rebuilds than necessary.
          # However, we want to avoid false cache hits at all costs.
          key: ${{ runner.os }}-toolchain-${{ matrix.arch }}-${{ steps.stamps.outputs.libc_headers }}

      - name: Restore or regenerate Toolchain
        run: TRY_USE_LOCAL_TOOLCHAIN=y ARCH="${{ matrix.arch }}" ${{ github.workspace }}/Toolchain/BuildIt.sh

      - name: ccache(1) cache
        # Pull the ccache *after* building the toolchain, in case building the Toolchain somehow interferes.
        # TODO: Change the version to the released version when https://github.com/actions/cache/pull/489 (or 571) is merged.
        uses: actions/cache@03e00da99d75a2204924908e1cca7902cafce66b
        env:
          CACHE_SKIP_SAVE: ${{ github.event_name == 'pull_request' }}
        with:
          path: /home/runner/.ccache
          # If you're here because ccache broke (it never should), increment matrix.ccache-mark.
          # We want to always reuse the last cache, but upload a new one.
          # This is achieved by using the "prefix-timestamp" format,
          # and permitting the restore-key "prefix-" without specifying a timestamp.
          # For this trick to work, the timestamp *must* come last, and it *must* be missing in 'restore-keys'.
          key: ${{ runner.os }}-ccache-${{ matrix.arch }}-v${{ matrix.ccache-mark }}-D${{ matrix.debug-options }}-toolchain_${{steps.stamps.outputs.libc_headers}}-time${{ steps.stamps.outputs.time }}
          restore-keys: |
            ${{ runner.os }}-ccache-${{ matrix.arch }}-v${{ matrix.ccache-mark }}-D${{ matrix.debug-options }}-toolchain_${{steps.stamps.outputs.libc_headers}}-

      - name: Show ccache stats before build and configure
        run: |
          # We only have 5 GiB of cache available *in total*. Beyond that, GitHub deletes caches.
          # Currently, we use about 130 MB for the two toolchains (i686 & x86_64), and three ccache caches:
          # One with ALL_DEBUG (i686) and two with NORMAL_DEBUG (i686 & x86_64).
          # Therefore, using 1.6 GB or more per cache causes disaster.
          # Building from scratch fills the ccache cache from 0 to about 0.7 GB, and after compression it comes out to
          # about 0.25 GB, so 3 GB (1GB after compression) should be plenty, all while comfortably fitting in the cache.
          ccache -M 3000M
          ccache -s
      - name: Create build directory
        run: |
          mkdir -p ${{ github.workspace }}/Build/${{ matrix.arch }}/TZDB
          mkdir -p ${{ github.workspace }}/Build/${{ matrix.arch }}/UCD
          mkdir -p ${{ github.workspace }}/Build/${{ matrix.arch }}/CLDR
      - name: TimeZoneData cache
        # TODO: Change the version to the released version when https://github.com/actions/cache/pull/489 (or 571) is merged.
        uses: actions/cache@03e00da99d75a2204924908e1cca7902cafce66b
        with:
          path: ${{ github.workspace }}/Build/${{ matrix.arch }}/TZDB
          key: TimeZoneData-${{ hashFiles('Meta/CMake/time_zone_data.cmake') }}
      - name: UnicodeData cache
        # TODO: Change the version to the released version when https://github.com/actions/cache/pull/489 (or 571) is merged.
        uses: actions/cache@03e00da99d75a2204924908e1cca7902cafce66b
        with:
          path: ${{ github.workspace }}/Build/${{ matrix.arch }}/UCD
          key: UnicodeData-${{ hashFiles('Meta/CMake/unicode_data.cmake') }}
      - name: UnicodeLocale Cache
        # TODO: Change the version to the released version when https://github.com/actions/cache/pull/489 (or 571) is merged.
        uses: actions/cache@03e00da99d75a2204924908e1cca7902cafce66b
        with:
          path: ${{ github.workspace }}/Build/${{ matrix.arch }}/CLDR
          key: UnicodeLocale-${{ hashFiles('Meta/CMake/unicode_data.cmake') }}
      - name: Create build environment with extra debug options
        # Build the entire project with all available debug options turned on, to prevent code rot.
        # However, it is unwieldy and slow to run tests with them enabled, so we will build twice.
        run: |
          cmake -S Meta/CMake/Superbuild -B Build/superbuild -GNinja \
            -DSERENITY_ARCH=${{ matrix.arch }} \
            -DSERENITY_TOOLCHAIN=GNU \
            -DBUILD_LAGOM=ON \
            -DCMAKE_C_COMPILER=gcc-11 \
            -DCMAKE_CXX_COMPILER=g++-11 \
            -DENABLE_ALL_DEBUG_FACILITIES=ON \
            -DENABLE_PCI_IDS_DOWNLOAD=OFF \
            -DENABLE_USB_IDS_DOWNLOAD=OFF
        if: ${{ matrix.debug-options == 'ALL_DEBUG' }}
      - name: Create build environment
        working-directory: ${{ github.workspace }}
        # Note that we do not set BUILD_LAGOM for the normal debug build
        # We build and run the Lagom tests in a separate job, and sanitizer builds take a good while longer than non-sanitized.
        run:  |
          cmake -S Meta/CMake/Superbuild -B Build/superbuild -GNinja \
            -DSERENITY_ARCH=${{ matrix.arch }} \
            -DSERENITY_TOOLCHAIN=GNU \
            -DCMAKE_C_COMPILER=gcc-11 \
            -DCMAKE_CXX_COMPILER=g++-11 \
            -DENABLE_UNDEFINED_SANITIZER=ON \
            -DENABLE_PCI_IDS_DOWNLOAD=OFF \
            -DENABLE_USB_IDS_DOWNLOAD=OFF
        if: ${{ matrix.debug-options == 'NORMAL_DEBUG' }}

      # === ACTUALLY BUILD ===

      - name: Build Serenity and Tests
        working-directory: ${{ github.workspace }}/Build/superbuild
        run: cmake --build .
      - name: Show ccache stats after build
        run: ccache -s
      - name: Lint (Phase 2/2)
        working-directory: ${{ github.workspace }}/Meta
        env:
          SERENITY_ARCH: ${{ matrix.arch }}
        run: ./check-symbols.sh

      - name: Create Serenity Rootfs
        if: ${{ matrix.debug-options == 'NORMAL_DEBUG'}}
        working-directory: ${{ github.workspace }}/Build/${{ matrix.arch }}
        run: ninja install && ninja image

      - name: Run On-Target Tests
        if: ${{ matrix.debug-options == 'NORMAL_DEBUG'}}
        working-directory: ${{ github.workspace }}/Build/${{ matrix.arch }}
        env:
          SERENITY_QEMU_CPU: "max,vmx=off"
          SERENITY_KERNEL_CMDLINE: "fbdev=off panic=shutdown system_mode=self-test"
          SERENITY_RUN: "ci"
        run: |
          echo "::group::ninja run # Qemu output"
          ninja run
          echo "::endgroup::"
          echo "::group::Verify Output File"
          mkdir fsmount
          sudo mount -t ext2 -o loop,rw _disk_image fsmount
          echo "Results: "
          sudo cat fsmount/home/anon/test-results.log
          if ! sudo grep -q "Failed: 0" fsmount/home/anon/test-results.log
          then
            echo "::error :^( Tests failed, failing job"
            exit 1
          fi
          echo "::endgroup::"
        timeout-minutes: 60

      - name: Print Target Logs
        # Extremely useful if Serenity hangs trying to run one of the tests
        if: ${{ !cancelled() && matrix.debug-options == 'NORMAL_DEBUG'}}
        working-directory: ${{ github.workspace }}/Build/${{ matrix.arch }}
        run: '[ ! -e debug.log ] || cat debug.log'

      - name: Check manpages for completeness
        if: ${{ matrix.debug-options == 'NORMAL_DEBUG' && matrix.arch == 'i686'}}
        working-directory: ${{ github.workspace }}/Build/${{ matrix.arch }}
        env:
          # The script already sets the correct SERENITY_RUN and SERENITY_KERNEL_CMDLINE envvars.
          SERENITY_ARCH: ${{ matrix.arch }}
          SERENITY_QEMU_CPU: "max,vmx=off"
        run: |
          # Running the tests apparently leaves the image sufficiently broken
          rm _disk_image
          ninja image
          /usr/bin/time ../../Meta/export-argsparser-manpages.sh --verify-git-state
        timeout-minutes: 10