Skip to content

Commit 68cd267

Browse files
committed
Added docs to cmake build
1 parent 2780ca4 commit 68cd267

18 files changed

+2223
-68
lines changed

.github/copilot-instructions.md

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@ Quick orientation (big picture)
1414

1515
What to assume when editing/building
1616
- SCHISM is expected to be pre-built. The build system requires `SCHISM_BUILD_DIR` to point
17-
to a SCHISM build (contains `include/` and `lib/` with `libhydro.a` etc.). See `CMakeLists.txt`.
17+
to a SCHISM build (contains `include/` and `lib/` with SCHISM libraries). See `CMakeLists.txt`.
18+
Required SCHISM libraries: `libcore.a`, `libhydro.a`, `libturbulence.a`, `libyaml.a`, `libparmetis.a`, `libmetis.a`
1819
- ESMF is discovered via an `esmf.mk` file; provide it via the environment variable `ESMFMKFILE`
1920
(or let `cmake/FindESMF.cmake` locate it). The CMake helper `cmake/FindESMF.cmake` parses the
2021
ESMF makefile and exposes include/lib variables and an `ESMF::ESMF` target.
22+
- **CRITICAL**: ESMF must be built with real MPI support (`ESMF_COMM=mpich` or `openmpi`), NOT `mpiuni` (MPI stub).
23+
Check with: `grep ESMF_COMM $ESMFMKFILE`
2124

2225
Build and test commands (concrete)
2326
- Fast: set env vars, configure, build
@@ -28,8 +31,13 @@ Build and test commands (concrete)
2831
cmake ..
2932
cmake --build . -- -j$(nproc)
3033
```
31-
- **macOS-specific**: use Homebrew-installed gfortran and explicitly set the Fortran compiler
34+
- **macOS-specific**: Install ESMF with MPI support, use Homebrew/conda gfortran
3235
```bash
36+
# Install ESMF with MPI (choose one MPI implementation)
37+
mamba install -c conda-forge "esmf=8.9.0=mpi_mpich*"
38+
# or
39+
mamba install -c conda-forge "esmf=8.9.0=mpi_openmpi*"
40+
3341
export ESMFMKFILE=/path/to/esmf.mk
3442
export SCHISM_BUILD_DIR=/path/to/schism/build
3543
mkdir -p build && cd build
@@ -44,10 +52,17 @@ Build and test commands (concrete)
4452

4553
CI-ready checklist (for automated builds)
4654
1. Ensure `ESMFMKFILE` points to a valid `esmf.mk` (check existence: `test -f "$ESMFMKFILE"`).
47-
2. Ensure `SCHISM_BUILD_DIR` points to a pre-built SCHISM (check lib: `test -f "$SCHISM_BUILD_DIR/lib/libhydro.a"`).
48-
3. Set `CMAKE_Fortran_COMPILER` to an MPI-aware wrapper (e.g., `mpif90`, `esmpifort`) — CMake will warn if you use a bare compiler.
49-
4. Run CMake configure with explicit compiler flags and capture stderr for "FATAL_ERROR" or "WARNING" messages.
50-
5. Run `cmake --build . -- VERBOSE=1` to see full compile/link commands and catch missing symbols early.
55+
2. **Verify ESMF has MPI support**: `grep ESMF_COMM "$ESMFMKFILE" | grep -v mpiuni` (must show `mpich` or `openmpi`).
56+
3. Ensure `SCHISM_BUILD_DIR` points to a pre-built SCHISM with all required libraries:
57+
```bash
58+
test -f "$SCHISM_BUILD_DIR/lib/libhydro.a" && \
59+
test -f "$SCHISM_BUILD_DIR/lib/libcore.a" && \
60+
test -f "$SCHISM_BUILD_DIR/lib/libturbulence.a" && \
61+
test -f "$SCHISM_BUILD_DIR/lib/libyaml.a"
62+
```
63+
4. Set `CMAKE_Fortran_COMPILER` to an MPI-aware wrapper (e.g., `mpif90`, `esmpifort`) — CMake will warn if you use a bare compiler.
64+
5. Run CMake configure with explicit compiler flags and capture stderr for "FATAL_ERROR" or "WARNING" messages.
65+
6. Run `cmake --build . -- VERBOSE=1` to see full compile/link commands and catch missing symbols early.
5166
6. Optional: run a quick smoke test by executing `./main_esmf --help` or similar (if applicable) to verify linkage.
5267

5368
**Automated validation**: Run `.github/test-cmake-instructions.sh` to validate your environment against this checklist.
@@ -64,7 +79,13 @@ Important patterns & conventions
6479
modules directory (`CMAKE_Fortran_MODULE_DIRECTORY` configured to `build/modules`). When adding
6580
new modules, ensure consumers see the `target_include_directories(...)` or that targets are linked
6681
in the correct CMake subdirectory (see `src/CMakeLists.txt`).
67-
- SCHISM libraries expected in `${SCHISM_BUILD_DIR}/lib` with names found by `find_library` for `core` and `hydro`.
82+
- **Shared source pattern**: Common Fortran sources used by multiple targets (e.g., `schism_bmi.F90`,
83+
`schism_esmf_util.F90`) are compiled once in a separate library (`schism_interface_common`) to avoid
84+
parallel build race conditions. See `src/schism/CMakeLists.txt` for the pattern.
85+
- SCHISM dependency chain: CMake discovers and links in this order:
86+
1. SCHISM core libraries: `libcore.a`, `libhydro.a`
87+
2. SCHISM dependencies: `libturbulence.a`, `libyaml.a`, `libparmetis.a`, `libmetis.a`
88+
3. MPI libraries: `find_package(MPI REQUIRED)` provides `${MPI_Fortran_LIBRARIES}`
6889
- Optional integrations: PDAF (data assimilation) and MOSSCO are optional — guard changes so they compile
6990
when absent. See `scripts/Readme.md` and `src/` subdirs referencing PDAF and MOSSCO.
7091

@@ -97,4 +118,4 @@ If anything here is unclear or you'd like me to expand a section (build matrix,
97118

98119
### Style to consider
99120

100-
Always use camelcase for naming the ReadMe.md files in each directory.
121+
Always use camelcase for naming the ReadMe.md files in each directory. Same with BuildTroubleshooting.md and TestReadMe.md and other markdown files.

.github/test-cmake-instructions.sh

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,24 @@ else
101101
version=$(grep "ESMF_VERSION_STRING" "$ESMFMKFILE" | head -1 | cut -d= -f2 | tr -d ' ')
102102
print_test INFO "ESMF Version" "$version"
103103
fi
104+
105+
# Check ESMF_COMM (critical for build success)
106+
if grep -q "ESMF_COMM" "$ESMFMKFILE"; then
107+
esmf_comm=$(grep "^ESMF_COMM=" "$ESMFMKFILE" | head -1 | cut -d= -f2 | tr -d ' ')
108+
print_test INFO "ESMF MPI Implementation" "$esmf_comm"
109+
110+
if [[ "$esmf_comm" == "mpiuni" ]] || [[ "$esmf_comm" =~ "nompi" ]]; then
111+
print_test FAIL "ESMF has real MPI support" "ESMF_COMM=$esmf_comm (stub MPI, not compatible with SCHISM)"
112+
print_test INFO "Fix (conda)" "mamba install -c conda-forge 'esmf=*=mpi_mpich*'"
113+
print_test INFO "Fix (spack)" "spack install esmf+mpi"
114+
elif [[ "$esmf_comm" == "mpich" ]] || [[ "$esmf_comm" == "openmpi" ]]; then
115+
print_test PASS "ESMF has real MPI support" "$esmf_comm"
116+
else
117+
print_test WARN "ESMF MPI implementation unknown" "$esmf_comm"
118+
fi
119+
else
120+
print_test FAIL "ESMF_COMM variable found" "Cannot determine MPI implementation"
121+
fi
104122
else
105123
print_test FAIL "esmf.mk appears invalid" "Missing ESMF_VERSION_MAJOR"
106124
fi
@@ -144,11 +162,103 @@ else
144162
if [[ -f "$SCHISM_BUILD_DIR/lib/libcore.a" ]]; then
145163
print_test PASS "libcore.a exists"
146164
else
147-
print_test WARN "libcore.a exists" "Optional library not found"
165+
print_test FAIL "libcore.a exists" "Core library not found"
166+
fi
167+
168+
# Check for additional required dependencies
169+
required_libs=("libturbulence.a" "libyaml.a")
170+
optional_libs=("libparmetis.a" "libmetis.a")
171+
172+
missing_required=()
173+
for lib in "${required_libs[@]}"; do
174+
if [[ -f "$SCHISM_BUILD_DIR/lib/$lib" ]]; then
175+
print_test PASS "$lib exists"
176+
else
177+
print_test FAIL "$lib exists" "Required dependency not found"
178+
missing_required+=("$lib")
179+
fi
180+
done
181+
182+
missing_optional=()
183+
for lib in "${optional_libs[@]}"; do
184+
if [[ -f "$SCHISM_BUILD_DIR/lib/$lib" ]]; then
185+
print_test PASS "$lib exists"
186+
else
187+
print_test WARN "$lib exists" "Optional library not found (may cause link errors)"
188+
missing_optional+=("$lib")
189+
fi
190+
done
191+
192+
if [[ ${#missing_required[@]} -gt 0 ]] || [[ ${#missing_optional[@]} -gt 0 ]]; then
193+
print_test INFO "Available SCHISM libraries" "$(ls -1 $SCHISM_BUILD_DIR/lib/*.a 2>/dev/null | xargs -n1 basename || echo 'none')"
194+
if [[ ${#missing_required[@]} -gt 0 ]]; then
195+
print_test INFO "Fix" "Rebuild SCHISM with: cmake ../src && make"
196+
fi
148197
fi
149198
fi
150199
echo ""
151200

201+
# ========================================
202+
# Test 2.5: Check MPI Libraries
203+
# ========================================
204+
echo "Test 2.5: MPI Library Availability"
205+
echo "-----------------------------------"
206+
207+
# Try to find MPI libraries
208+
mpi_found=false
209+
mpi_impl=""
210+
211+
if command -v mpirun &> /dev/null || command -v mpiexec &> /dev/null; then
212+
print_test PASS "MPI runtime found"
213+
mpi_found=true
214+
215+
# Detect MPI implementation
216+
if command -v mpichversion &> /dev/null; then
217+
mpi_impl="MPICH"
218+
mpi_version=$(mpichversion 2>/dev/null || echo "unknown")
219+
print_test INFO "MPI Implementation" "$mpi_impl $mpi_version"
220+
elif command -v ompi_info &> /dev/null; then
221+
mpi_impl="OpenMPI"
222+
mpi_version=$(ompi_info --version 2>/dev/null | head -1 || echo "unknown")
223+
print_test INFO "MPI Implementation" "$mpi_impl $mpi_version"
224+
else
225+
print_test INFO "MPI Implementation" "Unknown (mpirun found)"
226+
fi
227+
else
228+
print_test WARN "MPI runtime found" "mpirun/mpiexec not in PATH"
229+
fi
230+
231+
# Check for MPI libraries in common locations
232+
mpi_lib_found=false
233+
if [[ -n "${CONDA_PREFIX:-}" ]]; then
234+
if ls "$CONDA_PREFIX/lib"/libmpi*.dylib &>/dev/null || ls "$CONDA_PREFIX/lib"/libmpi*.so &>/dev/null; then
235+
print_test PASS "MPI libraries found in conda environment"
236+
mpi_lib_found=true
237+
print_test INFO "MPI library path" "$CONDA_PREFIX/lib"
238+
fi
239+
elif [[ -n "${SPACK_ROOT:-}" ]]; then
240+
# Spack environment - MPI should be in PATH
241+
print_test INFO "Spack environment detected" "MPI from spack load"
242+
mpi_lib_found=true
243+
else
244+
# Check system locations
245+
for libdir in /usr/lib /usr/local/lib /opt/local/lib /opt/homebrew/lib; do
246+
if [[ -d "$libdir" ]] && (ls "$libdir"/libmpi*.so &>/dev/null || ls "$libdir"/libmpi*.dylib &>/dev/null); then
247+
print_test PASS "MPI libraries found" "$libdir"
248+
mpi_lib_found=true
249+
break
250+
fi
251+
done
252+
fi
253+
254+
if ! $mpi_lib_found && ! $mpi_found; then
255+
print_test FAIL "MPI libraries available" "No MPI installation detected"
256+
print_test INFO "Fix (conda)" "mamba install -c conda-forge mpich or openmpi"
257+
print_test INFO "Fix (system)" "Install OpenMPI or MPICH via package manager"
258+
fi
259+
260+
echo ""
261+
152262
# ========================================
153263
# Test 3: Check Fortran compiler
154264
# ========================================

.github/test-examples.sh

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#!/usr/bin/env bash
2+
# SPDX-FileCopyrightText: 2025 Helmholtz-Zentrum Hereon
3+
# SPDX-License-Identifier: CC0-1.0
4+
#
5+
# Example: How to use the CMake test framework
6+
7+
# This script demonstrates typical usage patterns for the test framework
8+
9+
echo "=========================================="
10+
echo "CMake Test Framework - Usage Examples"
11+
echo "=========================================="
12+
echo ""
13+
14+
# Example 1: Basic test (assumes env vars are set)
15+
echo "Example 1: Basic Test"
16+
echo "---------------------"
17+
echo "Prerequisites: ESMFMKFILE and SCHISM_BUILD_DIR must be set"
18+
echo ""
19+
echo "Command:"
20+
echo " .github/test-cmake-instructions.sh"
21+
echo ""
22+
23+
# Example 2: Set env vars inline
24+
echo "Example 2: Set Environment Variables Inline"
25+
echo "--------------------------------------------"
26+
echo "Command:"
27+
echo " ESMFMKFILE=/opt/esmf/lib/esmf.mk \\"
28+
echo " SCHISM_BUILD_DIR=/path/to/schism/build \\"
29+
echo " .github/test-cmake-instructions.sh"
30+
echo ""
31+
32+
# Example 3: macOS with explicit compilers
33+
echo "Example 3: macOS with Homebrew Compilers"
34+
echo "-----------------------------------------"
35+
echo "Command:"
36+
echo " export CMAKE_Fortran_COMPILER=\$(brew --prefix gcc)/bin/gfortran"
37+
echo " export CMAKE_C_COMPILER=\$(brew --prefix gcc)/bin/gcc"
38+
echo " export ESMFMKFILE=/opt/esmf/lib/esmf.mk"
39+
echo " export SCHISM_BUILD_DIR=~/schism/build"
40+
echo " .github/test-cmake-instructions.sh"
41+
echo ""
42+
43+
# Example 4: Run only environment checks (skip CMake config)
44+
echo "Example 4: Quick Environment Check"
45+
echo "-----------------------------------"
46+
echo "To check only env vars without running CMake config,"
47+
echo "temporarily unset one of the required variables:"
48+
echo ""
49+
echo "Command:"
50+
echo " SCHISM_BUILD_DIR=/nonexistent \\"
51+
echo " .github/test-cmake-instructions.sh"
52+
echo ""
53+
54+
# Example 5: Integration with build script
55+
echo "Example 5: Integration with Build Script"
56+
echo "-----------------------------------------"
57+
echo "#!/usr/bin/env bash"
58+
echo "set -e"
59+
echo ""
60+
echo "# Validate environment before building"
61+
echo ".github/test-cmake-instructions.sh"
62+
echo ""
63+
echo "# If tests pass, proceed with build"
64+
echo "mkdir -p build && cd build"
65+
echo "cmake .."
66+
echo "cmake --build . -- -j\$(nproc)"
67+
echo ""
68+
69+
# Example 6: CI/CD usage
70+
echo "Example 6: CI/CD Integration"
71+
echo "-----------------------------"
72+
echo "In your CI config file:"
73+
echo ""
74+
echo "GitHub Actions:"
75+
echo " - name: Validate build environment"
76+
echo " run: .github/test-cmake-instructions.sh"
77+
echo " env:"
78+
echo " ESMFMKFILE: \${{ env.ESMFMKFILE }}"
79+
echo " SCHISM_BUILD_DIR: \${{ env.SCHISM_BUILD_DIR }}"
80+
echo ""
81+
echo "GitLab CI:"
82+
echo " test:"
83+
echo " script:"
84+
echo " - .github/test-cmake-instructions.sh"
85+
echo ""
86+
87+
echo "=========================================="
88+
echo "For more details, see:"
89+
echo " .github/TEST_README.md"
90+
echo "=========================================="

.github/workflows/docs.yml

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
name: Docs
2+
3+
on:
4+
push:
5+
branches: [ main, cmake ]
6+
pull_request:
7+
branches: [ main, cmake ]
8+
workflow_dispatch:
9+
10+
permissions:
11+
contents: write
12+
13+
jobs:
14+
build-docs-cmake:
15+
name: "CMake docs build (DOCS_ONLY)"
16+
runs-on: ubuntu-latest
17+
steps:
18+
- name: Checkout
19+
uses: actions/checkout@v4
20+
21+
- name: Set up Python
22+
uses: actions/setup-python@v5
23+
with:
24+
python-version: '3.x'
25+
26+
- name: Install doc dependencies
27+
run: |
28+
python -m pip install --upgrade pip
29+
pip install mkdocs mkdocs-material
30+
31+
- name: Configure (DOCS_ONLY)
32+
run: |
33+
cmake -S . -B build -DDOCS_ONLY=ON -DBUILD_DOCS=ON
34+
35+
- name: Build docs target
36+
run: |
37+
cmake --build build --target docs -- -j2
38+
39+
- name: Archive built site (from CMake)
40+
if: always()
41+
uses: actions/upload-artifact@v4
42+
with:
43+
name: cmake-docs-site
44+
path: build/docs
45+
46+
deploy-docs:
47+
name: "Deploy MkDocs site to GitHub Pages"
48+
needs: build-docs-cmake
49+
if: github.event_name == 'push' && contains('refs/heads/main refs/heads/cmake', github.ref)
50+
runs-on: ubuntu-latest
51+
steps:
52+
- name: Checkout
53+
uses: actions/checkout@v4
54+
55+
- name: Set up Python
56+
uses: actions/setup-python@v5
57+
with:
58+
python-version: '3.x'
59+
60+
- name: Install doc dependencies
61+
run: |
62+
python -m pip install --upgrade pip
63+
pip install mkdocs mkdocs-material
64+
65+
- name: Build MkDocs site
66+
run: mkdocs build --strict
67+
68+
- name: Deploy to GitHub Pages
69+
uses: peaceiris/actions-gh-pages@v3
70+
with:
71+
github_token: ${{ secrets.GITHUB_TOKEN }}
72+
publish_dir: ./site
73+
publish_branch: gh-pages
74+
force_orphan: true

0 commit comments

Comments
 (0)