build(install): added venv python managment

This commit is contained in:
2025-07-29 13:44:43 -04:00
parent f3cabfc191
commit 443f9e6888
2 changed files with 135 additions and 16 deletions

View File

@@ -31,7 +31,8 @@ GridFire is a part of the 4D-STAR collaboration.
Work for this project is funded by the European Union. Views and opinions expressed are however those of the author(s) 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. only and do not necessarily reflect those of the European Union or the European Research Council.
## Build and Installation Instructions ## Automatic Build and Installation
### Script Build and Installation Instructions
The easiest way to build GridFire is using the `install.sh` or `install-tui.sh` scripts in the root directory. To use The easiest way to build GridFire is using the `install.sh` or `install-tui.sh` scripts in the root directory. To use
these scripts, simply run: these scripts, simply run:
@@ -41,14 +42,28 @@ these scripts, simply run:
# or # or
./install-tui.sh ./install-tui.sh
``` ```
The regular installation script will select a standard "ideal" set of build options for you. If you want more control The regular installation script will select a standard "ideal" set of build options for you. If you want more control
over the build options, you can use the `install-tui.sh` script, which will provide a text-based user interface to over the build options, you can use the `install-tui.sh` script, which will provide a text-based user interface to
select the build options you want. select the build options you want.
Generally, both are intended to be easy to use and will prompt you automatically to install any missing dependencies. Generally, both are intended to be easy to use and will prompt you automatically to install any missing dependencies.
### Currently known good platforms
The installation script has been tested and found to work on clean installations of the following platforms:
- MacOS 15.3.2 (Apple Silicon + brew installed)
- Fedora 42.0 (aarch64)
- Ubuntu 25.04 (aarch64)
- Ubuntu 22.04 (X86_64)
> **Note:** On Ubuntu 22.04 the user needs to install boost libraries manually as the versions in the Ubuntu repositories
are too old. The installer automatically detects this and will instruct the user in how to do this.
## Manual Build Instructions
### Prerequisites ### Prerequisites
These only need to be manually installed if the user is not making use of the `install.sh` or `install-tui.sh`
- C++ compiler supporting C++23 standard - C++ compiler supporting C++23 standard
- Meson build system (>= 1.5.0) - Meson build system (>= 1.5.0)
- Python 3.10 or newer - Python 3.10 or newer

View File

@@ -17,6 +17,7 @@ set -o pipefail
LOGFILE="GridFire_Installer.log" LOGFILE="GridFire_Installer.log"
NOTES_FILE="notes.txt" NOTES_FILE="notes.txt"
CONFIG_FILE="gridfire_build.conf" CONFIG_FILE="gridfire_build.conf"
VENV_DIR=".venv"
MIN_GCC_VER="13.0.0" MIN_GCC_VER="13.0.0"
MIN_CLANG_VER="16.0.0" MIN_CLANG_VER="16.0.0"
MIN_MESON_VER="1.5.0" MIN_MESON_VER="1.5.0"
@@ -146,6 +147,25 @@ check_command() {
command -v "$1" &>/dev/null command -v "$1" &>/dev/null
} }
is_externally_managed() {
# Check for the PEP 668 marker file
local py_prefix
py_prefix=$(python3 -c "import sys; print(sys.prefix)")
if [ -f "$py_prefix/EXTERNALLY-MANAGED" ]; then
return 0 # 0 means true in bash
else
return 1 # 1 means false
fi
}
get_pip_cmd() {
if [ -d "$VENV_DIR" ]; then
echo "$VENV_DIR/bin/pip"
else
echo "python3 -m pip"
fi
}
set_compilers() { set_compilers() {
if [[ "$CC_COMPILER" == *"clang++"* ]]; then if [[ "$CC_COMPILER" == *"clang++"* ]]; then
C_COMPILER=$(echo "$CC_COMPILER" | sed 's/clang++/clang/') C_COMPILER=$(echo "$CC_COMPILER" | sed 's/clang++/clang/')
@@ -227,6 +247,16 @@ check_compiler() {
fi fi
} }
check_pip() {
if python3 -m pip --version &>/dev/null; then
log "${GREEN}[OK] Found pip.${NC}"
return 0
else
log "${RED}[FAIL] pip not found.${NC}"
return 1
fi
}
check_python_dev() { check_python_dev() {
if check_command python3 && python3-config --includes &>/dev/null; then if check_command python3 && python3-config --includes &>/dev/null; then
log "${GREEN}[OK] Found Python 3 development headers.${NC}" log "${GREEN}[OK] Found Python 3 development headers.${NC}"
@@ -238,6 +268,12 @@ check_python_dev() {
} }
check_meson_python() { check_meson_python() {
if [ -d "$VENV_DIR" ]; then
if "$VENV_DIR/bin/python3" -c "import mesonpy" &>/dev/null; then
log "${GREEN}[OK] Found meson-python package (in venv).${NC}"
return 0
fi
fi
if python3 -c "import mesonpy" &>/dev/null; then if python3 -c "import mesonpy" &>/dev/null; then
log "${GREEN}[OK] Found meson-python package.${NC}" log "${GREEN}[OK] Found meson-python package.${NC}"
return 0 return 0
@@ -258,8 +294,13 @@ check_cmake() {
} }
check_meson() { check_meson() {
if check_command meson; then local meson_cmd="meson"
local ver; ver=$(meson --version) if [ -d "$VENV_DIR" ]; then
meson_cmd="$VENV_DIR/bin/meson"
fi
if check_command "$meson_cmd"; then
local ver; ver=$($meson_cmd --version)
vercomp "$ver" "$MIN_MESON_VER" vercomp "$ver" "$MIN_MESON_VER"
if [[ $? -ne 2 ]]; then if [[ $? -ne 2 ]]; then
log "${GREEN}[OK] Found Meson ${ver}.${NC}" log "${GREEN}[OK] Found Meson ${ver}.${NC}"
@@ -383,6 +424,7 @@ get_install_cmd() {
case "$dep_name" in case "$dep_name" in
"compiler") cmd="$brew_cmd install gcc llvm" ;; # 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" ;;
"pip") cmd="python3 -m ensurepip --upgrade" ;;
"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" ;; "meson") cmd="python3 -m pip install --upgrade meson" ;;
"cmake") cmd="$brew_cmd install cmake" ;; "cmake") cmd="$brew_cmd install cmake" ;;
@@ -396,6 +438,7 @@ get_install_cmd() {
case "$dep_name" in case "$dep_name" in
"compiler") cmd="sudo apt-get install -y g++-13 gfortran-13 clang-16" ;; "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" ;;
"pip") cmd="sudo apt-get install -y python3-pip" ;;
"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" ;; "meson") cmd="python3 -m pip install --upgrade meson" ;;
"cmake") cmd="sudo apt-get install -y cmake" ;; "cmake") cmd="sudo apt-get install -y cmake" ;;
@@ -407,6 +450,7 @@ get_install_cmd() {
case "$dep_name" in case "$dep_name" in
"compiler") cmd="sudo dnf install -y gcc-c++ gcc-gfortran 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" ;;
"pip") cmd="sudo dnf install -y python3-pip" ;;
"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" ;; "meson") cmd="python3 -m pip install --upgrade meson" ;;
"cmake") cmd="sudo dnf install -y cmake" ;; "cmake") cmd="sudo dnf install -y cmake" ;;
@@ -418,6 +462,7 @@ get_install_cmd() {
case "$dep_name" in case "$dep_name" in
"compiler") cmd="sudo pacman -S --noconfirm gcc gcc-fortran 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" ;;
"pip") cmd="sudo pacman -S --noconfirm python-pip" ;;
"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" ;; "meson") cmd="python3 -m pip install --upgrade meson" ;;
"cmake") cmd="sudo pacman -S --noconfirm cmake" ;; "cmake") cmd="sudo pacman -S --noconfirm cmake" ;;
@@ -533,10 +578,27 @@ check_dialog_installed() {
return 0 return 0
} }
ensure_venv() {
if [ ! -d "$VENV_DIR" ]; then
if dialog --title "Virtual Environment" --yesno "A local Python virtual environment ('${VENV_DIR}') is required for this action. Create it now?" 8 70; then
log "${BLUE}[Info] Creating Python virtual environment in '${VENV_DIR}'...${NC}"
if ! python3 -m venv "$VENV_DIR"; then
dialog --msgbox "Failed to create virtual environment. Please ensure 'python3-venv' is installed." 8 60
return 1
fi
log "${GREEN}[Success] Virtual environment created.${NC}"
else
return 1
fi
fi
return 0
}
run_dependency_installer_tui() { run_dependency_installer_tui() {
# This function now just calls the check functions to populate status # This function now just calls the check functions to populate status
declare -A DEP_STATUS declare -A DEP_STATUS
check_compiler >/dev/null; DEP_STATUS[compiler]=$? check_compiler >/dev/null; DEP_STATUS[compiler]=$?
check_pip >/dev/null; DEP_STATUS[pip]=$?
check_python_dev >/dev/null; DEP_STATUS[python-dev]=$? check_python_dev >/dev/null; DEP_STATUS[python-dev]=$?
check_meson_python >/dev/null; DEP_STATUS[meson-python]=$? check_meson_python >/dev/null; DEP_STATUS[meson-python]=$?
check_cmake >/dev/null; DEP_STATUS[cmake]=$? check_cmake >/dev/null; DEP_STATUS[cmake]=$?
@@ -548,8 +610,9 @@ run_dependency_installer_tui() {
local choices local choices
choices=$(dialog --clear --backtitle "Project Dependency Installer" \ choices=$(dialog --clear --backtitle "Project Dependency Installer" \
--title "Install System Dependencies" \ --title "Install System Dependencies" \
--checklist "Select dependencies to install. Already found dependencies are unchecked." 20 70 6 \ --checklist "Select dependencies to install. Already found dependencies are unchecked." 20 70 7 \
"compiler" "C++ Compilers (g++, clang++)" "$([[ ${DEP_STATUS[compiler]} -ne 0 ]] && echo "on" || echo "off")" \ "compiler" "C++ Compilers (g++, clang++)" "$([[ ${DEP_STATUS[compiler]} -ne 0 ]] && echo "on" || echo "off")" \
"pip" "Python Package Installer (pip)" "$([[ ${DEP_STATUS[pip]} -ne 0 ]] && echo "on" || echo "off")" \
"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")" \
@@ -563,19 +626,30 @@ run_dependency_installer_tui() {
for choice in $choices; do for choice in $choices; do
local dep; dep=$(echo "$choice" | tr -d '"') local dep; dep=$(echo "$choice" | tr -d '"')
log "\n${BLUE}--- Installing ${dep} ---${NC}" log "\n${BLUE}--- Installing ${dep} ---${NC}"
local install_cmd; install_cmd=$(get_install_cmd "$dep")
if [ -n "$install_cmd" ]; then # Handle python packages specially
eval "$install_cmd" 2>&1 | tee -a "$LOGFILE" if [[ "$dep" == "meson-python" || "$dep" == "meson" ]]; then
if is_externally_managed; then
if ! ensure_venv; then
log "${YELLOW}[Skip] User cancelled venv creation. Skipping ${dep} installation.${NC}"
continue
fi
fi
local pip_cmd; pip_cmd=$(get_pip_cmd)
eval "$pip_cmd install --upgrade $dep" 2>&1 | tee -a "$LOGFILE"
else else
log "${RED}[Error] No automatic installation command for '${dep}'. Please install manually.${NC}" local install_cmd; install_cmd=$(get_install_cmd "$dep")
dialog --msgbox "Could not find an automatic installation command for '${dep}' on your system. Please install it manually." 8 60 if [ -n "$install_cmd" ]; then
eval "$install_cmd" 2>&1 | tee -a "$LOGFILE"
else
log "${RED}[Error] No automatic installation command for '${dep}'. Please install manually.${NC}"
dialog --msgbox "Could not find an automatic installation command for '${dep}' on your system. Please install it manually." 8 60
fi
fi fi
done done
# Re-run check to update status # Re-run check to update status
check_compiler check_compiler
log "${BLUE}[Info] Checking Boost library status (this may take a minute)...${NC}" BOOST_CHECKED=false # Force re-check of boost
# If BOOST_CHECKED is set, we assume Boost was checked previously
check_boost >/dev/null 2>&1 || BOOST_OKAY=false
} }
run_python_bindings_tui() { run_python_bindings_tui() {
@@ -595,6 +669,33 @@ run_python_bindings_tui() {
return return
fi fi
local pip_cmd="python3 -m pip"
local pip_opts=""
if is_externally_managed; then
local env_choice
env_choice=$(dialog --clear --backtitle "Python Environment" \
--title "Externally Managed Environment Detected" \
--menu "This OS protects its system Python. How would you like to install the bindings?" 15 78 3 \
"1" "Use a Virtual Environment (Recommended)" \
"2" "Install to System with --break-system-packages (Advanced)" \
"3" "Cancel" \
3>&1 1>&2 2>&3)
case "$env_choice" in
1)
if ! ensure_venv; then return; fi
pip_cmd="$VENV_DIR/bin/pip"
;;
2)
pip_opts="--break-system-packages"
;;
*)
return
;;
esac
fi
local choice local choice
choice=$(dialog --clear --backtitle "Python Bindings Installer" \ choice=$(dialog --clear --backtitle "Python Bindings Installer" \
--title "Install Python Bindings" \ --title "Install Python Bindings" \
@@ -607,7 +708,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 ! CC="${C_COMPILER}" CXX="${CC_COMPILER}" FC="${FC_COMPILER}" pip install -e . --no-build-isolation -vv; then if ! CC="${C_COMPILER}" CXX="${CC_COMPILER}" FC="${FC_COMPILER}" $pip_cmd install $pip_opts -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
@@ -617,7 +718,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 ! CC="${C_COMPILER}" CXX="${CC_COMPILER}" FC="${FC_COMPILER}" pip install .; then if ! CC="${C_COMPILER}" CXX="${CC_COMPILER}" FC="${FC_COMPILER}" $pip_cmd install $pip_opts .; 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
@@ -1062,7 +1163,10 @@ run_main_tui() {
clear clear
case "$choice" in case "$choice" in
1) run_dependency_installer_tui ;; 1)
run_dependency_installer_tui
BOOST_CHECKED=false # Force re-check after installing
;;
2) run_build_config_tui ;; 2) run_build_config_tui ;;
3) run_python_bindings_tui ;; 3) run_python_bindings_tui ;;
4) run_meson_setup && run_meson_compile ;; 4) run_meson_setup && run_meson_compile ;;