|
| 1 | +#!/bin/bash |
| 2 | + |
| 3 | +# Portable installer for the HardwarePHP extension. |
| 4 | +# - Detects php extension dir dynamically |
| 5 | +# - Enables for available SAPIs (CLI/FPM/Apache) when present |
| 6 | +# - Finds zephir automatically or respects $ZEPHIR_BIN |
| 7 | +# - Provides clear preflight checks and verification |
| 8 | + |
| 9 | +set -Eeuo pipefail |
| 10 | + |
| 11 | +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" |
| 12 | +EXTENSION_NAME="linuxsystem" |
| 13 | +BUILD_SO="${SCRIPT_DIR}/ext/modules/${EXTENSION_NAME}.so" |
| 14 | +LOG_FILE="${SCRIPT_DIR}/build.log" |
| 15 | + |
| 16 | +if [ "${EUID:-$(id -u)}" -ne 0 ]; then |
| 17 | + SUDO="sudo" |
| 18 | +else |
| 19 | + SUDO="" |
| 20 | +fi |
| 21 | + |
| 22 | +die() { |
| 23 | + echo "" |
| 24 | + echo "❌ $*" |
| 25 | + exit 1 |
| 26 | +} |
| 27 | + |
| 28 | +require_cmd() { |
| 29 | + local cmd="$1" |
| 30 | + command -v "$cmd" >/dev/null 2>&1 || die "Required command not found: $cmd" |
| 31 | +} |
| 32 | + |
| 33 | +header() { |
| 34 | + echo "==========================================" |
| 35 | + echo "LinuxDevices Extension Installer (portable)" |
| 36 | + echo "==========================================" |
| 37 | + echo "" |
| 38 | +} |
| 39 | + |
| 40 | +step() { |
| 41 | + echo "$*" |
| 42 | +} |
| 43 | + |
| 44 | +ok() { |
| 45 | + echo " ✓ $*" |
| 46 | +} |
| 47 | + |
| 48 | +header |
| 49 | + |
| 50 | +# Preflight |
| 51 | +step "🔎 Preflight checks..." |
| 52 | +require_cmd php |
| 53 | +require_cmd php-config |
| 54 | + |
| 55 | +# Resolve Zephir |
| 56 | +if [ -n "${ZEPHIR_BIN:-}" ]; then |
| 57 | + ZEPHIR="$ZEPHIR_BIN" |
| 58 | +elif command -v zephir >/dev/null 2>&1; then |
| 59 | + ZEPHIR="$(command -v zephir)" |
| 60 | +elif [ -x "$HOME/.config/composer/vendor/bin/zephir" ]; then |
| 61 | + ZEPHIR="$HOME/.config/composer/vendor/bin/zephir" |
| 62 | +else |
| 63 | + die "Zephir not found. Install via composer (composer global require phalcon/zephir) or set ZEPHIR_BIN." |
| 64 | +fi |
| 65 | +ok "Found zephir: $ZEPHIR" |
| 66 | + |
| 67 | +PHP_VER_MM="$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')" |
| 68 | +PHP_VER_NN="$(php -r 'echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;')" |
| 69 | +PHP_EXT_DIR="$(php-config --extension-dir || true)" |
| 70 | +[ -n "$PHP_EXT_DIR" ] || die "Could not determine PHP extension dir (php-config --extension-dir)." |
| 71 | +ok "PHP version: ${PHP_VER_MM}" |
| 72 | +ok "Extension dir: ${PHP_EXT_DIR}" |
| 73 | + |
| 74 | +# Set safe CFLAGS for GCC 14 compatibility (override any invalid flags from environment) |
| 75 | +# Suppress Zephir kernel code warnings that are harmless but break with GCC 14 |
| 76 | +export CFLAGS="-Wno-error -Wno-error=incompatible-pointer-types -Wno-pointer-compare" |
| 77 | +export CPPFLAGS="${CPPFLAGS:-} -Wno-error -Wno-error=incompatible-pointer-types" |
| 78 | +echo "" |
| 79 | + |
| 80 | +# Clean previous build |
| 81 | +step "🧹 Cleaning previous build..." |
| 82 | +cd "${SCRIPT_DIR}" |
| 83 | +if ! "$ZEPHIR" fullclean >"$LOG_FILE" 2>&1; then |
| 84 | + tail -50 "$LOG_FILE" || true |
| 85 | + die "Clean failed. See ${LOG_FILE}." |
| 86 | +fi |
| 87 | +ok "Clean complete" |
| 88 | +echo "" |
| 89 | + |
| 90 | +# Build |
| 91 | +step "🔨 Building extension..." |
| 92 | +if ! "$ZEPHIR" build >>"$LOG_FILE" 2>&1; then |
| 93 | + tail -80 "$LOG_FILE" || true |
| 94 | + die "Build failed. See ${LOG_FILE}." |
| 95 | +fi |
| 96 | +if [ ! -f "$BUILD_SO" ]; then |
| 97 | + tail -80 "$LOG_FILE" || true |
| 98 | + die "Build output not found at ${BUILD_SO}." |
| 99 | +fi |
| 100 | +ok "Build complete" |
| 101 | +echo "" |
| 102 | + |
| 103 | +# Install .so |
| 104 | +step "📦 Installing binary..." |
| 105 | +$SUDO cp -f "$BUILD_SO" "${PHP_EXT_DIR}/${EXTENSION_NAME}.so" |
| 106 | +$SUDO chmod 755 "${PHP_EXT_DIR}/${EXTENSION_NAME}.so" |
| 107 | +ok "Copied to: ${PHP_EXT_DIR}/${EXTENSION_NAME}.so" |
| 108 | +echo "" |
| 109 | + |
| 110 | +# Enable extension across detected SAPIs |
| 111 | +step "⚙️ Enabling extension..." |
| 112 | +declare -a CONF_DIR_CANDIDATES=() |
| 113 | + |
| 114 | +# CLI scan dir (most accurate for CLI) |
| 115 | +CLI_SCAN_DIR="$(php --ini 2>/dev/null | awk -F': ' '/Scan for additional \.ini files in:/{print $2}' || true)" |
| 116 | +if [ -n "$CLI_SCAN_DIR" ] && [ "$CLI_SCAN_DIR" != "(none)" ] && [ -d "$CLI_SCAN_DIR" ]; then |
| 117 | + CONF_DIR_CANDIDATES+=("$CLI_SCAN_DIR") |
| 118 | +fi |
| 119 | + |
| 120 | +# Debian/Ubuntu common paths |
| 121 | +for d in "/etc/php/${PHP_VER_MM}/cli/conf.d" "/etc/php/${PHP_VER_MM}/fpm/conf.d" "/etc/php/${PHP_VER_MM}/apache2/conf.d"; do |
| 122 | + [ -d "$d" ] && CONF_DIR_CANDIDATES+=("$d") |
| 123 | +done |
| 124 | + |
| 125 | +# Alpine common path (e.g., /etc/php83/conf.d) |
| 126 | +ALPINE_CONF="/etc/php${PHP_VER_NN}/conf.d" |
| 127 | +[ -d "$ALPINE_CONF" ] && CONF_DIR_CANDIDATES+=("$ALPINE_CONF") |
| 128 | + |
| 129 | +# FPM generic fallbacks |
| 130 | +for d in "/etc/php-fpm.d" "/etc/php-fpm/conf.d"; do |
| 131 | + [ -d "$d" ] && CONF_DIR_CANDIDATES+=("$d") |
| 132 | +done |
| 133 | + |
| 134 | +# Deduplicate |
| 135 | +mapfile -t CONF_DIRS < <(printf "%s\n" "${CONF_DIR_CANDIDATES[@]}" | awk '!seen[$0]++') |
| 136 | + |
| 137 | +if [ "${#CONF_DIRS[@]}" -eq 0 ]; then |
| 138 | + echo " ⚠️ No conf.d directories found; enabling only for current CLI context via php.d scan dir." |
| 139 | +fi |
| 140 | + |
| 141 | +INI_NAME="30-${EXTENSION_NAME}.ini" |
| 142 | +INI_CONTENT="extension=${EXTENSION_NAME}.so" |
| 143 | + |
| 144 | +for confd in "${CONF_DIRS[@]:-}"; do |
| 145 | + INI_PATH="${confd}/${INI_NAME}" |
| 146 | + if [ ! -f "$INI_PATH" ]; then |
| 147 | + echo "$INI_CONTENT" | $SUDO tee "$INI_PATH" >/dev/null |
| 148 | + ok "Created: $INI_PATH" |
| 149 | + else |
| 150 | + ok "Already enabled: $INI_PATH" |
| 151 | + fi |
| 152 | +done |
| 153 | +echo "" |
| 154 | + |
| 155 | +# Verify CLI load |
| 156 | +step "🔍 Verifying installation (CLI)..." |
| 157 | +if php -m 2>/dev/null | grep -q "^linuxsystem$"; then |
| 158 | + ok "Extension loaded successfully in CLI" |
| 159 | +else |
| 160 | + echo "" |
| 161 | + php -m 2>/dev/null | tail -n +1 >/dev/null || true |
| 162 | + die "Extension not detected in CLI. Check ${INI_NAME} placement and php --ini." |
| 163 | +fi |
| 164 | +echo "" |
| 165 | + |
| 166 | +# Show module info |
| 167 | +step "==========================================" |
| 168 | +step "Extension Information (CLI)" |
| 169 | +step "==========================================" |
| 170 | +php --ri linuxsystem || true |
| 171 | +echo "" |
| 172 | + |
| 173 | +# Reload FPM if present |
| 174 | +if command -v systemctl >/dev/null 2>&1; then |
| 175 | + if systemctl list-units --type=service 2>/dev/null | grep -q "php${PHP_VER_MM}-fpm\.service"; then |
| 176 | + step "🔁 Reloading php${PHP_VER_MM}-fpm..." |
| 177 | + $SUDO systemctl reload "php${PHP_VER_MM}-fpm" || true |
| 178 | + ok "php${PHP_VER_MM}-fpm reloaded" |
| 179 | + elif systemctl list-units --type=service 2>/dev/null | grep -q "php-fpm\.service"; then |
| 180 | + step "🔁 Reloading php-fpm..." |
| 181 | + $SUDO systemctl reload "php-fpm" || true |
| 182 | + ok "php-fpm reloaded" |
| 183 | + fi |
| 184 | +fi |
| 185 | + |
| 186 | +echo "✅ Installation complete!" |
| 187 | +echo "" |
| 188 | +echo "File locations:" |
| 189 | +echo " • Binary: ${PHP_EXT_DIR}/${EXTENSION_NAME}.so" |
| 190 | +if [ "${#CONF_DIRS[@]}" -gt 0 ]; then |
| 191 | + for d in "${CONF_DIRS[@]}"; do |
| 192 | + echo " • Config: ${d}/${INI_NAME}" |
| 193 | + done |
| 194 | +else |
| 195 | + echo " • Config: (CLI scan dir via php --ini)" |
| 196 | +fi |
| 197 | +echo "" |
| 198 | + |
| 199 | + |
0 commit comments