|
#!/usr/bin/env bash |
|
# |
|
# Pin a specific version of GCC installed via Homebrew. |
|
# It is typical that GCC will be built from source. |
|
# |
|
# ./homebrew_gcc_pin.sh <version> |
|
|
|
set -Eeuo pipefail |
|
|
|
if (( $# != 1 )); then |
|
echo "Usage: $0 <version>" >&2 |
|
exit 2 |
|
fi |
|
|
|
gcc_version=$1 |
|
tap_name="${USER}/local" |
|
|
|
gcc_release=${gcc_version%%.*} |
|
|
|
without_git_signing() { |
|
env \ |
|
GIT_CONFIG_COUNT=1 \ |
|
GIT_CONFIG_KEY_0=commit.gpgsign \ |
|
GIT_CONFIG_VALUE_0=false \ |
|
"$@" |
|
} |
|
|
|
if ! brew tap | grep -Fqx -- "$tap_name"; then |
|
without_git_signing brew tap-new "$tap_name" |
|
fi |
|
|
|
tap_dir=$(brew --repository "$tap_name") |
|
if ! git -C "$tap_dir" rev-parse --verify HEAD >/dev/null 2>&1; then |
|
without_git_signing git -C "$tap_dir" commit -m "Create $tap_name tap" |
|
fi |
|
|
|
if brew tap | grep -Fqx -- "homebrew/core"; then |
|
echo "homebrew/core tap is already installed." |
|
else |
|
echo "homebrew/core tap needed, tapping it now..." |
|
brew tap --force homebrew/core |
|
fi |
|
|
|
# Extract the GCC formula definition from homebrew-core history |
|
extract_status=0 |
|
if ! brew extract --version="${gcc_version}" gcc "$tap_name"; then |
|
extract_status=$? |
|
fi |
|
|
|
if (( extract_status != 0 )); then |
|
exit "$extract_status" |
|
fi |
|
|
|
# Homebrew requires custom-tap formulas to be trusted before installation. |
|
brew trust --formula "${tap_name}/gcc@${gcc_version}" |
|
|
|
# Avoid auto-linking into the shared Homebrew prefix so multiple GCC versions can coexist. |
|
# Use the versioned binary path directly when you need a specific compiler. |
|
HOMEBREW_NO_AUTO_LINK=1 brew install "gcc@${gcc_version}" |
|
|
|
versioned_prefix="/opt/homebrew/opt/gcc@${gcc_version}" |
|
versioned_bin="${versioned_prefix}/bin" |
|
|
|
gcc_script="$HOME/gcc-${gcc_version}.sh" |
|
|
|
if [[ -d "$versioned_bin" ]]; then |
|
echo |
|
echo "Installed GCC ${gcc_version} is available at:" |
|
echo " ${versioned_bin}" |
|
if [[ -f "$gcc_script" ]]; then |
|
echo |
|
echo "To use this compiler, make a script like $gcc_script:" |
|
echo |
|
echo " export CC=${versioned_bin}/gcc-${gcc_release}" |
|
echo " export CXX=${versioned_bin}/g++-${gcc_release}" |
|
echo " export FC=${versioned_bin}/gfortran-${gcc_release}" |
|
else |
|
echo "export CC=${versioned_bin}/gcc-${gcc_release}" >> "$gcc_script" |
|
echo "export CXX=${versioned_bin}/g++-${gcc_release}" >> "$gcc_script" |
|
echo "export FC=${versioned_bin}/gfortran-${gcc_release}" >> "$gcc_script" |
|
echo "To use this compiler, source the script:" |
|
echo |
|
echo " source $gcc_script" |
|
echo |
|
echo "which contains: " |
|
cat "$gcc_script" |
|
fi |
|
fi |
|
|
|
echo "if on using this GCC ${gcc_version} there are errors with stdlib headers, try using SDKROOT environment variable." |
|
echo "For an older GCC like 15.x you might need say:" |
|
echo "export SDKROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/" |
|
echo "check what directories like that exist and try." |
|
echo "reference:" |
|
echo "https://gist.github.com/scivision/d69faebbc56da9714798087b56de925a" |