Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ jobs:
os: ['ubuntu', 'macos']
mpi: ['mpi']
precision: ['']
debug: ['debug', 'no-debug']
debug: ['reldebug', 'no-debug']
intel: [true, false]
exclude:
- os: macos
Expand Down Expand Up @@ -266,7 +266,7 @@ jobs:
/bin/bash mfc.sh test -v --max-attempts 3 -j $(nproc) $ONLY_CHANGES $TEST_ALL $TEST_PCT
env:
TEST_ALL: ${{ matrix.mpi == 'mpi' && '--test-all' || '' }}
TEST_PCT: ${{ matrix.debug == 'debug' && '-% 20' || '' }}
TEST_PCT: ${{ matrix.debug == 'reldebug' && '-% 20' || '' }}
ONLY_CHANGES: ${{ github.event_name == 'pull_request' && '--only-changes' || '' }}

self:
Expand Down
58 changes: 53 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,18 @@ if (MFC_ALL)
set(MFC_DOCUMENTATION ON FORCE)
endif()

# Validate CMAKE_BUILD_TYPE to catch typos (CMake is case-sensitive).
set(_VALID_BUILD_TYPES "Debug" "Release" "RelDebug" "")
if (NOT CMAKE_BUILD_TYPE IN_LIST _VALID_BUILD_TYPES)
message(FATAL_ERROR "Unknown CMAKE_BUILD_TYPE '${CMAKE_BUILD_TYPE}'. Valid: Debug, RelDebug, Release")
endif()

# RelDebug: a lighter debug mode for CI. Compiler-specific blocks below add the
# actual flags; these defaults just tell CMake it is a recognised build type.
set(CMAKE_C_FLAGS_RELDEBUG "-g" CACHE STRING "")
set(CMAKE_CXX_FLAGS_RELDEBUG "-g" CACHE STRING "")
set(CMAKE_Fortran_FLAGS_RELDEBUG "-g" CACHE STRING "")
Comment on lines +47 to +51
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'RelDebug config plumbing:\n'
rg -n 'RelDebug|RELDEBUG|CMAKE_CONFIGURATION_TYPES|CMAKE_MAP_IMPORTED_CONFIG_RELDEBUG|CMAKE_BUILD_TYPE' CMakeLists.txt toolchain/mfc/build.py

printf '\nWindows / multi-config hints:\n'
rg -n '\.sln|Visual Studio|--config|mfc\.bat' docs .github toolchain

Repository: MFlowCode/MFC

Length of output: 3934


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Checking for CMAKE_CONFIGURATION_TYPES usage ==="
rg -n 'CMAKE_CONFIGURATION_TYPES' CMakeLists.txt toolchain/

echo -e "\n=== Checking for Intel compiler ID variations ==="
rg -n 'IntelLLVM|CMAKE_.*_COMPILER_ID.*Intel|CMAKE_Fortran_COMPILER_ID' CMakeLists.txt

echo -e "\n=== Checking CMake generator selection in build.py ==="
rg -n 'CMAKE_GENERATOR|Visual Studio|Xcode|Ninja|Unix Makefiles' toolchain/mfc/build.py

echo -e "\n=== Full Intel block context (lines ~240-270) ==="
sed -n '230,280p' CMakeLists.txt

Repository: MFlowCode/MFC

Length of output: 109


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Checking for CMAKE_CONFIGURATION_TYPES usage ==="
rg -n 'CMAKE_CONFIGURATION_TYPES' CMakeLists.txt toolchain/ || echo "(not found)"

echo -e "\n=== Checking for Intel compiler ID variations ==="
rg -n 'IntelLLVM|CMAKE_Fortran_COMPILER_ID.*Intel' CMakeLists.txt || echo "(not found)"

echo -e "\n=== Checking CMake generator selection in build.py ==="
rg -n 'CMAKE_GENERATOR|Visual Studio|Xcode|Ninja' toolchain/mfc/build.py || echo "(not found)"

echo -e "\n=== Intel-specific block context (lines 230-280) ==="
sed -n '230,280p' CMakeLists.txt

Repository: MFlowCode/MFC

Length of output: 2591


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Workflow configuration (check for generator hints) ==="
rg -n 'CMAKE_GENERATOR|Visual Studio|Xcode|generator' .github/workflows/

echo -e "\n=== mfc.bat content (Windows build entry point) ==="
head -50 mfc.bat

echo -e "\n=== build.py generator handling ==="
sed -n '350,420p' toolchain/mfc/build.py

Repository: MFlowCode/MFC

Length of output: 115


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Workflow configuration (check for generator hints) ==="
rg -n 'CMAKE_GENERATOR|Visual Studio|Xcode|generator' .github/workflows/ || echo "(not found)"

echo -e "\n=== mfc.bat content (Windows build entry point) ==="
head -60 mfc.bat || echo "(mfc.bat not found or empty)"

echo -e "\n=== build.py CMake invocation (lines 350-420) ==="
sed -n '350,420p' toolchain/mfc/build.py

Repository: MFlowCode/MFC

Length of output: 4991


Verify RelDebug support on multi-config generators and add Intel oneAPI compiler ID.

Multi-config generators (Visual Studio, Xcode) will fail to use the custom RelDebug flags:

  • CMAKE_BUILD_TYPE is empty on multi-config generators, so the if(CMAKE_BUILD_TYPE STREQUAL "RelDebug") conditionals throughout the file will not fire (lines 240, 248, 259, 268, 333, 647)
  • CMAKE_CONFIGURATION_TYPES is never set, so RelDebug is not registered as a valid configuration
  • cmake --build --config RelDebug will use default flags instead of the custom ones, or fail

The code sets CMAKE_BUILD_TYPE (single-config only) but later passes --config (multi-config syntax) to the build command, suggesting both patterns were intended but not properly reconciled.

Additionally, the Intel Fortran block (line 243) only checks for CMAKE_Fortran_COMPILER_ID STREQUAL "Intel" but does not handle IntelLLVM, which is what Intel oneAPI (ifx) reports. If oneAPI is installed, the compiler ID will not match and flags will not be applied.

Suggested fixes:

  1. Add CMAKE_CONFIGURATION_TYPES registration for multi-config generators and use generator expressions instead of CMAKE_BUILD_TYPE conditionals, or
  2. Detect the generator type and apply platform-appropriate logic
  3. Extend the Intel block to also check for IntelLLVM:
elseif ((CMAKE_Fortran_COMPILER_ID STREQUAL "Intel") OR (CMAKE_Fortran_COMPILER_ID STREQUAL "IntelLLVM"))


if (MFC_SINGLE_PRECISION)
add_compile_definitions(MFC_SINGLE_PRECISION)
else()
Expand Down Expand Up @@ -83,7 +95,7 @@ elseif ((CMAKE_Fortran_COMPILER_ID STREQUAL "NVHPC") OR (CMAKE_Fortran_COMPILER_
message(FATAL_ERROR "ERROR: When using NVHPC, v21.7 or newer is required to build MFC.\n${__err_msg}")
endif()

if ((CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 24.5) AND (CMAKE_BUILD_TYPE STREQUAL "Debug") AND MFC_OpenACC)
if ((CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 24.5) AND (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelDebug") AND MFC_OpenACC)
message(FATAL_ERROR "ERROR: When using NVHPC, MFC with Debug and GPU options requires NVHPC v24.5 or newer.\n${__err_msg}")
endif()
elseif (CMAKE_Fortran_COMPILER_ID STREQUAL "AppleClang" OR CMAKE_C_COMPILER_ID STREQUAL "AppleClang")
Expand Down Expand Up @@ -165,13 +177,29 @@ if (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
-Wrealloc-lhs
-Wsurprising
)
elseif (CMAKE_BUILD_TYPE STREQUAL "RelDebug")
add_compile_options(
-Og
-Wall
-Wextra
-fcheck=bounds,pointer
-fbacktrace
-fimplicit-none
-fsignaling-nans
-finit-real=snan
-finit-integer=-99999999
-Wconversion
-Wintrinsic-shadow
-Wunderflow
-Wrealloc-lhs
-Wsurprising
)
endif()

if (CMAKE_Fortran_COMPILER_VERSION VERSION_GREATER 10)
add_compile_options(
$<$<COMPILE_LANGUAGE:Fortran>:-fallow-invalid-boz>
$<$<COMPILE_LANGUAGE:Fortran>:-fallow-argument-mismatch>
$<$<COMPILE_LANGUAGE:Fortran>:-fcheck=bounds>
)
endif()
elseif (CMAKE_Fortran_COMPILER_ID STREQUAL "Cray")
Expand All @@ -193,6 +221,13 @@ elseif (CMAKE_Fortran_COMPILER_ID STREQUAL "Cray")
"SHELL: -K trap=fp" "SHELL: -g" "SHELL: -O0"
)
add_link_options("SHELL: -K trap=fp" "SHELL: -g" "SHELL: -O0")
elseif (CMAKE_BUILD_TYPE STREQUAL "RelDebug")
add_compile_options(
"SHELL:-h acc_model=auto_async_none"
"SHELL: -h acc_model=no_fast_addr"
"SHELL: -K trap=fp" "SHELL: -g" "SHELL: -O1"
)
add_link_options("SHELL: -K trap=fp" "SHELL: -g" "SHELL: -O1")
endif()

elseif (CMAKE_Fortran_COMPILER_ID STREQUAL "Flang")
Expand All @@ -201,11 +236,17 @@ elseif (CMAKE_Fortran_COMPILER_ID STREQUAL "Flang")
$<$<COMPILE_LANGUAGE:Fortran>:-Mpreprocess>
$<$<COMPILE_LANGUAGE:Fortran>:-fdefault-real-8>
)

if (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelDebug")
add_compile_options($<$<COMPILE_LANGUAGE:Fortran>:-O1> $<$<COMPILE_LANGUAGE:Fortran>:-g>)
endif()
elseif (CMAKE_Fortran_COMPILER_ID STREQUAL "Intel")
add_compile_options($<$<COMPILE_LANGUAGE:Fortran>:-free>)

if (CMAKE_BUILD_TYPE STREQUAL "Debug")
add_compile_options(-g -Og -traceback -debug)
add_compile_options(-g -Og -traceback -debug -check all)
elseif (CMAKE_BUILD_TYPE STREQUAL "RelDebug")
add_compile_options(-g -Og -traceback -check bounds)
Comment on lines 246 to +249
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

For Intel oneAPI ifx, what value does CMake set in CMAKE_Fortran_COMPILER_ID: IntelorIntelLLVM?

💡 Result:

For Intel oneAPI ifx (LLVM-based Fortran compiler), CMake sets:

  • CMAKE_Fortran_COMPILER_ID = IntelLLVM (not Intel). [1], [2]

Sources: CMake Discourse example output showing “Fortran Compiler ID: IntelLLVM” when using ifx [1], and Intel’s oneAPI Fortran 2021 release notes stating ifx is supported with compiler id IntelLLVM (with CMake 3.20 + oneAPI HPC Toolkit 2021.2 on Linux). [2]


🏁 Script executed:

# Find and read the CMakeLists.txt file around lines 236-239 with full context
fd CMakeLists.txt | head -1 | xargs -I {} sh -c 'wc -l {} && echo "---" && head -n 260 {} | tail -n 50'

Repository: MFlowCode/MFC

Length of output: 2069


🏁 Script executed:

fd CMakeLists.txt | head -1 | xargs -I {} sh -c 'grep -n "CMAKE_Fortran_COMPILER_ID\|IntelLLVM\|Intel" {} | head -20'

Repository: MFlowCode/MFC

Length of output: 1532


🏁 Script executed:

fd CMakeLists.txt | head -1 | xargs -I {} sh -c 'sed -n "130,320p" {} | cat -n'

Repository: MFlowCode/MFC

Length of output: 9152


🏁 Script executed:

cd . && git log --oneline -1 2>/dev/null || echo "Not a git repo or git not available"
git diff HEAD -- CMakeLists.txt 2>/dev/null | grep -A 5 -B 5 "CMAKE_BUILD_TYPE.*RelDebug" | head -30 || echo "No git diff available"

Repository: MFlowCode/MFC

Length of output: 157


🏁 Script executed:

cd . && git show HEAD --stat | head -20

Repository: MFlowCode/MFC

Length of output: 1160


🏁 Script executed:

fd . -name "*.md" | xargs grep -l "ifx\|IntelLLVM\|oneAPI" 2>/dev/null | head -5

Repository: MFlowCode/MFC

Length of output: 287


🏁 Script executed:

fd ".*\.md$" | xargs grep -l "ifx\|IntelLLVM\|oneAPI" 2>/dev/null

Repository: MFlowCode/MFC

Length of output: 187


🏁 Script executed:

git show HEAD:CMakeLists.txt | grep -A 10 'CMAKE_Fortran_COMPILER_ID STREQUAL "Intel"'

Repository: MFlowCode/MFC

Length of output: 1349


The Intel conditional block needs to handle IntelLLVM compiler ID for ifx support.

CMake identifies Intel oneAPI's ifx compiler as CMAKE_Fortran_COMPILER_ID = "IntelLLVM", not "Intel". The current check at line 114 (elseif (CMAKE_Fortran_COMPILER_ID STREQUAL "Intel")) will not match ifx, causing the entire Intel-specific block—including the new RelDebug flags (-Og -traceback -check bounds)—to be skipped. Update the condition to also check for IntelLLVM:

elseif ((CMAKE_Fortran_COMPILER_ID STREQUAL "Intel") OR (CMAKE_Fortran_COMPILER_ID STREQUAL "IntelLLVM"))

endif()
elseif ((CMAKE_Fortran_COMPILER_ID STREQUAL "NVHPC") OR (CMAKE_Fortran_COMPILER_ID STREQUAL "PGI"))
add_compile_options(
Expand All @@ -224,6 +265,13 @@ elseif ((CMAKE_Fortran_COMPILER_ID STREQUAL "NVHPC") OR (CMAKE_Fortran_COMPILER_
$<$<COMPILE_LANGUAGE:Fortran>:-Minform=inform>
$<$<COMPILE_LANGUAGE:Fortran>:-Mbounds>
)
elseif (CMAKE_BUILD_TYPE STREQUAL "RelDebug")
add_compile_options(
$<$<COMPILE_LANGUAGE:Fortran>:-O1>
$<$<COMPILE_LANGUAGE:Fortran>:-g>
$<$<COMPILE_LANGUAGE:Fortran>:-traceback>
$<$<COMPILE_LANGUAGE:Fortran>:-Mbounds>
)
endif()

if (DEFINED ENV{MFC_CUDA_CC})
Expand Down Expand Up @@ -282,7 +330,7 @@ if (CMAKE_BUILD_TYPE STREQUAL "Release")
endif()
endif()

if (CMAKE_BUILD_TYPE STREQUAL "Debug")
if (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelDebug")
add_compile_definitions(MFC_DEBUG)
endif()

Expand Down Expand Up @@ -596,7 +644,7 @@ function(MFC_SETUP_TARGET)
)
endif()

if (CMAKE_BUILD_TYPE STREQUAL "Debug")
if (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelDebug")
target_compile_options(${a_target}
PRIVATE -gpu=debug
)
Expand Down
3 changes: 2 additions & 1 deletion docs/documentation/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ MFC can be built with support for various (compile-time) features:
| :----------------: | :---------: | :------------: | :-----: | --------------------------------------------------------------- |
| **MPI** | `--mpi` | `--no-mpi` | On | Allows MFC to run on multiple processors (and nodes). |
| **GPU** | `--gpu` | `--no-gpu` | Off | Enables GPU acceleration via OpenACC or OpenMP offload. |
| **Debug** | `--debug` | `--no-debug` | Off | Requests the compiler build MFC in debug mode. |
| **Debug** | `--debug` | `--no-debug` | Off | Full debug mode: all runtime checks, minimal optimization. |
| **RelDebug** | `--reldebug`| `--no-reldebug`| Off | Lightweight debug: key runtime checks, `-Og`/`-O1`. Used by CI.|
| **GCov** | `--gcov` | `--no-gcov` | Off | Build MFC with coverage flags on. |
| **Unified Memory** | `--unified` | `--no-unified` | Off | Build MFC with unified CPU/GPU memory (GH200 superchip only) |
| **Single** | `--single` | `--no-single` | Off | Build MFC in single precision |
Expand Down
37 changes: 30 additions & 7 deletions docs/documentation/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ This guide covers debugging tools, common issues, and troubleshooting workflows
| `-vv` | build, run, test | Full compiler/cmake output |
| `-vvv` | build | Add cmake dependency debugging |
| `-d` | all | Write debug log to file |
| `--debug` | build | Build with debug symbols |
| `--debug` | build | Full debug: all runtime checks, minimal optimization |
| `--reldebug` | build | Lightweight debug: key runtime checks, `-Og`/`-O1` |
| `--gcov` | build | Build with code coverage |
| `--no-gpu` | build | Disable GPU to isolate issues |
| `--no-mpi` | build | Disable MPI to isolate issues |
Expand Down Expand Up @@ -126,17 +127,39 @@ MFC supports three verbosity levels for builds:

### Debug Builds

Build with debug symbols for better error messages and debugging:
MFC has two debug build modes:

**Full Debug** (`--debug`) — for local development and deep investigation:

```bash
./mfc.sh build --debug
```

This sets `CMAKE_BUILD_TYPE=Debug`, which:
- Adds `-g` debug symbols
- Reduces optimization (`-O0` or `-O1`)
- Enables runtime checks in some compilers
- Makes stack traces more readable
Sets `CMAKE_BUILD_TYPE=Debug`. Enables all runtime checks (`-fcheck=all` on gfortran,
`-C` on NVHPC, `-K trap=fp` on Cray, `-check all` on Intel), minimizes optimization
(`-O0` or `-Og`), and adds debug symbols. Catches the widest range of bugs but runs
~5x slower than Release.

**RelDebug** (`--reldebug`) — lightweight debug used by CI:

```bash
./mfc.sh build --reldebug
```

Sets `CMAKE_BUILD_TYPE=RelDebug`. Keeps key runtime checks (compiler-dependent: bounds
and/or pointer checking, FP traps) and compile-time warnings, but uses `-Og`/`-O1`
and drops expensive checks like `do`, `mem`, and `recursion`. Runs ~2x faster than
full Debug while catching most real bugs. See the table below for exact flags per
compiler.

| Compiler | Full Debug (`--debug`) | RelDebug (`--reldebug`) |
|----------|----------------------|------------------------|
| gfortran | `-O0 -fcheck=all,no-array-temps` | `-Og -fcheck=bounds,pointer` |
| Intel ifx | `-Og -check all` | `-Og -check bounds` |
| NVHPC | `-O0 -C -Mbounds` | `-O1 -Mbounds` |
| Cray ftn | `-O0 -K trap=fp` | `-O1 -K trap=fp` |

Both modes define `MFC_DEBUG` and enable debug logging via `@:LOG()`.

### Code Coverage

Expand Down
13 changes: 13 additions & 0 deletions toolchain/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,19 @@ def __run():
# Setup debug logging if requested
setup_debug_logging(ARG("debug_log", dflt=None))

# --reldebug and --debug are mutually exclusive: if the user explicitly
# passed one, clear the other (which may be lingering from a prior run's
# persisted config).
if state.gARG.get("reldebug") and state.gARG.get("debug"):
# Determine which flag the user explicitly passed on this invocation
# by checking whether the persisted config already had it set.
if not state.gCFG.reldebug:
# User just passed --reldebug; clear persisted --debug
state.gARG["debug"] = False
else:
# User just passed --debug; clear persisted --reldebug
state.gARG["reldebug"] = False

lock.switch(state.MFCConfig.from_dict(state.gARG))

# Ensure IDE configuration is up to date (lightweight check)
Expand Down
19 changes: 16 additions & 3 deletions toolchain/mfc/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,9 @@ def is_buildable(self) -> bool:
return True

def configure(self, case: Case):
if ARG("debug") and ARG("reldebug"):
raise MFCException("--debug and --reldebug are mutually exclusive.")

build_dirpath = self.get_staging_dirpath(case)
cmake_dirpath = self.get_cmake_dirpath()
install_dirpath = self.get_install_dirpath(case)
Expand All @@ -383,9 +386,9 @@ def configure(self, case: Case):
# build the configured targets. This is mostly useful for debugging.
# See: https://cmake.org/cmake/help/latest/variable/CMAKE_EXPORT_COMPILE_COMMANDS.html.
"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON",
# Set build type (e.g Debug, Release, etc.).
# Set build type (Debug, RelDebug, or Release).
# See: https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html
f"-DCMAKE_BUILD_TYPE={'Debug' if ARG('debug') else 'Release'}",
f"-DCMAKE_BUILD_TYPE={'Debug' if ARG('debug') else 'RelDebug' if ARG('reldebug') else 'Release'}",
# Used by FIND_PACKAGE (/FindXXX) to search for packages, with the
# second highest level of priority, still letting users manually
# specify <PackageName>_ROOT, which has precedence over CMAKE_PREFIX_PATH.
Expand Down Expand Up @@ -455,7 +458,17 @@ def configure(self, case: Case):
def build(self, case: input.MFCInputFile):
case.generate_fpp(self)

command = ["cmake", "--build", self.get_staging_dirpath(case), "--target", self.name, "--parallel", ARG("jobs"), "--config", "Debug" if ARG("debug") else "Release"]
command = [
"cmake",
"--build",
self.get_staging_dirpath(case),
"--target",
self.name,
"--parallel",
ARG("jobs"),
"--config",
"Debug" if ARG("debug") else "RelDebug" if ARG("reldebug") else "Release",
]

verbosity = ARG("verbose")
# -vv or higher: add cmake --verbose flag for full compiler commands
Expand Down
5 changes: 3 additions & 2 deletions toolchain/mfc/cli/argparse_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,9 @@ def _add_mfc_config_arguments(parser: argparse.ArgumentParser, config):
)
parser.add_argument(f"--no-{f.name}", action="store_const", const=gpuConfigOptions.NONE.value, dest=f.name, help=f"Turn the {f.name} option OFF.")
else:
parser.add_argument(f"--{f.name}", action="store_true", help=f"Turn the {f.name} option ON.")
parser.add_argument(f"--no-{f.name}", action="store_false", dest=f.name, help=f"Turn the {f.name} option OFF.")
cli_name = f.name.replace("_", "-")
parser.add_argument(f"--{cli_name}", action="store_true", dest=f.name, help=f"Turn the {f.name} option ON.")
parser.add_argument(f"--no-{cli_name}", action="store_false", dest=f.name, help=f"Turn the {f.name} option OFF.")

parser.set_defaults(**{f.name: getattr(config, f.name) for f in dataclasses.fields(config)})

Expand Down
6 changes: 4 additions & 2 deletions toolchain/mfc/cli/docs_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ def _generate_options_table(cmd: Command, schema: CLISchema) -> List[str]:
if "mfc_config" in cmd.include_common:
lines.append("| `--mpi`, `--no-mpi` | Enable/disable MPI | `true` |")
lines.append("| `--gpu [acc/mp]`, `--no-gpu` | Enable GPU (OpenACC/OpenMP) | `no` |")
lines.append("| `--debug`, `--no-debug` | Build with debug compiler flags | `false` |")
lines.append("| `--debug`, `--no-debug` | Build with full debug compiler flags | `false` |")
lines.append("| `--reldebug`, `--no-reldebug` | Build with lightweight debug flags (CI) | `false` |")

lines.append("")

Expand Down Expand Up @@ -278,7 +279,8 @@ def generate_cli_reference(schema: CLISchema) -> str:
"|------|-------------|",
"| `--mpi` / `--no-mpi` | Enable/disable MPI support |",
"| `--gpu [acc/mp]` / `--no-gpu` | Enable GPU with OpenACC or OpenMP |",
"| `--debug` / `--no-debug` | Build with debug compiler flags |",
"| `--debug` / `--no-debug` | Build with full debug compiler flags |",
"| `--reldebug` / `--no-reldebug` | Build with lightweight debug flags (CI) |",
"| `--gcov` / `--no-gcov` | Enable code coverage |",
"| `--single` / `--no-single` | Single precision |",
"| `--mixed` / `--no-mixed` | Mixed precision |",
Expand Down
11 changes: 7 additions & 4 deletions toolchain/mfc/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class MFCConfig:
mpi: bool = True
gpu: str = gpuConfigOptions.NONE.value
debug: bool = False
reldebug: bool = False
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Normalize debug/reldebug before persisting config.

Because config is remembered across commands, debug and reldebug can both end up True (for example, after --debug and later --reldebug). toolchain/mfc/build.py then still selects Debug, while make_options() / make_slug() serialize a distinct configuration. That makes --reldebug silently ineffective and creates duplicate build/cache keys.

Also applies to: 47-63

gcov: bool = False
unified: bool = False
single: bool = False
Expand Down Expand Up @@ -43,21 +44,23 @@ def make_options(self) -> typing.List[str]:
Example: --no-debug --mpi --no-gpu --no-gcov --no-unified"""
options = []
for k, v in self.items():
cli_k = k.replace("_", "-")
if k == "gpu":
options.append(f"--{v}-{k}")
options.append(f"--{v}-{cli_k}")
else:
options.append(f"--{'no-' if not v else ''}{k}")
options.append(f"--{'no-' if not v else ''}{cli_k}")
return options

def make_slug(self) -> str:
"""Sort the items by key, then join them with underscores. This uniquely
identifies the configuration. Example: no-debug_no-gpu_no_mpi_no-gcov"""
options = []
for k, v in sorted(self.items(), key=lambda x: x[0]):
cli_k = k.replace("_", "-")
if k == "gpu":
options.append(f"--{v}-{k}")
options.append(f"--{v}-{cli_k}")
else:
options.append(f"--{'no-' if not v else ''}{k}")
options.append(f"--{'no-' if not v else ''}{cli_k}")
return "_".join(options)

def __eq__(self, other) -> bool:
Expand Down
Loading