build(installer): added compile version checking

This commit is contained in:
2025-07-29 10:54:49 -04:00
parent 8318a07aec
commit 7ceb997b7d
3 changed files with 235 additions and 98 deletions

View File

@@ -1,5 +1,6 @@
cppad_inc = include_directories('include', is_system: true)
cppad_dep = declare_dependency( cppad_dep = declare_dependency(
include_directories: include_directories('include'), include_directories: cppad_inc,
) )
message('Registering CppAD headers for installation...') message('Registering CppAD headers for installation...')

View File

@@ -3,7 +3,7 @@
# install.sh - Comprehensive interactive installation script for GridFire. # install.sh - Comprehensive interactive installation script for GridFire.
# #
# This script performs the following actions: # This script performs the following actions:
# 1. Checks for essential system dependencies. # 1. Checks for essential system dependencies against required minimum versions.
# 2. If run with the --tui flag, it provides a comprehensive text-based user interface # 2. If run with the --tui flag, it provides a comprehensive text-based user interface
# to select and install dependencies, configure the build, and run build steps. # to select and install dependencies, configure the build, and run build steps.
# 3. If run without flags, it prompts the user interactively for each missing dependency. # 3. If run without flags, it prompts the user interactively for each missing dependency.
@@ -15,16 +15,22 @@ set -o pipefail
# --- Configuration --- # --- Configuration ---
LOGFILE="GridFire_Installer.log" LOGFILE="GridFire_Installer.log"
NOTES_FILE="notes.txt"
MIN_GCC_VER="13.0.0"
MIN_CLANG_VER="16.0.0"
MIN_MESON_VER="1.5.0"
# --- Build Configuration Globals --- # --- Build Configuration Globals ---
BUILD_DIR="build" BUILD_DIR="build"
INSTALL_PREFIX="/usr/local" INSTALL_PREFIX="/usr/local"
MESON_BUILD_TYPE="release" MESON_BUILD_TYPE="debug" # Default to debug to match Meson's default and avoid optimization warnings
MESON_LOG_LEVEL="info" MESON_LOG_LEVEL="info"
MESON_PKG_CONFIG="true" MESON_PKG_CONFIG="true"
MESON_NUM_CORES=$(getconf _NPROCESSORS_ONLN 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 1) MESON_NUM_CORES=$(getconf _NPROCESSORS_ONLN 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 1)
C_COMPILER=""
CC_COMPILER="" CC_COMPILER=""
AVAILABLE_COMPILERS=() FC_COMPILER=""
declare -A VALID_COMPILERS
# --- ANSI Color Codes --- # --- ANSI Color Codes ---
RED="\033[0;31m" RED="\033[0;31m"
@@ -44,20 +50,40 @@ log() {
echo -e "${message}" | sed 's/\x1B\[[0-9;]*[mK]//g' >> "$LOGFILE" echo -e "${message}" | sed 's/\x1B\[[0-9;]*[mK]//g' >> "$LOGFILE"
} }
# Prompt the user for a yes/no answer. # Version comparison function. Returns 0 if v1=v2, 1 if v1>v2, 2 if v1<v2
prompt_yes_no() { vercomp() {
local prompt_msg="$1" local v1=$1 v2=$2
local answer if [[ "$v1" == "$v2" ]]; then return 0; fi
while true; do local IFS=.
read -p "$(echo -e "${YELLOW}${prompt_msg}${NC}") " answer read -ra v1_parts <<< "$v1"
case "$answer" in read -ra v2_parts <<< "$v2"
[Yy]* ) return 0;;
[Nn]* ) return 1;; local i
* ) echo "Please answer yes or no.";; # Pad the shorter version array with zeros
esac local len1=${#v1_parts[@]}
local len2=${#v2_parts[@]}
if (( len1 > len2 )); then
for ((i=len2; i<len1; i++)); do v2_parts[i]=0; done
elif (( len2 > len1 )); then
for ((i=len1; i<len2; i++)); do v1_parts[i]=0; done
fi
for i in "${!v1_parts[@]}"; do
local p1=${v1_parts[i]}
local p2=${v2_parts[i]}
# Ensure parts are integers before comparison
if ! [[ "$p1" =~ ^[0-9]+$ ]]; then p1=0; fi
if ! [[ "$p2" =~ ^[0-9]+$ ]]; then p2=0; fi
if (( p1 > p2 )); then return 1; fi
if (( p1 < p2 )); then return 2; fi
done done
return 0
} }
# Show the help message and exit. # Show the help message and exit.
show_help() { show_help() {
echo "Usage: ./install.sh [options]" echo "Usage: ./install.sh [options]"
@@ -90,25 +116,83 @@ check_command() {
command -v "$1" &>/dev/null command -v "$1" &>/dev/null
} }
check_compiler() { set_compilers() {
AVAILABLE_COMPILERS=() if [[ "$CC_COMPILER" == *"clang++"* ]]; then
if check_command g++; then C_COMPILER=$(echo "$CC_COMPILER" | sed 's/clang++/clang/')
AVAILABLE_COMPILERS+=("g++") # Try to find a corresponding flang or fallback to gfortran
local fc_ver=$(echo "$C_COMPILER" | grep -oE '[0-9]+')
if check_command "flang-$fc_ver"; then
FC_COMPILER="flang-$fc_ver"
elif check_command "flang"; then
FC_COMPILER="flang"
elif check_command "gfortran"; then
FC_COMPILER="gfortran"
else
FC_COMPILER=""
fi fi
if check_command clang++; then elif [[ "$CC_COMPILER" == *"g++"* ]]; then
AVAILABLE_COMPILERS+=("clang++") C_COMPILER=$(echo "$CC_COMPILER" | sed 's/g++/gcc/')
FC_COMPILER=$(echo "$CC_COMPILER" | sed 's/g++/gfortran/')
if ! check_command "$FC_COMPILER"; then
# Fallback to generic gfortran if versioned one not found
if check_command "gfortran"; then
FC_COMPILER="gfortran"
else
FC_COMPILER=""
fi fi
fi
else
C_COMPILER=""
FC_COMPILER=""
fi
}
if [ ${#AVAILABLE_COMPILERS[@]} -gt 0 ]; then check_compiler() {
# Set default compiler if not already set or if current selection is no longer valid VALID_COMPILERS=()
if ! [[ " ${AVAILABLE_COMPILERS[*]} " =~ " ${CC_COMPILER} " ]]; then local potential_gccs=("g++-14" "g++-13" "g++")
CC_COMPILER="${AVAILABLE_COMPILERS[0]}" local potential_clangs=("clang++-17" "clang++-16" "clang++")
for cc in "${potential_gccs[@]}"; do
if check_command "$cc"; then
local ver; ver=$($cc -dumpversion | grep -oE '[0-9]+(\.[0-9]+)*' | head -n1)
if [[ -n "$ver" ]]; then
vercomp "$ver" "$MIN_GCC_VER"
if [[ $? -ne 2 ]]; then
VALID_COMPILERS["g++ ($ver)"]="$cc"
break # Found a valid one, stop searching for g++
fi fi
log "${GREEN}[OK] Found C++ compiler(s): ${AVAILABLE_COMPILERS[*]}. Using '${CC_COMPILER}'.${NC}" fi
fi
done
for cc in "${potential_clangs[@]}"; do
if check_command "$cc"; then
local ver; ver=$($cc --version | head -n1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1)
if [[ -n "$ver" ]]; then
vercomp "$ver" "$MIN_CLANG_VER"
if [[ $? -ne 2 ]]; then
VALID_COMPILERS["clang++ ($ver)"]="$cc"
break # Found a valid one
fi
fi
fi
done
if [ ${#VALID_COMPILERS[@]} -gt 0 ]; then
if ! [[ " ${VALID_COMPILERS[*]} " =~ " ${CC_COMPILER} " ]]; then
# Correctly get the first value from the associative array
local keys=("${!VALID_COMPILERS[@]}")
local first_key="${keys[0]}"
CC_COMPILER="${VALID_COMPILERS[$first_key]}"
fi
set_compilers
log "${GREEN}[OK] Found valid C++ compiler(s). Using C: '${C_COMPILER}', C++: '${CC_COMPILER}', FC: '${FC_COMPILER}'.${NC}"
return 0 return 0
else else
log "${RED}[FAIL] No C++ compiler (g++ or clang++) found.${NC}" log "${RED}[FAIL] No valid C++ compiler found (GCC >= ${MIN_GCC_VER} or Clang >= ${MIN_CLANG_VER}).${NC}"
CC_COMPILER="" CC_COMPILER=""
C_COMPILER=""
FC_COMPILER=""
return 1 return 1
fi fi
} }
@@ -145,8 +229,15 @@ check_cmake() {
check_meson() { check_meson() {
if check_command meson; then if check_command meson; then
log "${GREEN}[OK] Found Meson: $(meson --version)${NC}" local ver; ver=$(meson --version)
vercomp "$ver" "$MIN_MESON_VER"
if [[ $? -ne 2 ]]; then
log "${GREEN}[OK] Found Meson ${ver}.${NC}"
return 0 return 0
else
log "${RED}[FAIL] Meson version ${ver} is too old. Need >= ${MIN_MESON_VER}.${NC}"
return 1
fi
else else
log "${RED}[FAIL] Meson not found.${NC}" log "${RED}[FAIL] Meson not found.${NC}"
return 1 return 1
@@ -182,26 +273,28 @@ get_compiler_install_cmd() {
local brew_cmd; brew_cmd=$(command -v brew) local brew_cmd; brew_cmd=$(command -v brew)
case "$compiler_to_install" in case "$compiler_to_install" in
"g++") cmd="$brew_cmd install gcc" ;; "g++") cmd="$brew_cmd install gcc" ;;
"clang++") cmd="xcode-select --install" ;; "clang++") cmd="$brew_cmd install llvm" ;; # llvm provides clang
esac esac
;; ;;
"Linux") "Linux")
case "$DISTRO_ID" in case "$DISTRO_ID" in
"ubuntu"|"debian"|"linuxmint") "ubuntu"|"debian"|"linuxmint")
case "$compiler_to_install" in case "$compiler_to_install" in
"g++") cmd="sudo apt-get install -y g++" ;; "g++") cmd="sudo apt-get install -y g++-13 gfortran-13" ;;
"clang++") cmd="sudo apt-get install -y clang" ;; "clang++") cmd="sudo apt-get install -y clang-16" ;;
esac esac
;; ;;
"fedora") "fedora")
# Fedora usually has recent versions in main repos
case "$compiler_to_install" in case "$compiler_to_install" in
"g++") cmd="sudo dnf install -y gcc-c++" ;; "g++") cmd="sudo dnf install -y gcc-c++ gcc-gfortran" ;;
"clang++") cmd="sudo dnf install -y clang" ;; "clang++") cmd="sudo dnf install -y clang" ;;
esac esac
;; ;;
"arch"|"manjaro") "arch"|"manjaro")
# Arch is rolling release, should be fine
case "$compiler_to_install" in case "$compiler_to_install" in
"g++") cmd="sudo pacman -S --noconfirm gcc" ;; "g++") cmd="sudo pacman -S --noconfirm gcc gcc-fortran" ;;
"clang++") cmd="sudo pacman -S --noconfirm clang" ;; "clang++") cmd="sudo pacman -S --noconfirm clang" ;;
esac esac
;; ;;
@@ -221,11 +314,11 @@ get_install_cmd() {
local brew_cmd local brew_cmd
brew_cmd=$(command -v brew) brew_cmd=$(command -v brew)
case "$dep_name" in case "$dep_name" in
"compiler") cmd="xcode-select --install; $brew_cmd install gcc" ;; # Install both "compiler") cmd="$brew_cmd install gcc llvm" ;; # Install both
"python-dev") cmd="$brew_cmd install python3" ;; "python-dev") cmd="$brew_cmd install python3" ;;
"meson-python") cmd="python3 -m pip install meson-python" ;; "meson-python") cmd="python3 -m pip install meson-python" ;;
"meson") cmd="python3 -m pip install --upgrade meson" ;;
"cmake") cmd="$brew_cmd install cmake" ;; "cmake") cmd="$brew_cmd install cmake" ;;
"meson") cmd="$brew_cmd install meson" ;;
"boost") cmd="$brew_cmd install boost" ;; "boost") cmd="$brew_cmd install boost" ;;
"dialog") cmd="$brew_cmd install dialog" ;; "dialog") cmd="$brew_cmd install dialog" ;;
esac esac
@@ -234,33 +327,33 @@ get_install_cmd() {
case "$DISTRO_ID" in case "$DISTRO_ID" in
"ubuntu"|"debian"|"linuxmint") "ubuntu"|"debian"|"linuxmint")
case "$dep_name" in case "$dep_name" in
"compiler") cmd="sudo apt-get install -y build-essential clang" ;; "compiler") cmd="sudo apt-get install -y g++-13 gfortran-13 clang-16" ;;
"python-dev") cmd="sudo apt-get install -y python3-dev" ;; "python-dev") cmd="sudo apt-get install -y python3-dev" ;;
"meson-python") cmd="python3 -m pip install meson-python" ;; "meson-python") cmd="python3 -m pip install meson-python" ;;
"meson") cmd="python3 -m pip install --upgrade meson" ;;
"cmake") cmd="sudo apt-get install -y cmake" ;; "cmake") cmd="sudo apt-get install -y cmake" ;;
"meson") cmd="sudo apt-get install -y meson" ;;
"boost") cmd="sudo apt-get install -y libboost-all-dev" ;; "boost") cmd="sudo apt-get install -y libboost-all-dev" ;;
"dialog") cmd="sudo apt-get install -y dialog" ;; "dialog") cmd="sudo apt-get install -y dialog" ;;
esac esac
;; ;;
"fedora") "fedora")
case "$dep_name" in case "$dep_name" in
"compiler") cmd="sudo dnf install -y gcc-c++ clang" ;; "compiler") cmd="sudo dnf install -y gcc-c++ gcc-gfortran clang" ;;
"python-dev") cmd="sudo dnf install -y python3-devel" ;; "python-dev") cmd="sudo dnf install -y python3-devel" ;;
"meson-python") cmd="python3 -m pip install meson-python" ;; "meson-python") cmd="python3 -m pip install meson-python" ;;
"meson") cmd="python3 -m pip install --upgrade meson" ;;
"cmake") cmd="sudo dnf install -y cmake" ;; "cmake") cmd="sudo dnf install -y cmake" ;;
"meson") cmd="sudo dnf install -y meson" ;;
"boost") cmd="sudo dnf install -y boost-devel" ;; "boost") cmd="sudo dnf install -y boost-devel" ;;
"dialog") cmd="sudo dnf install -y dialog" ;; "dialog") cmd="sudo dnf install -y dialog" ;;
esac esac
;; ;;
"arch"|"manjaro") "arch"|"manjaro")
case "$dep_name" in case "$dep_name" in
"compiler") cmd="sudo pacman -S --noconfirm base-devel clang" ;; "compiler") cmd="sudo pacman -S --noconfirm gcc gcc-fortran clang" ;;
"python-dev") cmd="sudo pacman -S --noconfirm python" ;; "python-dev") cmd="sudo pacman -S --noconfirm python" ;;
"meson-python") cmd="python3 -m pip install meson-python" ;; "meson-python") cmd="python3 -m pip install meson-python" ;;
"meson") cmd="python3 -m pip install --upgrade meson" ;;
"cmake") cmd="sudo pacman -S --noconfirm cmake" ;; "cmake") cmd="sudo pacman -S --noconfirm cmake" ;;
"meson") cmd="sudo pacman -S --noconfirm meson" ;;
"boost") cmd="sudo pacman -S --noconfirm boost" ;; "boost") cmd="sudo pacman -S --noconfirm boost" ;;
"dialog") cmd="sudo pacman -S --noconfirm dialog" ;; "dialog") cmd="sudo pacman -S --noconfirm dialog" ;;
esac esac
@@ -280,8 +373,8 @@ run_meson_setup() {
if [ ! -f "meson.build" ]; then if [ ! -f "meson.build" ]; then
log "${RED}[FATAL] meson.build file not found. Cannot proceed.${NC}"; return 1; log "${RED}[FATAL] meson.build file not found. Cannot proceed.${NC}"; return 1;
fi fi
if [ -z "$CC_COMPILER" ]; then if [ -z "$CC_COMPILER" ] || [ -z "$C_COMPILER" ]; then
log "${RED}[FATAL] No C++ compiler selected. Configure one first.${NC}"; return 1; log "${RED}[FATAL] No valid C/C++ compiler selected. Configure one first.${NC}"; return 1;
fi fi
local reconfigure_flag="" local reconfigure_flag=""
if [ -d "$BUILD_DIR" ]; then if [ -d "$BUILD_DIR" ]; then
@@ -295,10 +388,12 @@ run_meson_setup() {
meson_opts+=("-Dpkg-config=${MESON_PKG_CONFIG}") meson_opts+=("-Dpkg-config=${MESON_PKG_CONFIG}")
meson_opts+=("--prefix=${INSTALL_PREFIX}") meson_opts+=("--prefix=${INSTALL_PREFIX}")
log "${BLUE}[Info] Using C compiler: ${C_COMPILER}${NC}"
log "${BLUE}[Info] Using C++ compiler: ${CC_COMPILER}${NC}" log "${BLUE}[Info] Using C++ compiler: ${CC_COMPILER}${NC}"
log "${BLUE}[Info] Using Fortran compiler: ${FC_COMPILER}${NC}"
log "${BLUE}[Info] Running meson setup with options: ${meson_opts[*]}${NC}" log "${BLUE}[Info] Running meson setup with options: ${meson_opts[*]}${NC}"
# Set CXX environment variable for the meson command # Set CC, CXX, and FC environment variables for the meson command
if ! CXX="${CC_COMPILER}" meson setup "${BUILD_DIR}" "${meson_opts[@]}" ${reconfigure_flag}; then if ! CC="${C_COMPILER}" CXX="${CC_COMPILER}" FC="${FC_COMPILER}" meson setup "${BUILD_DIR}" "${meson_opts[@]}" ${reconfigure_flag}; then
log "${RED}[FATAL] Meson setup failed. See log for details.${NC}"; return 1; log "${RED}[FATAL] Meson setup failed. See log for details.${NC}"; return 1;
fi fi
log "${GREEN}[Success] Meson setup complete.${NC}" log "${GREEN}[Success] Meson setup complete.${NC}"
@@ -384,7 +479,7 @@ run_dependency_installer_tui() {
"python-dev" "Python 3 Dev Headers" "$([[ ${DEP_STATUS[python-dev]} -ne 0 ]] && echo "on" || echo "off")" \ "python-dev" "Python 3 Dev Headers" "$([[ ${DEP_STATUS[python-dev]} -ne 0 ]] && echo "on" || echo "off")" \
"meson-python" "meson-python (for Python bindings)" "$([[ ${DEP_STATUS[meson-python]} -ne 0 ]] && echo "on" || echo "off")" \ "meson-python" "meson-python (for Python bindings)" "$([[ ${DEP_STATUS[meson-python]} -ne 0 ]] && echo "on" || echo "off")" \
"cmake" "CMake" "$([[ ${DEP_STATUS[cmake]} -ne 0 ]] && echo "on" || echo "off")" \ "cmake" "CMake" "$([[ ${DEP_STATUS[cmake]} -ne 0 ]] && echo "on" || echo "off")" \
"meson" "Meson Build System" "$([[ ${DEP_STATUS[meson]} -ne 0 ]] && echo "on" || echo "off")" \ "meson" "Meson Build System (>=${MIN_MESON_VER})" "$([[ ${DEP_STATUS[meson]} -ne 0 ]] && echo "on" || echo "off")" \
"boost" "Boost Libraries" "$([[ ${DEP_STATUS[boost]} -ne 0 ]] && echo "on" || echo "off")" \ "boost" "Boost Libraries" "$([[ ${DEP_STATUS[boost]} -ne 0 ]] && echo "on" || echo "off")" \
3>&1 1>&2 2>&3) 3>&1 1>&2 2>&3)
@@ -435,7 +530,7 @@ run_python_bindings_tui() {
case "$choice" in case "$choice" in
1) 1)
log "${BLUE}[Info] Installing Python bindings in Developer Mode...${NC}" log "${BLUE}[Info] Installing Python bindings in Developer Mode...${NC}"
if ! CXX="${CC_COMPILER}" pip install -e . --no-build-isolation -vv; then if ! CC="${C_COMPILER}" CXX="${CC_COMPILER}" FC="${FC_COMPILER}" pip install -e . --no-build-isolation -vv; then
log "${RED}[Error] Failed to install Python bindings in developer mode.${NC}" log "${RED}[Error] Failed to install Python bindings in developer mode.${NC}"
dialog --msgbox "Developer mode installation failed. Check the log for details." 8 60 dialog --msgbox "Developer mode installation failed. Check the log for details." 8 60
else else
@@ -445,7 +540,7 @@ run_python_bindings_tui() {
;; ;;
2) 2)
log "${BLUE}[Info] Installing Python bindings in User Mode...${NC}" log "${BLUE}[Info] Installing Python bindings in User Mode...${NC}"
if ! CXX="${CC_COMPILER}" pip install .; then if ! CC="${C_COMPILER}" CXX="${CC_COMPILER}" FC="${FC_COMPILER}" pip install .; then
log "${RED}[Error] Failed to install Python bindings in user mode.${NC}" log "${RED}[Error] Failed to install Python bindings in user mode.${NC}"
dialog --msgbox "User mode installation failed. Check the log for details." 8 60 dialog --msgbox "User mode installation failed. Check the log for details." 8 60
else else
@@ -460,53 +555,59 @@ run_python_bindings_tui() {
} }
run_compiler_selection_tui() { run_compiler_selection_tui() {
local gpp_found=false local gpp_ver; gpp_ver=$(g++ -dumpversion 2>/dev/null | grep -oE '[0-9]+(\.[0-9]+)*' | head -n1)
local clang_found=false local clang_ver; clang_ver=$(clang++ --version 2>/dev/null | head -n1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1)
check_command g++ && gpp_found=true
check_command clang++ && clang_found=true
# Scenario 1: No compilers found local gpp_ok=false
if ! $gpp_found && ! $clang_found; then local clang_ok=false
if [[ -n "$gpp_ver" ]]; then vercomp "$gpp_ver" "$MIN_GCC_VER"; [[ $? -ne 2 ]] && gpp_ok=true; fi
if [[ -n "$clang_ver" ]]; then vercomp "$clang_ver" "$MIN_CLANG_VER"; [[ $? -ne 2 ]] && clang_ok=true; fi
if ! $gpp_ok && ! $clang_ok; then
# No valid compilers found
local choices local choices
choices=$(dialog --title "Compiler Installation" --checklist "No C++ compiler found. Please select which to install:" 15 70 2 \ choices=$(dialog --title "Compiler Installation" --checklist "No valid C++ compiler found. Please select which to install:" 15 70 2 \
"g++" "GNU C++ Compiler" "on" \ "g++" "GNU C++ Compiler (>=${MIN_GCC_VER})" "on" \
"clang++" "Clang C++ Compiler (often faster)" "off" 3>&1 1>&2 2>&3) "clang++" "Clang C++ Compiler (>=${MIN_CLANG_VER}, often faster)" "off" 3>&1 1>&2 2>&3)
if [ -n "$choices" ]; then if [ -n "$choices" ]; then
for choice in $choices; do for choice in $choices; do
local compiler_to_install; compiler_to_install=$(echo "$choice" | tr -d '"') local compiler_to_install; compiler_to_install=$(echo "$choice" | tr -d '"')
local install_cmd; install_cmd=$(get_compiler_install_cmd "$compiler_to_install") local install_cmd; install_cmd=$(get_compiler_install_cmd "$compiler_to_install")
if [ -n "$install_cmd" ]; then if [ -n "$install_cmd" ]; then eval "$install_cmd" 2>&1 | tee -a "$LOGFILE"; fi
eval "$install_cmd" 2>&1 | tee -a "$LOGFILE"
fi
done done
fi fi
# Scenario 2: g++ found, clang++ not found elif ! $gpp_ok && [[ -n "$gpp_ver" ]]; then
elif $gpp_found && ! $clang_found; then # g++ found but too old
if dialog --title "Compiler Installation" --yesno "g++ is installed. Would you like to install clang++?\n\n(Note: clang++ often provides faster compilation times)" 10 70; then if dialog --title "Compiler Update" --yesno "Found g++ version ${gpp_ver}, but require >= ${MIN_GCC_VER}.\n\nAttempt to install a compatible version?" 10 70; then
local install_cmd; install_cmd=$(get_compiler_install_cmd "clang++") local install_cmd; install_cmd=$(get_compiler_install_cmd "g++")
if [ -n "$install_cmd" ]; then eval "$install_cmd" 2>&1 | tee -a "$LOGFILE"; fi if [ -n "$install_cmd" ]; then eval "$install_cmd" 2>&1 | tee -a "$LOGFILE"; fi
fi fi
# Scenario 3: clang++ found, g++ not found elif ! $clang_ok && [[ -n "$clang_ver" ]]; then
elif ! $gpp_found && $clang_found; then # clang++ found but too old
if dialog --title "Compiler Installation" --yesno "clang++ is installed. Would you like to install g++?" 8 70; then if dialog --title "Compiler Update" --yesno "Found clang++ version ${clang_ver}, but require >= ${MIN_CLANG_VER}.\n\nAttempt to install a compatible version?" 10 70; then
local install_cmd; install_cmd=$(get_compiler_install_cmd "g++") local install_cmd; install_cmd=$(get_compiler_install_cmd "clang++")
if [ -n "$install_cmd" ]; then eval "$install_cmd" 2>&1 | tee -a "$LOGFILE"; fi if [ -n "$install_cmd" ]; then eval "$install_cmd" 2>&1 | tee -a "$LOGFILE"; fi
fi fi
fi fi
# Re-check compilers and let user choose if multiple are available # Re-check compilers and let user choose if multiple are available
check_compiler check_compiler
if [ ${#AVAILABLE_COMPILERS[@]} -gt 1 ]; then if [ ${#VALID_COMPILERS[@]} -gt 0 ]; then
local menu_items=() local menu_items=()
for compiler in "${AVAILABLE_COMPILERS[@]}"; do menu_items+=("$compiler" ""); done for name in "${!VALID_COMPILERS[@]}"; do
local compiler_choice menu_items+=("$name" "")
compiler_choice=$(dialog --title "Select C++ Compiler" --menu "Select the C++ compiler to use:" 15 70 ${#AVAILABLE_COMPILERS[@]} "${menu_items[@]}" 3>&1 1>&2 2>&3) done
if [ -n "$compiler_choice" ]; then local compiler_choice_key
CC_COMPILER="$compiler_choice" compiler_choice_key=$(dialog --title "Select C++ Compiler" --menu "Select the C++ compiler to use:" 15 70 ${#VALID_COMPILERS[@]} "${menu_items[@]}" 3>&1 1>&2 2>&3)
if [ -n "$compiler_choice_key" ]; then
CC_COMPILER="${VALID_COMPILERS[$compiler_choice_key]}"
set_compilers
log "${BLUE}[Config] Set C compiler to: ${C_COMPILER}${NC}"
log "${BLUE}[Config] Set C++ compiler to: ${CC_COMPILER}${NC}" log "${BLUE}[Config] Set C++ compiler to: ${CC_COMPILER}${NC}"
log "${BLUE}[Config] Set Fortran compiler to: ${FC_COMPILER}${NC}"
fi fi
elif [ ${#AVAILABLE_COMPILERS[@]} -eq 0 ]; then else
dialog --msgbox "No C++ compiler could be found or installed. Please install one manually." 8 70 dialog --msgbox "No valid C++ compiler could be found or installed. Please install one manually that meets the version requirements." 8 70
fi fi
} }
@@ -517,7 +618,7 @@ run_build_config_tui() {
--menu "Select an option to configure:" 20 70 7 \ --menu "Select an option to configure:" 20 70 7 \
"1" "Build Directory (current: ${BUILD_DIR})" \ "1" "Build Directory (current: ${BUILD_DIR})" \
"2" "Install Prefix (current: ${INSTALL_PREFIX})" \ "2" "Install Prefix (current: ${INSTALL_PREFIX})" \
"3" "Manage & Select C++ Compiler (current: ${CC_COMPILER})" \ "3" "Manage & Select C/C++/Fortran Compiler" \
"4" "Build Type (current: ${MESON_BUILD_TYPE})" \ "4" "Build Type (current: ${MESON_BUILD_TYPE})" \
"5" "Log Level (current: ${MESON_LOG_LEVEL})" \ "5" "Log Level (current: ${MESON_LOG_LEVEL})" \
"6" "Generate pkg-config (current: ${MESON_PKG_CONFIG})" \ "6" "Generate pkg-config (current: ${MESON_PKG_CONFIG})" \
@@ -547,10 +648,11 @@ run_build_config_tui() {
;; ;;
4) 4)
local build_type_choice local build_type_choice
build_type_choice=$(dialog --title "Select Build Type" --menu "" 15 70 3 \ build_type_choice=$(dialog --title "Select Build Type" --menu "" 15 70 4 \
"debug" "No optimizations, with debug symbols" \
"release" "Optimized for performance" \ "release" "Optimized for performance" \
"debug" "With debug symbols, no optimization" \
"debugoptimized" "With debug symbols and optimization" \ "debugoptimized" "With debug symbols and optimization" \
"plain" "Custom flags only" \
3>&1 1>&2 2>&3) 3>&1 1>&2 2>&3)
if [ -n "$build_type_choice" ]; then if [ -n "$build_type_choice" ]; then
MESON_BUILD_TYPE="$build_type_choice" MESON_BUILD_TYPE="$build_type_choice"
@@ -589,6 +691,32 @@ run_build_config_tui() {
esac esac
} }
run_notes_tui() {
if [ ! -f "$NOTES_FILE" ]; then
dialog --msgbox "Notes file '${NOTES_FILE}' not found." 8 50
return
fi
local notes_content=""
local counter=1
# Read file, filter comments, and process non-empty lines
while IFS= read -r line; do
# Skip empty or comment lines
if [[ -z "$line" || "$line" =~ ^[[:space:]]*# ]]; then
continue
fi
echo "$line"
notes_content+="${counter}. ${line}\n\n"
((counter++))
done < "$NOTES_FILE"
if [ -z "$notes_content" ]; then
dialog --msgbox "No notes found in '${NOTES_FILE}'." 8 50
else
dialog --title "Installer Notes" --msgbox "$notes_content" 20 70
fi
}
run_main_tui() { run_main_tui() {
if ! check_dialog_installed; then return 1; fi if ! check_dialog_installed; then return 1; fi
# Initial check to populate compiler list and set a default # Initial check to populate compiler list and set a default
@@ -603,7 +731,7 @@ run_main_tui() {
local choice local choice
choice=$(dialog --clear --backtitle "GridFire Installer - [${sudo_status}]" \ choice=$(dialog --clear --backtitle "GridFire Installer - [${sudo_status}]" \
--title "Main Menu" \ --title "Main Menu" \
--menu "COMPILER: ${CC_COMPILER:-Not Found} | DIR: ${BUILD_DIR}\nTYPE: ${MESON_BUILD_TYPE} | CORES: ${MESON_NUM_CORES}\nPREFIX: ${INSTALL_PREFIX}\nLOG: ${MESON_LOG_LEVEL} | PKG-CONFIG: ${MESON_PKG_CONFIG}" 20 70 10 \ --menu "C: ${C_COMPILER:-N/A} C++: ${CC_COMPILER:-N/A} FC: ${FC_COMPILER:-N/A}\nDIR: ${BUILD_DIR} | TYPE: ${MESON_BUILD_TYPE} | CORES: ${MESON_NUM_CORES}\nPREFIX: ${INSTALL_PREFIX}\nLOG: ${MESON_LOG_LEVEL} | PKG-CONFIG: ${MESON_PKG_CONFIG}" 22 78 11 \
"1" "Install System Dependencies" \ "1" "Install System Dependencies" \
"2" "Configure Build Options" \ "2" "Configure Build Options" \
"3" "Install Python Bindings" \ "3" "Install Python Bindings" \
@@ -612,7 +740,8 @@ run_main_tui() {
"6" "Run Meson Compile" \ "6" "Run Meson Compile" \
"7" "Run Meson Install (requires sudo)" \ "7" "Run Meson Install (requires sudo)" \
"8" "Run Tests" \ "8" "Run Tests" \
"9" "Exit" \ "9" "View Notes" \
"10" "Exit" \
3>&1 1>&2 2>&3) 3>&1 1>&2 2>&3)
clear clear
@@ -625,7 +754,8 @@ run_main_tui() {
6) run_meson_compile ;; 6) run_meson_compile ;;
7) run_meson_install ;; 7) run_meson_install ;;
8) run_meson_tests ;; 8) run_meson_tests ;;
9) break ;; 9) run_notes_tui ;;
10) break ;;
*) log "${YELLOW}[Info] TUI cancelled.${NC}"; break ;; *) log "${YELLOW}[Info] TUI cancelled.${NC}"; break ;;
esac esac
done done

6
notes.txt Normal file
View File

@@ -0,0 +1,6 @@
The logical flow of using this installer is (for C++ usage): install system dependencies > "Run Full Build" > "Run Meson Install"
The logical flow of using this installer is (for Python usage): install system dependencies > "Install Python Bindings" (note this will take a while).
When building in release mode (default), static analysis of CppAD throws a few bounds warnings. Testing indicates that these are not problems. These warnings do not get identified in debug builds.
GridFire requires gcc >= 13.0.0 or clang >= 16.0.0
GridFire is authored by the 4D-STAR collaboration and Emily M. Boudreaux.
4D-STAR is funded by European Research Council (ERC) under the Horizon Europe programme (Synergy Grant agreement No. 101071505: 4D-STAR). Work for this project is funded by the European Union. Views and opinions expressed are however those of the author(s) only and do not necessarily reflect those of the European Union or the European Research Council.