Skip to content

Conversation

@Aadharsh-Rajkumar
Copy link

@Aadharsh-Rajkumar Aadharsh-Rajkumar commented Oct 13, 2025

User description

Description

A solution for consolidating dependency installation commands for different operating systems (for macOS, Debian/Ubuntu, RedHat/CentOS). Allows minimal repetition in command installations in multiple CI workflow files. CI logs on which commands are being run.

Fixes #660

Type of change

  • [Yes] New feature (non-breaking change which adds functionality)

Scope

  • [Yes] This PR comprises a set of related changes with a common goal

How Has This Been Tested?

By running these two commands:

  1. chmod +x ./scripts/install_dependencies.sh
  2. ./scripts/install_dependencies.sh

I was only able to test on a macOS system so for other OS like ubuntu and RedHat tests still need to be done.

Checklist

  • [ Yes] I have added comments for the new code
  • I added Doxygen docstrings to the new code
  • I have made corresponding changes to the documentation (docs/)
  • I have added regression tests to the test suite so that people can verify in the future that the feature is behaving as expected
  • I have added example cases in examples/ that demonstrate my new feature performing as expected.
    They run to completion and demonstrate "interesting physics"
  • I ran ./mfc.sh format before committing my code
  • [ Yes] New and existing tests pass locally with my changes, including with GPU capability enabled (both NVIDIA hardware with NVHPC compilers and AMD hardware with CRAY compilers) and disabled
  • [ Yes] This PR does not introduce any repeated code (it follows the DRY principle)
  • [ Yes] I cannot think of a way to condense this code and reduce any introduced additional line count

I left unchecked boxes for things that I did not find relevant for this issue which was a shell script and not a Fortran or C++ file.


PR Type

Enhancement


Description

  • Consolidate OS-specific dependency installation into unified script

  • Replace inline CI workflow setup with centralized install_dependencies.sh

  • Support macOS, Debian/Ubuntu, and RedHat/CentOS with conditional logic

  • Add dependency verification executable and enforce LF line endings


Diagram Walkthrough

flowchart LR
  A["CI Workflow"] -->|calls| B["install_dependencies.sh"]
  B -->|detects OS| C["macOS<br/>Debian/Ubuntu<br/>RedHat/CentOS"]
  C -->|installs| D["Dependencies<br/>cmake, gcc, boost, etc."]
  D -->|verifies| E["dependency_check executable"]
Loading

File Walkthrough

Relevant files
Enhancement
install_dependencies.sh
Cross-platform dependency installation script                       

scripts/install_dependencies.sh

  • New bash script that detects OS and installs appropriate dependencies
  • Supports macOS with Homebrew, Debian/Ubuntu with apt, RedHat/CentOS
    with yum
  • Includes conditional Intel OneAPI installation for Ubuntu CI
    environments
  • Performs verification checks and sets environment variables for CI
+153/-0 
test.yml
Refactor CI workflow to use unified installer                       

.github/workflows/test.yml

  • Replace 45+ lines of OS-specific setup steps with unified script call
  • Consolidate macOS, Ubuntu, and Intel setup into single
    install_dependencies.sh invocation
  • Add verification step to confirm key dependencies installed correctly
  • Simplify workflow by removing redundant package manager commands
+12/-30 
CMakeLists.txt
Add dependency verification executable target                       

CMakeLists.txt

  • Add dependency_check executable target for CI verification
  • Find and link Boost package as required dependency
  • Include Boost headers for dependency verification checks
+9/-0     
Configuration changes
.gitattributes
Enforce consistent LF line endings across file types         

.gitattributes

  • Enforce LF line endings for shell scripts (.sh files)
  • Enforce LF line endings for Fortran source files (.fpp, .f90)
  • Maintain existing linguist-generated settings for tests and toolchain
+5/-2     

@qodo-merge-pro
Copy link
Contributor

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

🎫 Ticket compliance analysis 🔶

660 - Partially compliant

Compliant requirements:

  • Consolidate duplicated CI steps that install build dependencies into a single, reusable mechanism.
  • Ensure dependencies include recent additions like FFTW.
  • Make the solution usable across different OS environments used in CI (e.g., macOS, Debian/Ubuntu, RedHat/CentOS).
  • Reduce repetition across multiple workflow files while keeping logs of executed commands.
  • Optionally expose the installer for users to run locally.

Non-compliant requirements:

  • None

Requires further human verification:

  • Verify the script integrates into CI workflows (GitHub Actions) and actually replaces duplicated code in those files.
  • Validate on real runners for Ubuntu and RedHat/CentOS to ensure package names and versions resolve correctly.
  • Confirm FFTW and OpenMPI linkage works for the project build on all platforms after install.
⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Possible Issue

Using OSTYPE for macOS detection but uname-derived variable OS for logging may cause misleading output; also, Homebrew path is hardcoded to /opt/homebrew (Apple Silicon) and may fail on Intel Macs without fallback.

OS="$(uname -s)"
echo "Installing dependencies for $OS OS"

# macOS
if [[ "$OSTYPE" == "darwin"* ]]; then
    # Use Homebrew for macOS package management
    echo "Detected macOS."
    export PATH="/opt/homebrew/bin:/opt/homebrew/sbin:$PATH"
    brew update
Portability

On RedHat/CentOS, the script installs cmake3 but does not provide a cmake symlink; downstream scripts expecting 'cmake' may fail. Consider creating a symlink or checking for both.

# Install all required packages (this time with openmpi and fftw)
pkgs="tar wget make cmake3 gcc gcc-c++ python3 openmpi fftw protobuf boost-devel"
sudo yum install -y $pkgs

# Verification
echo "Verifying installations..."
cmake3 --version || echo "cmake3 not found"
gcc --version || echo "gcc not found"
python3 --version || echo "python3 not found"
Robustness

Unconditional 'set -euo pipefail' with verification commands that intentionally fail can stop the script despite '|| echo'; ensure each verification command cannot trigger 'set -e' termination or group them safely.

# Verification
echo "Verifying installations..."
which cmake; cmake --version
which gcc; gcc --version
which python3; python3 --version
brew list boost || echo "boost not found"
brew list protobuf || echo "protobuf not found"

Comment on lines 64 to 70
# Verification
echo "Verifying installations..."
cmake --version || echo "cmake not found"
gcc --version || echo "gcc not found"
python3 --version || echo "python3 not found"
mpirun --version || echo "mpirun not found"
ldconfig -p | grep -q libfftw3 || echo "FFTW library not found"
Copy link
Contributor

@qodo-merge-pro qodo-merge-pro bot Oct 13, 2025

Choose a reason for hiding this comment

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

Suggestion: Replace the command || echo constructs in the verification steps with if ! command; then echo; fi blocks. This ensures the custom error messages are displayed correctly when set -e is active. [possible issue, importance: 7]

Suggested change
# Verification
echo "Verifying installations..."
cmake --version || echo "cmake not found"
gcc --version || echo "gcc not found"
python3 --version || echo "python3 not found"
mpirun --version || echo "mpirun not found"
ldconfig -p | grep -q libfftw3 || echo "FFTW library not found"
# Verification
echo "Verifying installations..."
if ! cmake --version; then echo "cmake not found"; fi
if ! gcc --version; then echo "gcc not found"; fi
if ! python3 --version; then echo "python3 not found"; fi
if ! mpirun --version; then echo "mpirun not found"; fi
if ! ldconfig -p | grep -q libfftw3; then echo "FFTW library not found"; fi

Comment on lines 33 to 42
# Install missing packages
for exe in "${!packages[@]}"; do
formula="${packages[$exe]}"
if ! command -v "$exe" >/dev/null 2>&1; then
echo "Installing $formula..."
brew install --verbose "$formula"
else
echo "$exe already installed"
fi
done
Copy link
Contributor

@qodo-merge-pro qodo-merge-pro bot Oct 13, 2025

Choose a reason for hiding this comment

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

Suggestion: Modify the macOS package check to use brew list instead of command -v. This correctly detects installed Homebrew libraries like boost and protobuf, preventing unnecessary reinstallations. [possible issue, importance: 8]

Suggested change
# Install missing packages
for exe in "${!packages[@]}"; do
formula="${packages[$exe]}"
if ! command -v "$exe" >/dev/null 2>&1; then
echo "Installing $formula..."
brew install --verbose "$formula"
else
echo "$exe already installed"
fi
done
# Install missing packages
for exe in "${!packages[@]}"; do
formula="${packages[$exe]}"
if ! brew list --formula | grep -q "^${formula%%@*}$"; then
echo "Installing $formula..."
brew install --verbose "$formula"
else
echo "$formula already installed"
fi
done

@sbryngelson
Copy link
Member

Can you test any of the others via VMs? Otherwise, it's really hard to know if this 'works' or not. Also, try to make a PR change that involves the source code!

@sbryngelson
Copy link
Member

This PR introduces a script but doesn't point the user to it, nor use it in CI, anywhere. Marking as draft as it's clearly incomplete.

@sbryngelson sbryngelson marked this pull request as draft October 13, 2025 14:34
- scripts/install_dependencies.sh: installs required dependencies on CI
- .github/workflows/test.yml: updated workflow to call the install_dependencies.sh script
- CMakeLists.txt: added dependency check/integration for CI
@Aadharsh-Rajkumar
Copy link
Author

Update as of 10/19:

  1. Tested in Git Bash for Unix and WSL and ensured that the dependencies were correctly satisfied.
  2. Used the shell script in the github actions workflow through /workflows/test.yml. Updated this to reference install_dependencies and call it at the start of the CI workflow.
  3. Updated CMakeLists.txt to perform a dependency check during build.
  4. Created a mock m_thermochem with stubbed functions as the real module was not available locally. This allowed me to actually build the entire project locally without errors, and I ran 'make' to ensure the build completed.

Files included:

  • scripts/install_dependencies.sh: Installs all required system dependencies for CI builds.
  • .github/workflows/test.yml: Calls the install_dependencies.sh script in the CI workflow.
  • CMakeLists.txt: Integrates the dependency check into the build process.
  • Updated .gitattributes: Fixes file ending issue with ubuntu/linux in WSL

@Aadharsh-Rajkumar Aadharsh-Rajkumar marked this pull request as ready for review October 19, 2025 04:40
@Aadharsh-Rajkumar Aadharsh-Rajkumar requested a review from a team as a code owner October 19, 2025 04:40
@qodo-merge-pro
Copy link
Contributor

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

🎫 Ticket compliance analysis ✅

660 - PR Code Verified

Compliant requirements:

  • Consolidate duplicated CI steps that install/build MFC dependencies across workflows.
  • Provide a single, reusable mechanism to install dependencies across OSs.
  • Cover at least macOS and Ubuntu; RedHat/CentOS support would be beneficial.
  • Include missing dependencies like fftw in the consolidated solution.
  • Make it easy to update dependencies in one place when they change.

Requires further human verification:

  • Verify the script works on Ubuntu and RedHat/CentOS runners (author notes only macOS tested).
  • Ensure all CI jobs and other workflows call the new script where relevant (only test.yml shown here).
⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 No relevant tests
🔒 Security concerns

Download and repository trust:
The Intel OneAPI install path uses wget of a GPG key and apt-key add, which is deprecated and weakens supply chain protections. Prefer fetching keys via HTTPS with fingerprint verification and using signed-by in sources.list.d.

⚡ Recommended focus areas for review

Possible Issue

On macOS the script writes to GITHUB_ENV unconditionally; when run locally, GITHUB_ENV may be unset, causing redirection to an empty path or failure. Guard appends with a check for GITHUB_ENV existence.

# Environment setup
echo "FC=gfortran-15" >> "$GITHUB_ENV"
echo "BOOST_INCLUDE=/opt/homebrew/include/" >> "$GITHUB_ENV"

echo "macOS dependencies installed successfully."
Robustness

Debian/Ubuntu branch uses deprecated apt-key and add-apt-repository for Intel OneAPI. These may fail on newer runners. Consider using signed-by with sources.list.d and official installation scripts.

# Install all required packages (this time with openmpi and fftw)
if [[ "${CI_INTEL:-false}" == "true" ]]; then
    echo "Intel OneAPI environment detected. Installing Intel compilers and MPI..."
    wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB
    $SUDO apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB
    $SUDO add-apt-repository "deb https://apt.repos.intel.com/oneapi all main"
    $SUDO apt-get update
    $SUDO apt-get install -y intel-oneapi-compiler-fortran intel-oneapi-mpi intel-oneapi-mpi-devel
    source /opt/intel/oneapi/setvars.sh
    if [[ -n "${GITHUB_ENV:-}" ]]; then
        echo "source /opt/intel/oneapi/setvars.sh" >> "$GITHUB_ENV"
    fi
    printenv >> "$GITHUB_ENV"
    echo "Intel OneAPI installation completed."
else
Ordering

Python is set up after dependency verification. Some tools might rely on a specific Python before checks. Consider moving setup-python before verification to avoid path/version mismatches.

- name: Verify dependency installation
  run: |
    cmake --version
    gcc --version
    python3 --version

- name: Set up Python 3.13
  uses: actions/setup-python@v5
  with:
    python-version: '3.13'

Copy link
Contributor

Choose a reason for hiding this comment

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

High-level Suggestion

The dependency_check executable should be removed from the main CMakeLists.txt because it is only used for CI. Instead, the dependency verification should be handled directly within the install_dependencies.sh script. [High-level, importance: 8]

Solution Walkthrough:

Before:

# In CMakeLists.txt
# ... (main project configuration)

# Small dependency-check executable (used by CI to verify deps like Boost)
find_package(Boost REQUIRED)
add_executable(dependency_check examples/dependency_check/dependency_check.cpp)
target_include_directories(dependency_check PRIVATE ${Boost_INCLUDE_DIRS})

# No check inside install_dependencies.sh

After:

# In CMakeLists.txt
# ... (main project configuration)
# The dependency_check executable and related find_package(Boost) are removed.

# In scripts/install_dependencies.sh
# ... (after installing dependencies)
echo "Verifying Boost dependency by compiling a test file..."
cat <<EOF > /tmp/boost_check.cpp
#include <boost/version.hpp>
#include <iostream>
int main() { std::cout << "Boost version: " << BOOST_LIB_VERSION << std::endl; return 0; }
EOF
g++ /tmp/boost_check.cpp -o /tmp/boost_check $(pkg-config --cflags --libs boost || echo "-I${Boost_INCLUDE_DIRS}")
/tmp/boost_check

if [[ "${CI_INTEL:-false}" == "true" ]]; then
echo "Intel OneAPI environment detected. Installing Intel compilers and MPI..."
wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB
$SUDO apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB
Copy link
Contributor

@qodo-merge-pro qodo-merge-pro bot Oct 19, 2025

Choose a reason for hiding this comment

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

Suggestion: Replace the deprecated apt-key command with the modern, secure method of managing APT keys. Store the GPG key in /etc/apt/keyrings and reference it from a dedicated sources list file. [security, importance: 8]

Suggested change
$SUDO apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB
$SUDO install -m 0644 GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB /etc/apt/keyrings/intel-archive-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/intel-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main" | $SUDO tee /etc/apt/sources.list.d/oneapi.list > /dev/null

Comment on lines 104 to 108
source /opt/intel/oneapi/setvars.sh
if [[ -n "${GITHUB_ENV:-}" ]]; then
echo "source /opt/intel/oneapi/setvars.sh" >> "$GITHUB_ENV"
fi
printenv >> "$GITHUB_ENV"
Copy link
Contributor

@qodo-merge-pro qodo-merge-pro bot Oct 19, 2025

Choose a reason for hiding this comment

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

Suggestion: Correct the method for persisting environment variables from setvars.sh in the GitHub Actions environment. Instead of dumping all variables with printenv, capture and append only the variables modified by the script to $GITHUB_ENV. [possible issue, importance: 10]

Suggested change
source /opt/intel/oneapi/setvars.sh
if [[ -n "${GITHUB_ENV:-}" ]]; then
echo "source /opt/intel/oneapi/setvars.sh" >> "$GITHUB_ENV"
fi
printenv >> "$GITHUB_ENV"
# Create a temporary file to store the environment before sourcing
env > /tmp/env_before
# Source the Intel script to set variables for the current shell
source /opt/intel/oneapi/setvars.sh
# Compare the environment before and after, and append only the new/changed variables to GITHUB_ENV
if [[ -n "${GITHUB_ENV:-}" ]]; then
diff --unchanged-line-format="" --old-line-format="" --new-line-format="%L" <(sort /tmp/env_before) <(env | sort) >> "$GITHUB_ENV"
fi
rm /tmp/env_before

Comment on lines 133 to 134
pkgs="tar wget make cmake3 gcc gcc-c++ python3 openmpi fftw protobuf boost-devel"
$SUDO yum install -y $pkgs
Copy link
Contributor

@qodo-merge-pro qodo-merge-pro bot Oct 19, 2025

Choose a reason for hiding this comment

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

Suggestion: Add missing development packages (-devel) to the yum installation list for RedHat/CentOS. The current list lacks headers and libraries for openmpi, fftw, protobuf, and python3, which are required for compilation. [possible issue, importance: 9]

Suggested change
pkgs="tar wget make cmake3 gcc gcc-c++ python3 openmpi fftw protobuf boost-devel"
$SUDO yum install -y $pkgs
pkgs="tar wget make cmake3 gcc gcc-c++ python3-devel openmpi openmpi-devel fftw fftw-devel protobuf protobuf-devel boost-devel"
$SUDO yum install -y $pkgs

@sbryngelson
Copy link
Member

very cool! keep going... seems to be almost there

@Aadharsh-Rajkumar
Copy link
Author

Update as of 10/24:

macOS:

  • Ensures Homebrew packages are installed (coreutils, python, fftw, hdf5, gcc@15, boost, open-mpi, lapack, cmake, protobuf).
  • Added brew link --overwrite for critical libraries to prevent path issues.
  • Safely sets FC=gfortran-15 and BOOST_INCLUDE in GITHUB_ENV.

Debian/Ubuntu:

  • Installs standard GNU toolchain + FFTW, Boost, Protobuf, OpenMPI.
  • Intel OneAPI conditional installation preserved.

RHEL/CentOS:

  • Installs necessary packages with fallback for cmake3 vs cmake.

Boost verification: Compiles a tiny program with safe fallbacks if Boost include paths are unknown.

@sbryngelson
Copy link
Member

This seems to be going the wrong direction, and now you've replaced the CMakeLists with something entirely different. Not sure what's going on.

…and added suggested fixes for dependency installer
@Aadharsh-Rajkumar
Copy link
Author

Update as of 10/27:

I undid the past commit and have implemented all suggestions, most importantly Boost compile checks and secure APT key handling. I have tested both on MacOS and Ubuntu through WSL.

Specific Key Changes:

  • Secure apt key handling for Intel OneAPI (stores GPG key under /etc/apt/keyrings and uses signed-by).
  • Uses brew list checks to detect Homebrew formulae (avoids reinstalls for boost/protobuf).
  • Appends environment variables to $GITHUB_ENV only when present.
  • Adds a Boost compile-check instead of a CI-only CMake target.
  • CI workflow: Setup Python 3.13 before running the dependency verification and installer.
  • Removed CI-only dependency_check executable and find_package from the main CMakeLists (bot recommended keeping CI verification in the installer script instead of the project CMake).

@sbryngelson
Copy link
Member

I think this might be the wrong project for you, thanks for your interest but I'm closing this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

CI duplicates code to build MFC

2 participants