Skip to content
Closed
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
7 changes: 5 additions & 2 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
/tests/**/* linguist-generated=true
/toolchain/mechanisms/* linguist-generated=true
*.fpp text eol=lf
*.f90 text eol=lf
*.sh text eol=lf
/tests/**/* linguist-generated=true
/toolchain/mechanisms/* linguist-generated=true
37 changes: 10 additions & 27 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,34 +53,17 @@ jobs:
with:
python-version: '3.13'

- name: Setup MacOS
if: matrix.os == 'macos'
run: |
brew update
brew upgrade
brew install coreutils python fftw hdf5 gcc@15 boost open-mpi lapack
echo "FC=gfortran-15" >> $GITHUB_ENV
echo "BOOST_INCLUDE=/opt/homebrew/include/" >> $GITHUB_ENV

- name: Setup Ubuntu
if: matrix.os == 'ubuntu' && matrix.intel == false
run: |
sudo apt update -y
sudo apt install -y cmake gcc g++ python3 python3-dev hdf5-tools \
libfftw3-dev libhdf5-dev openmpi-bin libopenmpi-dev \
libblas-dev liblapack-dev
- name: Make dependency installer executable
run: chmod +x ./scripts/install_dependencies.sh

- name: Setup Ubuntu (Intel)
if: matrix.os == 'ubuntu' && matrix.intel == true
run: |
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
printenv >> $GITHUB_ENV
- name: Run dependency installer
run: ./scripts/install_dependencies.sh

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

- name: Build
run: |
Expand Down Expand Up @@ -135,4 +118,4 @@ jobs:
if: matrix.lbl == 'frontier'
with:
name: logs-${{ strategy.job-index }}-${{ matrix.device }}
path: test-${{ matrix.device }}.out
path: test-${{ matrix.device }}.out
15 changes: 12 additions & 3 deletions CMakeLists.txt
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

Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ if (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
$<$<COMPILE_LANGUAGE:Fortran>:-fprofile-arcs>
$<$<COMPILE_LANGUAGE:Fortran>:-ftest-coverage>
$<$<COMPILE_LANGUAGE:Fortran>:-O1>
)
)

add_link_options(
$<$<COMPILE_LANGUAGE:Fortran>:-lgcov>
Expand All @@ -148,7 +148,7 @@ if (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
-Wunderflow
-Wrealloc-lhs
-Wsurprising
)
)
endif()

if (CMAKE_Fortran_COMPILER_VERSION VERSION_GREATER 10)
Expand Down Expand Up @@ -195,7 +195,7 @@ elseif ((CMAKE_Fortran_COMPILER_ID STREQUAL "NVHPC") OR (CMAKE_Fortran_COMPILER_
add_compile_options(
$<$<COMPILE_LANGUAGE:Fortran>:-Mfreeform>
$<$<COMPILE_LANGUAGE:Fortran>:-cpp>
$<$<COMPILE_LANGUAGE:Fortran>:-Minfo=inline>
$<$<COMPILE_LANGUAGE:Fortran>:-Minfo=inline>
$<$<COMPILE_LANGUAGE:Fortran>:-Minfo=accel>
)

Expand Down Expand Up @@ -715,3 +715,12 @@ site_name(SITE_NAME)
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/toolchain/cmake/configuration.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/configuration.txt")

# -------------------------
# 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)
# make sure compiler sees Boost headers
target_include_directories(dependency_check PRIVATE ${Boost_INCLUDE_DIRS})
# don't force any link libraries: we use Boost header macros only
# -------------------------
206 changes: 206 additions & 0 deletions scripts/install_dependencies.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
#!/bin/bash
# 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.

# Instructions:
# 1. Run this command: chmod +x ./scripts/install_dependencies.sh
# 2. Run the installer: ./scripts/install_dependencies.sh

set -euo pipefail
set -x

SUDO=${SUDO:-sudo}
CI_INTEL=${CI_INTEL:-false}

log() { echo ">>> $*"; }

# Guarded append to GITHUB_ENV (safe when running locally)
append_to_github_env() {
local line="$1"
if [[ -n "${GITHUB_ENV:-}" ]]; then
printf '%s\n' "$line" >> "$GITHUB_ENV"
else
printf '%s\n' "$line"
fi
}

verify_tool() {
local t="$1"
if command -v "$t" >/dev/null 2>&1; then
"$t" --version 2>&1 | head -n1 || true
else
echo "$t not found"
fi
}

# macOS / Homebrew
install_macos() {
log "Detected macOS"

if ! command -v brew >/dev/null 2>&1; then
log "Homebrew not found. Please install Homebrew first."
return 1
fi

export PATH="/opt/homebrew/bin:/opt/homebrew/sbin:$PATH"
brew update
brew upgrade || true

pkgs=(coreutils python fftw hdf5 gcc@15 boost open-mpi lapack cmake protobuf)

for pkg in "${pkgs[@]}"; do
# Use brew list to detect installed formulae (correct for lib-only formulae)
if ! brew list --formula | grep -q "^${pkg%%@*}$"; then
log "Installing ${pkg}..."
brew install "${pkg}" || brew reinstall "${pkg}" || log "Failed to install ${pkg} (continuing)"
else
log "${pkg} already installed"
fi
done

# Attempt to fix common Homebrew linking quirks
brew link --overwrite python || true
brew link --overwrite boost || true
brew link --overwrite hdf5 || true
brew link --overwrite cmake || true
brew link --overwrite protobuf || true

# Export useful environment vars in GH Actions only (guarded)
append_to_github_env "FC=gfortran-15"
append_to_github_env "BOOST_INCLUDE=/opt/homebrew/include/"

log "Verifying installations..."
# Use guarded verification so script doesn't exit on set -e for these checks
if ! verify_tool cmake >/dev/null 2>&1; then echo "cmake not found"; fi
if ! verify_tool gcc >/dev/null 2>&1; then echo "gcc not found"; fi
if ! verify_tool gfortran >/dev/null 2>&1; then echo "gfortran not found"; fi
if ! verify_tool python3 >/dev/null 2>&1; then echo "python3 not found"; fi
if ! verify_tool mpirun >/dev/null 2>&1; then echo "mpirun not found"; fi

if brew list --formula | grep -q "^fftw$"; then
echo "FFTW library found"
else
echo "FFTW library not found"
fi

log "macOS dependencies installed successfully."
}

# Debian / Ubuntu
install_debian() {
log "Detected Debian/Ubuntu"

$SUDO apt-get update -y
$SUDO apt-get install -y build-essential wget tar cmake python3 python3-dev pkg-config

if [[ "${CI_INTEL}" == "true" ]]; then
log "Intel OneAPI: adding repo with signed-by keyring (secure method)"
# download key and install to /etc/apt/keyrings (modern secure approach)
wget -q https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB -O /tmp/intel-pubkey.PUB
$SUDO mkdir -p /etc/apt/keyrings
$SUDO install -m 0644 /tmp/intel-pubkey.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
$SUDO apt-get update -y
$SUDO apt-get install -y intel-oneapi-compiler-fortran intel-oneapi-mpi intel-oneapi-mpi-devel || log "Intel packages failed; continuing"

# capture environment changes made by Intel setvars.sh and append only deltas to GITHUB_ENV
if [[ -f /opt/intel/oneapi/setvars.sh ]]; then
env > /tmp/env_before
source /opt/intel/oneapi/setvars.sh || log "sourcing Intel setvars.sh failed"
if [[ -n "${GITHUB_ENV:-}" ]]; then
# append only newly added / changed env vars
diff --unchanged-line-format="" --old-line-format="" --new-line-format="%L" <(sort /tmp/env_before) <(env | sort) >> "$GITHUB_ENV" || true
fi
rm -f /tmp/env_before
fi
fi

# Install common dev packages including fftw/openmpi/protobuf/boost
$SUDO apt-get install -y libfftw3-dev libopenmpi-dev openmpi-bin libprotobuf-dev protobuf-compiler libboost-all-dev

log "Verifying installations..."
if ! verify_tool cmake >/dev/null 2>&1; then echo "cmake not found"; fi
if ! verify_tool gfortran >/dev/null 2>&1; then echo "gfortran not found"; fi
if ! verify_tool python3 >/dev/null 2>&1; then echo "python3 not found"; fi
if ! verify_tool mpirun >/dev/null 2>&1; then echo "mpirun not found"; fi
if ! ldconfig -p | grep -q libfftw3; then echo "FFTW library not found"; fi
}

# RHEL / CentOS
install_rhel() {
log "Detected RHEL/CentOS"

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 || $SUDO dnf install -y $pkgs || log "yum/dnf install failed"

log "Verifying installations..."
if command -v cmake3 >/dev/null 2>&1; then
verify_tool cmake3
elif command -v cmake >/dev/null 2>&1; then
verify_tool cmake
else
echo "cmake not found"
fi

if ! verify_tool gfortran >/dev/null 2>&1; then echo "gfortran not found"; fi
if ! verify_tool python3 >/dev/null 2>&1; then echo "python3 not found"; fi
if ! verify_tool mpirun >/dev/null 2>&1; then echo "mpirun not found"; fi
if ! ldconfig -p | grep -q libfftw3; then echo "FFTW library not found"; fi
}

# Boost compile check
boost_check() {
log "Verifying Boost by compiling a tiny program..."
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

# Try pkg-config first (if available)
if command -v pkg-config >/dev/null 2>&1 && pkg-config --exists boost; then
g++ /tmp/boost_check.cpp -o /tmp/boost_check $(pkg-config --cflags --libs boost) || true
else
# Try a plain compile (system include path), fallback to /opt/homebrew/include
if g++ /tmp/boost_check.cpp -o /tmp/boost_check 2>/dev/null; then
true
else
if [[ -d /opt/homebrew/include ]]; then
g++ -I/opt/homebrew/include /tmp/boost_check.cpp -o /tmp/boost_check || true
else
log "Could not compile boost_check; boost include path unknown"
fi
fi
fi

if [[ -x /tmp/boost_check ]]; then
/tmp/boost_check || true
else
log "boost_check binary not available"
fi
}

# Main entry
main() {
case "$(uname -s)" in
Darwin)
install_macos
;;
*)
if [[ -f /etc/debian_version ]]; then
install_debian
elif [[ -f /etc/redhat-release ]] || [[ -f /etc/centos-release ]]; then
install_rhel
else
log "Unsupported OS: $OSTYPE"
return 1
fi
;;
esac

boost_check
log "Done."
}

main "$@"