Contributing to ewcalc
July 11, 2026 · View on GitHub
Workflow
- Branch off
main(e.g.feat/<short-description>,fix/<short-description>). - Open a pull request against
main. CI (.github/workflows/ci.yml) must pass:build-windows,build-macos,build-linux,sanitizers,static-analysis, andcoverage. - PRs are squash-merged. The squash commit message is
<PR title> (#<PR number>)(seegit logfor examples, e.g.v0.9.0 — Infrastructure & Hardening (#36)). - Releases follow a squash-merged milestone PR, then a separate
chore: bump version to vX.Y.Zcommit and tag onmain. Add a matching entry toCHANGELOG.md.
Build prerequisites
See AGENTS.md for per-platform prerequisites (CMake, compiler, and
per-frontend toolchain requirements) and the macOS Homebrew-LLVM caveat under
"Session Start". Don't duplicate that guidance here — it's kept in one place
to avoid drift.
Running tests
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --parallel
ctest --test-dir build -C Release --output-on-failure
Each test file compiles to its own executable under build/bin/tests/
(e.g. build/bin/tests/test_antenna) and can be run directly.
Sanitizer, static analysis, and coverage builds
These mirror the sanitizers, static-analysis, and coverage jobs in
.github/workflows/ci.yml. Run them locally before opening a PR that touches
libew or ewpresenter:
Sanitizers (ASan/UBSan):
cmake -B build-san -DEWCALC_BUILD_TESTS=ON -DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_CXX_FLAGS="-fsanitize=address,undefined -fno-sanitize-recover=all -fno-omit-frame-pointer" \
-DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address,undefined"
cmake --build build-san --parallel
ctest --test-dir build-san --output-on-failure
Static analysis (clang-tidy + cppcheck): clang-tidy uses the repo's
.clang-tidy config (WarningsAsErrors set, so any enabled-check violation
fails the run):
cmake -B build-lint -DEWCALC_BUILD_TESTS=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
find libew/src ewpresenter/src -name '*.cpp' -print0 | xargs -0 clang-tidy -p build-lint
cppcheck --enable=warning,style,performance,portability \
--std=c++20 --language=c++ --inline-suppr --error-exitcode=1 \
-I libew/include -I ewpresenter/include libew/src ewpresenter/src
Coverage (Clang/llvm-cov, 75% line-coverage gate):
cmake -B build-cov -DEWCALC_BUILD_TESTS=ON -DEWCALC_BUILD_COVERAGE=ON \
-DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
cmake --build build-cov --parallel
ctest --test-dir build-cov --output-on-failure
See the coverage job in .github/workflows/ci.yml for the llvm-profdata/llvm-cov
report-generation steps.
Code style
- C++20,
-Wall -Wextra -Wpedantic -Werror(GCC/Clang) or/W4 /WX /permissive-(MSVC). #pragma oncein every header.- No external dependencies in
libeworewpresenter. - Use
libew::unitsstrong types (Dbm,Db,Km,Mhz, …) for every RF quantity inlibewandewpresenter— never a baredouble. - Document public API headers with Doxygen-style
///comments (@file,@brief,@param,@return), matching the existing headers underlibew/include/libew/.
Adding a new calculator
Follow the three-layer pattern used by every existing domain. The antenna
domain is a complete, working example to copy from at each layer:
libew— addlibew/include/libew/<domain>/<domain>.h(Doxygen-commented,libew::unitstypes only) andlibew/src/<domain>.cpp. Addlibew/tests/test_<domain>.cppusing the framework inlibew/tests/test_main.h(TEST_MAIN(),RUN_TEST,ASSERT_NEAR,ASSERT_TRUE), with a// Source: ...comment above each formula's test block. Compare againstlibew/include/libew/antenna/antenna.h,libew/src/antenna.cpp, andlibew/tests/test_antenna.cpp.ewpresenter— addewpresenter/include/ewpresenter/<domain>_presenter.handewpresenter/src/<domain>_presenter.cpp, following thePresenterBase<Derived>pattern (seeewpresenter/include/ewpresenter/presenter_base.handewpresenter/include/ewpresenter/antenna_presenter.h): validated setters, arecompute()that callslibewand fills anOutputstruct with formatted strings, and anon_changecallback.- Per-platform adapter/view — reference the antenna implementation on
each platform:
- macOS:
frontend/macos/app/Adapters/AntennaAdapter.swift,frontend/macos/app/Views/AntennaView.swift. - Windows:
frontend/windows/ewcalc-winui/ewpresenter.net/AntennaAdapter.cpp/.h(C++/CLI bridge),frontend/windows/ewcalc-winui/ewcalc-winui/ViewModels/AntennaViewModel.cs,.../Views/AntennaPage.xaml. - Linux:
frontend/linux/src/pages/AntennaPage.cpp/.h(Qt6).
- macOS:
- If the macOS frontend needs the new domain, also add functions to the
plain-C
bridge/ewcalc_bridge.h/.cppAPI and cover them inewpresenter/tests/test_bridge.cpp.