Skip to content

v2.0: Modernization (M1-M6, 44 tasks) #847

v2.0: Modernization (M1-M6, 44 tasks)

v2.0: Modernization (M1-M6, 44 tasks) #847

Workflow file for this run

name: "Verify Build"
on:
push:
branches: [master]
pull_request:
# The branches below must be a subset of the branches above
branches: [master]
schedule:
- cron: '0 0 * * 0'
# Restrict every job's GITHUB_TOKEN to read-only by default.
# Jobs that need broader access should override at the job level.
permissions:
contents: read
jobs:
verify:
name: Verify
runs-on: ${{ matrix.os }}
env:
DEBUG: ${{ matrix.debug }}
COVERAGE: ${{ matrix.coverage }}
LINKING: ${{ matrix.linking }}
BUILD_TYPE: ${{ matrix.build-type }}
CC: ${{ matrix.c-compiler }}
CXX: ${{ matrix.cc-compiler }}
defaults:
run:
shell: ${{ matrix.shell }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
os-type: [ubuntu, mac]
test-group: [basic]
compiler-family: [none]
c-compiler: [gcc, clang]
cc-compiler: [g++, clang++]
debug: [debug, nodebug]
coverage: [coverage, nocoverage]
linking: [dynamic, static]
build-type: [classic]
shell: [bash]
exclude:
- os: ubuntu-latest
os-type: mac
- os: macos-latest
os-type: ubuntu
- c-compiler: gcc
cc-compiler: clang++
- c-compiler: clang
cc-compiler: g++
- c-compiler: clang
debug: debug
- debug: debug
coverage: nocoverage
- debug: nodebug
coverage: coverage
- linking: static
debug: debug
- linking: static
coverage: coverage
include:
- test-group: extra
os: ubuntu-latest
os-type: ubuntu
build-type: asan
compiler-family: clang
c-compiler: clang-18
cc-compiler: clang++-18
debug: debug
coverage: nocoverage
shell: bash
# This test gives false positives on newer versions of clang
# and ubuntu-18.04 is not supported anymore on github
#- test-group: extra
# os: ubuntu-18.04
# os-type: ubuntu
# build-type: msan
# compiler-family: clang
# c-compiler: clang-6.0
# cc-compiler: clang++-6.0
# debug: debug
# coverage: nocoverage
- test-group: extra
os: ubuntu-latest
os-type: ubuntu
build-type: lsan
compiler-family: clang
c-compiler: clang-18
cc-compiler: clang++-18
debug: debug
coverage: nocoverage
shell: bash
- test-group: extra
os: ubuntu-latest
os-type: ubuntu
build-type: tsan
compiler-family: clang
c-compiler: clang-18
cc-compiler: clang++-18
debug: debug
coverage: nocoverage
shell: bash
- test-group: extra
os: ubuntu-latest
os-type: ubuntu
build-type: ubsan
compiler-family: clang
c-compiler: clang-18
cc-compiler: clang++-18
debug: debug
coverage: nocoverage
shell: bash
# gcc-9 and gcc-10 dropped: lack full C++20 support (no concepts library, no std::span, no <bit> features).
- test-group: extra
os: ubuntu-latest
os-type: ubuntu
build-type: none
compiler-family: gcc
c-compiler: gcc-11
cc-compiler: g++-11
debug: nodebug
coverage: nocoverage
shell: bash
- test-group: extra
os: ubuntu-latest
os-type: ubuntu
build-type: none
compiler-family: gcc
c-compiler: gcc-12
cc-compiler: g++-12
debug: nodebug
coverage: nocoverage
shell: bash
- test-group: extra
os: ubuntu-latest
os-type: ubuntu
build-type: none
compiler-family: gcc
c-compiler: gcc-13
cc-compiler: g++-13
debug: nodebug
coverage: nocoverage
shell: bash
- test-group: extra
os: ubuntu-latest
os-type: ubuntu
build-type: none
compiler-family: gcc
c-compiler: gcc-14
cc-compiler: g++-14
debug: nodebug
coverage: nocoverage
shell: bash
# clang-11, clang-12, clang-14, and clang-15 dropped: incomplete C++20 support (concepts/<bit>/<span> gaps).
# clang-13 retained: passes the autoconf C++20 feature check on ubuntu-22.04.
- test-group: extra
os: ubuntu-22.04
os-type: ubuntu
build-type: none
compiler-family: clang
c-compiler: clang-13
cc-compiler: clang++-13
debug: nodebug
coverage: nocoverage
shell: bash
- test-group: extra
os: ubuntu-latest
os-type: ubuntu
build-type: none
compiler-family: clang
c-compiler: clang-16
cc-compiler: clang++-16
debug: nodebug
coverage: nocoverage
shell: bash
- test-group: extra
os: ubuntu-latest
os-type: ubuntu
build-type: none
compiler-family: clang
c-compiler: clang-17
cc-compiler: clang++-17
debug: nodebug
coverage: nocoverage
shell: bash
- test-group: extra
os: ubuntu-latest
os-type: ubuntu
build-type: valgrind
compiler-family: gcc
c-compiler: gcc-14
cc-compiler: g++-14
debug: nodebug
coverage: nocoverage
shell: bash
# Test build without digest auth support (issue #232)
- test-group: extra
os: ubuntu-latest
os-type: ubuntu
build-type: no-dauth
compiler-family: gcc
c-compiler: gcc
cc-compiler: g++
debug: nodebug
coverage: nocoverage
linking: dynamic
shell: bash
- test-group: extra
os: ubuntu-latest
os-type: ubuntu
build-type: iwyu
compiler-family: clang
c-compiler: clang-18
cc-compiler: clang++-18
debug: nodebug
coverage: nocoverage
shell: bash
- test-group: performance
os: ubuntu-latest
os-type: ubuntu
build-type: select
compiler-family: gcc
c-compiler: gcc-14
cc-compiler: g++-14
debug: nodebug
coverage: nocoverage
shell: bash
- test-group: performance
os: ubuntu-latest
os-type: ubuntu
build-type: nodelay
compiler-family: gcc
c-compiler: gcc-14
cc-compiler: g++-14
debug: nodebug
coverage: nocoverage
shell: bash
- test-group: performance
os: ubuntu-latest
os-type: ubuntu
build-type: threads
compiler-family: gcc
c-compiler: gcc-14
cc-compiler: g++-14
debug: nodebug
coverage: nocoverage
shell: bash
- test-group: extra
os: ubuntu-latest
os-type: ubuntu
build-type: lint
compiler-family: gcc
c-compiler: gcc-14
cc-compiler: g++-14
debug: debug
coverage: nocoverage
shell: bash
# TASK-007: dedicated header-hygiene gate. Runs `make check-hygiene`
# (preprocesses <httpserver.hpp> against the staged install and greps
# for forbidden backend headers). Surfaces this gate as its own named
# GitHub Actions check so reviewers see header-hygiene status
# independently of the broader `make check` log. Until M5 lands the
# check is informational (HEADER_HYGIENE_STRICT defaults to "no");
# TASK-020 flips it to strict.
- test-group: extra
os: ubuntu-latest
os-type: ubuntu
build-type: header-hygiene
compiler-family: gcc
c-compiler: gcc-14
cc-compiler: g++-14
debug: nodebug
coverage: nocoverage
linking: dynamic
shell: bash
# TASK-037: build-flag invariance gate (HAVE_* all ON lane).
# PRD-FLG-REQ-001 / arch §9 testing item 2. The consumer_fixture
# binary (test/consumer_fixture.cpp) touches every public symbol
# whose declaration was previously #ifdef HAVE_* gated. It MUST
# compile + link in this configuration. Stock libmicrohttpd +
# gnutls; isolated as its own matrix entry so the build-flag
# invariance gate has a dedicated status check.
- test-group: extra
os: ubuntu-latest
os-type: ubuntu
build-type: flag-invariance-on
compiler-family: gcc
c-compiler: gcc
cc-compiler: g++
debug: nodebug
coverage: nocoverage
linking: dynamic
shell: bash
# TASK-037: build-flag invariance gate (HAVE_* all OFF lane).
# libmicrohttpd is rebuilt with --disable-bauth --disable-dauth
# --disable-websockets so libhttpserver auto-detects all three
# as off. The gnutls install step is gated off for this build-
# type so gnutls/gnutls.h is absent from the include search path
# and HAVE_GNUTLS auto-detects to off as well. The same
# consumer_fixture.cpp must compile + link without source changes,
# proving every flag-gated public declaration is unconditional.
- test-group: extra
os: ubuntu-latest
os-type: ubuntu
build-type: flag-invariance-off
compiler-family: gcc
c-compiler: gcc
cc-compiler: g++
debug: nodebug
coverage: nocoverage
linking: dynamic
shell: bash
- test-group: basic
os: windows-latest
os-type: windows
msys-env: MINGW64
shell: 'msys2 {0}'
build-type: classic
compiler-family: none
c-compiler: gcc
cc-compiler: g++
debug: nodebug
coverage: nocoverage
linking: dynamic
- test-group: basic
os: windows-latest
os-type: windows
msys-env: MSYS
shell: 'msys2 {0}'
build-type: classic
compiler-family: none
c-compiler: gcc
cc-compiler: g++
debug: nodebug
coverage: nocoverage
linking: dynamic
# ARM 32-bit cross-compilation (ARMv7 hard-float)
- test-group: cross-compile
os: ubuntu-latest
os-type: ubuntu
build-type: arm32
compiler-family: arm-cross
c-compiler: arm-linux-gnueabihf-gcc
cc-compiler: arm-linux-gnueabihf-g++
debug: nodebug
coverage: nocoverage
linking: dynamic
shell: bash
# ARM 64-bit cross-compilation (AArch64)
- test-group: cross-compile
os: ubuntu-latest
os-type: ubuntu
build-type: arm64
compiler-family: arm-cross
c-compiler: aarch64-linux-gnu-gcc
cc-compiler: aarch64-linux-gnu-g++
debug: nodebug
coverage: nocoverage
linking: dynamic
shell: bash
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
shell: bash
if: ${{ github.event_name == 'pull_request' }}
- name: Setup MSYS2
if: ${{ matrix.os-type == 'windows' }}
uses: msys2/setup-msys2@v2
with:
msystem: ${{ matrix.msys-env }}
update: true
install: >-
autotools
base-devel
- name: Install MinGW64 packages
if: ${{ matrix.os-type == 'windows' && matrix.msys-env == 'MINGW64' }}
run: |
pacman --noconfirm -S --needed mingw-w64-x86_64-{toolchain,libtool,make,pkg-config,libsystre,doxygen,gnutls,graphviz,curl}
- name: Install MSYS packages
if: ${{ matrix.os-type == 'windows' && matrix.msys-env == 'MSYS' }}
run: |
pacman --noconfirm -S --needed msys2-devel gcc make libcurl-devel libgnutls-devel
- name: Install Ubuntu test sources
# ppa:ubuntu-toolchain-r/test was historically used to backport newer
# gcc onto older Ubuntu LTS. With the C++20 floor (TASK-001), our matrix
# only retains compilers that ship in stock ubuntu-22.04 / 24.04 repos
# (gcc-11..14, clang-13/16/17/18), so the PPA is no longer needed -- and
# add-apt-repository talks to launchpad, which is a flaky dependency.
run: |
sudo apt-get update ;
if: ${{ matrix.os-type == 'ubuntu' }}
- name: Install apache benchmark if needed
run: sudo apt-get install apache2-utils ;
if: ${{ matrix.test-group == 'performance' && matrix.os-type == 'ubuntu' }}
- name: Install optional clang if needed
run: sudo apt-get install ${{ matrix.c-compiler }}
if: ${{ matrix.compiler-family == 'clang' && matrix.os-type == 'ubuntu' }}
- name: Install optional gcc if needed
run: sudo apt-get install ${{ matrix.cc-compiler }}
if: ${{ matrix.compiler-family == 'gcc' && matrix.os-type == 'ubuntu' }}
- name: Install ARM cross-compilation toolchain
run: |
sudo apt-get update
if [ "${{ matrix.build-type }}" = "arm32" ]; then
sudo apt-get install -y gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf
elif [ "${{ matrix.build-type }}" = "arm64" ]; then
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
fi
if: ${{ matrix.compiler-family == 'arm-cross' }}
- name: Install valgrind if needed
run: sudo apt-get install valgrind
if: ${{ matrix.build-type == 'valgrind' && matrix.os-type == 'ubuntu' }}
- name: Install cpplint if needed
run: sudo pip3 install cpplint ;
if: ${{ matrix.build-type == 'lint' && matrix.os-type == 'ubuntu' }}
- name: Install IWYU dependencies if needed
run: |
sudo apt-get install llvm-18-dev libclang-18-dev clang-18 ;
if: ${{ matrix.build-type == 'iwyu' && matrix.os-type == 'ubuntu' }}
- name: IWYU from cache (for testing)
id: cache-IWYU
uses: actions/cache@v4
with:
path: include-what-you-use
key: ${{ matrix.os }}-${{ matrix.c-compiler }}-include-what-you-use-pre-built
if: ${{ matrix.build-type == 'iwyu' && matrix.os-type == 'ubuntu' }}
# Installing iwyu manually because clang and iwyu paths won't match on Ubuntu otherwise.
- name: Build IWYU if requested
run: |
CLANG_ROOT_PATH=`llvm-config-18 --prefix` ;
CLANG_BIN_PATH=`llvm-config-18 --bindir` ;
git clone https://github.com/include-what-you-use/include-what-you-use.git ;
cd include-what-you-use ;
git checkout clang_18 ;
mkdir build_iwyu ;
cd build_iwyu ;
cmake -G "Unix Makefiles" -DCMAKE_PREFIX_PATH=$CLANG_ROOT_PATH -DCMAKE_C_COMPILER=$CLANG_BIN_PATH/clang -DCMAKE_CXX_COMPILER=$CLANG_BIN_PATH/clang++ ../ ;
make ;
sudo make install ;
if: ${{ matrix.build-type == 'iwyu' && matrix.os-type == 'ubuntu' && steps.cache-IWYU.outputs.cache-hit != 'true' }}
- name: Install IWYU if requested
run: |
cd include-what-you-use/build_iwyu ;
sudo make install ;
if: ${{ matrix.build-type == 'iwyu' && matrix.os-type == 'ubuntu' }}
- name: CURL from cache (for testing)
id: cache-CURL
uses: actions/cache@v4
with:
path: curl-7.75.0
key: ${{ matrix.os }}-CURL-pre-built-v2
if: ${{ matrix.os == 'macos-latest' }}
- name: Build CURL (for testing)
run: |
curl https://libhttpserver.s3.amazonaws.com/travis_stuff/curl-7.75.0.tar.gz -o curl-7.75.0.tar.gz ;
tar -xzf curl-7.75.0.tar.gz ;
cd curl-7.75.0 ;
./configure --with-darwinssl --without-ssl ;
make ;
if: ${{ matrix.os == 'macos-latest' && steps.cache-CURL.outputs.cache-hit != 'true' }}
- name: Install CURL (for testing on mac only)
run: cd curl-7.75.0 ; sudo make install ;
if: ${{ matrix.os == 'macos-latest' }}
- name: Install CURL (for testing on linux)
run: sudo apt-get install libcurl4-openssl-dev
if: ${{ matrix.os-type == 'ubuntu' }}
- name: Install autotools on mac
run: brew install autoconf automake libtool
if: ${{ matrix.os == 'macos-latest' }}
- name: Setup dependencies (only on linux)
run: |
sudo apt-get install info install-info ;
sudo apt-get install cppcheck ;
if: ${{ matrix.os-type == 'ubuntu' }}
- name: Setup coverage dependencies (only on linux)
run: |
sudo pip install gcovr ;
if: ${{ matrix.os-type == 'ubuntu' && matrix.c-compiler == 'gcc' && matrix.debug == 'debug' && matrix.coverage == 'coverage' }}
- name: Setup gnutls dependency (only on linux)
run: |
sudo apt-get install libgnutls28-dev gnutls-bin ;
# TASK-037: skip gnutls install on the flag-invariance-off lane so
# HAVE_GNUTLS auto-detects to off (the configure script just
# AC_CHECK_HEADER's gnutls/gnutls.h, no header == HAVE_GNUTLS=0).
if: ${{ matrix.os-type == 'ubuntu' && matrix.build-type != 'flag-invariance-off' }}
- name: Fetch libmicrohttpd from cache
id: cache-libmicrohttpd
uses: actions/cache@v4
with:
path: libmicrohttpd-1.0.3
key: ${{ matrix.os }}-${{ matrix.c-compiler }}-libmicrohttpd-1.0.3-pre-built-v2
# TASK-037: the flag-invariance-off lane rebuilds libmicrohttpd with
# every sub-feature disabled, so it must skip the stock cache fetch.
if: ${{ matrix.os-type != 'windows' && matrix.build-type != 'no-dauth' && matrix.build-type != 'flag-invariance-off' && matrix.compiler-family != 'arm-cross' }}
- name: Build libmicrohttpd dependency (if not cached)
run: |
curl https://s3.amazonaws.com/libhttpserver/libmicrohttpd_releases/libmicrohttpd-1.0.3.tar.gz -o libmicrohttpd-1.0.3.tar.gz ;
echo "7816b57aae199cf5c3645e8770e1be5f0a4dfafbcb24b3772173dc4ee634126a libmicrohttpd-1.0.3.tar.gz" | sha256sum -c ;
tar -xzf libmicrohttpd-1.0.3.tar.gz ;
cd libmicrohttpd-1.0.3 ;
./configure --disable-examples ;
make ;
# TASK-037: as above -- flag-invariance-off has its own dedicated
# libmicrohttpd build step below.
if: ${{ matrix.os-type != 'windows' && matrix.build-type != 'no-dauth' && matrix.build-type != 'flag-invariance-off' && matrix.compiler-family != 'arm-cross' && steps.cache-libmicrohttpd.outputs.cache-hit != 'true' }}
- name: Build libmicrohttpd without digest auth (no-dauth test)
run: |
curl https://s3.amazonaws.com/libhttpserver/libmicrohttpd_releases/libmicrohttpd-1.0.3.tar.gz -o libmicrohttpd-1.0.3.tar.gz ;
echo "7816b57aae199cf5c3645e8770e1be5f0a4dfafbcb24b3772173dc4ee634126a libmicrohttpd-1.0.3.tar.gz" | sha256sum -c ;
tar -xzf libmicrohttpd-1.0.3.tar.gz ;
cd libmicrohttpd-1.0.3 ;
./configure --disable-examples --disable-dauth ;
make ;
if: ${{ matrix.build-type == 'no-dauth' }}
- name: Build libmicrohttpd with all features off (TASK-037 flag-invariance-off lane)
run: |
curl https://s3.amazonaws.com/libhttpserver/libmicrohttpd_releases/libmicrohttpd-1.0.3.tar.gz -o libmicrohttpd-1.0.3.tar.gz ;
echo "7816b57aae199cf5c3645e8770e1be5f0a4dfafbcb24b3772173dc4ee634126a libmicrohttpd-1.0.3.tar.gz" | sha256sum -c ;
tar -xzf libmicrohttpd-1.0.3.tar.gz ;
cd libmicrohttpd-1.0.3 ;
./configure --disable-examples --disable-bauth --disable-dauth --disable-websockets ;
make ;
if: ${{ matrix.build-type == 'flag-invariance-off' }}
- name: Install libmicrohttpd
run: cd libmicrohttpd-1.0.3 ; sudo make install ;
if: ${{ matrix.os-type != 'windows' && matrix.compiler-family != 'arm-cross' }}
- name: Verify digest auth is disabled (no-dauth test)
run: |
# Verify that MHD_queue_auth_fail_response is NOT present in libmicrohttpd
if nm /usr/local/lib/libmicrohttpd.so 2>/dev/null | grep -q MHD_queue_auth_fail_response; then
echo "ERROR: libmicrohttpd was built WITH digest auth support" ;
exit 1 ;
fi
echo "Verified: libmicrohttpd built without digest auth support" ;
if: ${{ matrix.build-type == 'no-dauth' }}
- name: Verify libmicrohttpd built without bauth/dauth/websockets (TASK-037 flag-invariance-off lane)
# TASK-037 / PRD-FLG-REQ-001: belt-and-braces check that the bespoke
# libmicrohttpd build above actually stripped the symbols that drive
# libhttpserver's HAVE_BAUTH / HAVE_DAUTH / HAVE_WEBSOCKET
# auto-detection. If any of these slipped back in, the configure
# step would (correctly) flip the corresponding HAVE_* back on and
# the lane would no longer be exercising the flag-off invariant.
run: |
fail=0 ;
for sym in MHD_basic_auth_get_username_password3 MHD_digest_auth_check3 MHD_queue_auth_fail_response; do
if nm /usr/local/lib/libmicrohttpd.so 2>/dev/null | grep -q "$sym"; then
echo "ERROR: $sym present in libmicrohttpd (expected absent)" ;
fail=1 ;
else
echo "Verified: $sym absent from libmicrohttpd" ;
fi ;
done ;
if ls /usr/local/lib/libmicrohttpd_ws* >/dev/null 2>&1; then
echo "ERROR: libmicrohttpd_ws present (expected absent)" ;
fail=1 ;
else
echo "Verified: libmicrohttpd_ws not built/installed" ;
fi ;
if [ "$fail" -ne 0 ]; then exit 1; fi
if: ${{ matrix.build-type == 'flag-invariance-off' }}
- name: Build and install libmicrohttpd (Windows)
if: ${{ matrix.os-type == 'windows' }}
run: |
curl https://s3.amazonaws.com/libhttpserver/libmicrohttpd_releases/libmicrohttpd-1.0.3.tar.gz -o libmicrohttpd-1.0.3.tar.gz
echo "7816b57aae199cf5c3645e8770e1be5f0a4dfafbcb24b3772173dc4ee634126a libmicrohttpd-1.0.3.tar.gz" | sha256sum -c
tar -xzf libmicrohttpd-1.0.3.tar.gz
cd libmicrohttpd-1.0.3
./configure --disable-examples --enable-poll=no
make
make install
- name: Fetch libmicrohttpd from cache (ARM cross-compile)
id: cache-libmicrohttpd-arm
uses: actions/cache@v4
with:
path: libmicrohttpd-1.0.3-${{ matrix.build-type }}
key: ${{ matrix.os }}-${{ matrix.build-type }}-libmicrohttpd-1.0.3-cross-compiled
if: ${{ matrix.compiler-family == 'arm-cross' }}
- name: Cross-compile libmicrohttpd for ARM
run: |
curl https://s3.amazonaws.com/libhttpserver/libmicrohttpd_releases/libmicrohttpd-1.0.3.tar.gz -o libmicrohttpd-1.0.3.tar.gz
echo "7816b57aae199cf5c3645e8770e1be5f0a4dfafbcb24b3772173dc4ee634126a libmicrohttpd-1.0.3.tar.gz" | sha256sum -c
tar -xzf libmicrohttpd-1.0.3.tar.gz
mv libmicrohttpd-1.0.3 libmicrohttpd-1.0.3-${{ matrix.build-type }}
cd libmicrohttpd-1.0.3-${{ matrix.build-type }}
mkdir -p ${{ github.workspace }}/arm-sysroot
if [ "${{ matrix.build-type }}" = "arm32" ]; then
./configure --host=arm-linux-gnueabihf --prefix=${{ github.workspace }}/arm-sysroot --disable-examples --disable-doc
else
./configure --host=aarch64-linux-gnu --prefix=${{ github.workspace }}/arm-sysroot --disable-examples --disable-doc
fi
make
make install
if: ${{ matrix.compiler-family == 'arm-cross' && steps.cache-libmicrohttpd-arm.outputs.cache-hit != 'true' }}
- name: Install cross-compiled libmicrohttpd from cache
run: |
cd libmicrohttpd-1.0.3-${{ matrix.build-type }}
mkdir -p ${{ github.workspace }}/arm-sysroot
make install
if: ${{ matrix.compiler-family == 'arm-cross' && steps.cache-libmicrohttpd-arm.outputs.cache-hit == 'true' }}
- name: Refresh links to shared libs
run: sudo ldconfig ;
if: ${{ matrix.os-type == 'ubuntu' }}
- name: Run cpplint on code
run: cpplint --extensions=cpp,hpp --headers=hpp --recursive . ;
if: ${{ matrix.build-type == 'lint' && matrix.os-type == 'ubuntu' }}
- name: Run libhttpserver configure
run: |
# Set memory check flags. They need to stay in step as env variables don't propagate across steps.
# TASK-038: CXXFLAGS (NOT CXXLAGS) is the autoconf-recognized var
# that gets passed to the C++ compiler. A long-standing typo left
# C++ TUs uninstrumented under asan/msan/lsan/tsan/ubsan — the
# runtime libs were linked but the code itself was compiled
# without -fsanitize=..., so the sanitizers were no-ops on the
# library. The fix is a single missing 'F' per line.
if [ "$BUILD_TYPE" = "asan" ]; then export CFLAGS='-fsanitize=address'; export CXXFLAGS='-fsanitize=address'; export LDFLAGS='-fsanitize=address'; fi
if [ "$BUILD_TYPE" = "msan" ]; then export CFLAGS='-fsanitize=memory'; export CXXFLAGS='-fsanitize=memory'; export LDFLAGS='-fsanitize=memory'; fi
if [ "$BUILD_TYPE" = "lsan" ]; then export CFLAGS='-fsanitize=leak'; export CXXFLAGS='-fsanitize=leak'; export LDFLAGS='-fsanitize=leak'; fi
if [ "$BUILD_TYPE" = "tsan" ]; then export CFLAGS='-fsanitize=thread'; export CXXFLAGS='-fsanitize=thread'; export LDFLAGS='-fsanitize=thread'; fi
if [ "$BUILD_TYPE" = "ubsan" ]; then export CFLAGS='-fsanitize=undefined'; export CXXFLAGS='-fsanitize=undefined'; export LDFLAGS='-fsanitize=undefined'; fi
# Additional flags on mac. They need to stay in step as env variables don't propagate across steps.
if [ "${{ matrix.os }}" = "macos-latest" ]; then
export CFLAGS='-mtune=generic' ;
export IPV6_TESTS_ENABLED="true" ;
fi
./bootstrap ;
mkdir build ;
cd build ;
if [ "${{ matrix.compiler-family }}" = "arm-cross" ]; then
export CPPFLAGS="-I${{ github.workspace }}/arm-sysroot/include"
export LDFLAGS="-L${{ github.workspace }}/arm-sysroot/lib"
export PKG_CONFIG_PATH="${{ github.workspace }}/arm-sysroot/lib/pkgconfig"
if [ "${{ matrix.build-type }}" = "arm32" ]; then
../configure --host=arm-linux-gnueabihf --disable-fastopen;
else
../configure --host=aarch64-linux-gnu --disable-fastopen;
fi
elif [ "$LINKING" = "static" ]; then
../configure --enable-static --disable-fastopen;
elif [ "$DEBUG" = "debug" ] && [ "$COVERAGE" = "coverage" ]; then
../configure --enable-debug --enable-coverage --disable-shared --disable-fastopen;
elif [ "$DEBUG" = "debug" ]; then
../configure --enable-debug --disable-shared --disable-fastopen;
elif [ "$BUILD_TYPE" = "valgrind" ]; then
../configure --enable-debug --disable-fastopen --disable-valgrind-helgrind --disable-valgrind-drd --disable-valgrind-sgcheck;
elif [ "$BUILD_TYPE" = "iwyu" ]; then
../configure --disable-examples;
else
../configure --disable-fastopen;
fi
- name: Verify libhttpserver detected no digest auth (no-dauth test)
run: |
cd build ;
if grep -q "Digest Auth.*:.*no" config.log; then
echo "Verified: libhttpserver correctly detected digest auth is disabled" ;
else
echo "ERROR: libhttpserver did not detect that digest auth is disabled" ;
grep "Digest Auth" config.log || echo "Digest Auth line not found" ;
exit 1 ;
fi
if: ${{ matrix.build-type == 'no-dauth' }}
- name: Verify libhttpserver detected all features off (TASK-037 flag-invariance-off lane)
# TASK-037 / PRD-FLG-REQ-001 / arch §9 testing item 2. Asserts that
# configure auto-detected every HAVE_* feature as off in this lane;
# if any of them are 'yes', the lane wouldn't actually be exercising
# the flag-off invariant and we want the matrix to go red loudly.
run: |
cd build ;
fail=0 ;
for feat in "TLS Enabled" "Basic Auth" "Digest Auth" "WebSocket"; do
if grep -qE "^ ${feat}[[:space:]]*:[[:space:]]*no$" config.log; then
echo "Verified: ${feat} is off" ;
else
echo "ERROR: ${feat} is NOT off in this configuration" ;
grep "${feat}" config.log || echo "${feat} line not found" ;
fail=1 ;
fi ;
done ;
if [ "$fail" -ne 0 ]; then exit 1; fi
if: ${{ matrix.build-type == 'flag-invariance-off' }}
- name: Print config.log
shell: bash
run: |
cd build ;
cat config.log ;
if: ${{ failure() }}
# Make or run iwyu. If running iwyu, check for the result code to be 2 (IWYU always returns an error code, if it is 2, no corrections are necessary).
- name: Make or run IWYU
run: |
# IWYU always return an error code. If it returns "2" it indicates a success so we manage this within the function below.
function safe_make_iwyu() {
{
make -k CXX='/usr/local/bin/include-what-you-use -Xiwyu --mapping_file=${top_builddir}/../custom_iwyu.imp' CXXFLAGS="-std=c++20 -DHTTPSERVER_COMPILATION -D_REENTRANT $CXXFLAGS" ;
} || {
if [ $? -ne 2 ]; then
return 1;
else
return 0;
fi
}
return 0;
}
cd build ;
if [ "$BUILD_TYPE" = "iwyu" ]; then
safe_make_iwyu ;
else
make ;
fi
- name: Build consumer fixture (TASK-037 build-flag invariance gate)
# TASK-037 / PRD-FLG-REQ-001 / arch §9 testing item 2. The headline
# gate: the same test/consumer_fixture.cpp (which touches every
# previously HAVE_*-gated public symbol) must compile + link in
# both the all-features-on and all-features-off configurations.
# The matrix entries skip the broad `make check` / `cppcheck` steps
# below -- this single fixture compile + link is the build-flag-
# invariance assertion.
run: |
cd build ;
make -C test consumer_fixture ;
if: ${{ matrix.build-type == 'flag-invariance-on' || matrix.build-type == 'flag-invariance-off' }}
- name: Run tests
run: |
cd build ;
make check;
# TASK-037: flag-invariance-{on,off} are compile/link-only gates, so
# skip the full `make check` (which spins up real servers and would
# crash on the OFF lane for the BAUTH/DAUTH/WS unit tests anyway).
if: ${{ matrix.build-type != 'iwyu' && matrix.compiler-family != 'arm-cross' && matrix.build-type != 'header-hygiene' && matrix.build-type != 'flag-invariance-on' && matrix.build-type != 'flag-invariance-off' }}
- name: Run header-hygiene check
# TASK-007: dedicated public-header hygiene gate. Runs the
# preprocessor-grep target (Layer 2) against a staged install and
# reports any forbidden backend headers reaching <httpserver.hpp>.
# Currently informational (HEADER_HYGIENE_STRICT=no) -- TASK-020
# flips this to strict when M5 closes the umbrella.
run: |
cd build
make check-hygiene
if: ${{ matrix.build-type == 'header-hygiene' }}
- name: Print tests results
shell: bash
run: |
cd build ;
cat test/test-suite.log ;
if: ${{ failure() && matrix.build-type != 'iwyu' && matrix.compiler-family != 'arm-cross' }}
- name: Run Valgrind checks
run: |
cd build ;
make check-valgrind ;
if: ${{ matrix.build-type == 'valgrind' }}
- name: Print Valgrind memcheck results
shell: bash
run: |
cd build ;
if [ -f test/test-suite-memcheck.log ]; then
cat test/test-suite-memcheck.log ;
fi
if: ${{ always() && matrix.build-type == 'valgrind' }}
- name: Run cppcheck
run: |
cd src/ ;
cppcheck --error-exitcode=1 . ;
# TASK-037: flag-invariance lanes are minimal gates -- skip cppcheck.
if: ${{ matrix.os-type == 'ubuntu' && matrix.compiler-family != 'arm-cross' && matrix.build-type != 'flag-invariance-on' && matrix.build-type != 'flag-invariance-off' }}
- name: Run performance tests (select)
run: |
cd build
cd examples
./benchmark_select 8080 $(nproc) &
sleep 5 && ab -n 1000000 -c 100 127.0.0.1:8080/plaintext
if: ${{ matrix.build-type == 'select' }}
- name: Run performance tests (nodelay)
run: |
cd build
cd examples
./benchmark_nodelay 8080 $(nproc) &
sleep 5 && ab -n 1000000 -c 100 127.0.0.1:8080/plaintext
if: ${{ matrix.build-type == 'nodelay' }}
- name: Run performance tests (threads)
run: |
cd build
cd examples
./benchmark_threads 8080 &
sleep 5 && ab -n 1000000 -c 100 127.0.0.1:8080/plaintext
if: ${{ matrix.build-type == 'threads' }}
- name: Generate coverage report
run: |
cd build
gcovr --root .. --filter '../src/' --xml coverage.xml --xml-pretty --print-summary --gcov-ignore-parse-errors=negative_hits.warn_once_per_file
if: ${{ matrix.os-type == 'ubuntu' && matrix.c-compiler == 'gcc' && matrix.debug == 'debug' && matrix.coverage == 'coverage' && success() }}
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: build/coverage.xml
fail_ci_if_error: false
if: ${{ matrix.os-type == 'ubuntu' && matrix.c-compiler == 'gcc' && matrix.debug == 'debug' && matrix.coverage == 'coverage' && success() }}