Skip to content
Open
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
39 changes: 7 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,42 +62,17 @@ Additional options can be specified when installing Go:
-h, --help Display this message.

### A Note on Compiling Go 1.5+
Go 1.5+ removed the C compilers from the toolchain and [replaced][compiler_note] them with one written in Go. Obviously, this creates a bootstrapping problem if you don't already have a working Go install. In order to compile Go 1.5+, make sure Go 1.4 is installed first. If Go 1.4 won't install try a later version (e.g. go1.5), just make sure you have the `-B` option after the version number.
Go 1.5+ removed the C compilers from the toolchain and replaced them with one written in Go. GVM handles this bootstrapping problem automatically. When you install a version of Go from source that requires a bootstrap compiler, GVM will:

```
gvm install go1.4 -B
gvm use go1.4
export GOROOT_BOOTSTRAP=$GOROOT
gvm install go1.7
```

### A Note on ARMv6 and ARMv7 architectures (32 bit)
Binary versions for ARMv6 architecture are available [starting from Go 1.6](https://go.dev/dl/#go1.6). So, it is necessary to bootstrap with an existing binary version, then it will be possible compiling other versions. For instance, to bootstrap a setup, version `1.21.0` may be used:

```
gvm install go1.21.0 -B
gvm use go1.21.0
```
1. Search your installed versions for a compatible bootstrap Go.
2. If none is found, it will automatically download and install the required bootstrap version as a binary.
3. Use that binary to compile your target version.

And then, compile any other version:
This allows you to install any version of Go (including `master`) on a clean system without any pre-existing Go installation.

```
gvm install go1.20.7
```

#### To install Go 1.20+
Go 1.20+ requires go1.17.3+. Use the below:
### A Note on ARMv6 and ARMv7 architectures (32 bit)
Binary versions for ARMv6 architecture are available [starting from Go 1.6](https://go.dev/dl/#go1.6). GVM will automatically pull a compatible binary to bootstrap source installations on ARM platforms as well.

```
gvm install go1.4 -B
gvm use go1.4
export GOROOT_BOOTSTRAP=$GOROOT
gvm install go1.17.13
gvm use go1.17.13
export GOROOT_BOOTSTRAP=$GOROOT
gvm install go1.20
gvm use go1.20
```

[compiler_note]: https://docs.google.com/document/d/1OaatvGhEAq7VseQ9kkavxKNAfepWy2yhPUBs96FGV28/edit

Expand Down
154 changes: 154 additions & 0 deletions scripts/function/gvm_bootstrap
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
#!/usr/bin/env bash

__gvm_get_required_bootstrap_version() {
local version=$1
if [[ "$version" == "master" ]]; then
echo "1.22.6"
return 0
fi

local semver=$(extract_version "$version")

# Check for non-numeric versions (like tip, etc)
if [[ ! "$semver" =~ ^[0-9]+(\.[0-9]+)*$ ]]; then
# Default to latest bootstrap for unknown versions
echo "1.22.6"
return 0
fi

# Go 1.24+ needs Go 1.22.6+
compare_version "$semver" "1.24"
if [[ $? -ne 2 ]]; then
echo "1.22.6"
return 0
fi

# Go 1.22+ needs Go 1.20+
compare_version "$semver" "1.22"
if [[ $? -ne 2 ]]; then
echo "1.20.14"
return 0
fi

# Go 1.20+ needs Go 1.17.13+
compare_version "$semver" "1.20"
if [[ $? -ne 2 ]]; then
echo "1.17.13"
return 0
fi

# Go 1.5+ needs Go 1.4+
compare_version "$semver" "1.5"
if [[ $? -ne 2 ]]; then
echo "1.4.3"
return 0
fi

echo ""
return 1
}

__gvm_find_best_installed_bootstrap() {
local min_version=$1
local best_version=""
local best_semver=""

if [[ ! -d "$GVM_ROOT/gos" ]]; then
return 1
fi

for v_dir in "$GVM_ROOT/gos"/*; do
[[ -d "$v_dir" ]] || continue
[[ -x "$v_dir/bin/go" ]] || continue
local v_name=$(basename "$v_dir")
local v_semver=$(extract_version "$v_name")

# Only consider numeric versions
if [[ ! "$v_semver" =~ ^[0-9]+(\.[0-9]+)*$ ]]; then
continue
fi

compare_version "$v_semver" "$min_version"
if [[ $? -ne 2 ]]; then # v_semver >= min_version
if [[ -z "$best_version" ]]; then
best_version=$v_name
best_semver=$v_semver
else
compare_version "$v_semver" "$best_semver"
if [[ $? -eq 1 ]]; then # v_semver > best_semver
best_version=$v_name
best_semver=$v_semver
fi
fi
fi
done

if [[ -n "$best_version" ]]; then
echo "$best_version"
return 0
fi
return 1
}

__gvm_is_bootstrap_compatible() {
local target=$1
local bootstrap_path=$2

local req_version=$(__gvm_get_required_bootstrap_version "$target")
if [[ -z "$req_version" ]]; then
return 0 # No bootstrap needed
fi

if [[ -z "$bootstrap_path" ]]; then
return 1 # No bootstrap path provided
fi

if [[ ! -x "$bootstrap_path/bin/go" ]]; then
return 1 # Bootstrap path doesn't have a working go
fi

# Try to get the version of the bootstrap Go
local bootstrap_version_out=$("$bootstrap_path/bin/go" version 2>/dev/null)
if [[ $? -ne 0 ]]; then
return 1
fi

# Extract version from "go version go1.22.6 linux/amd64"
local bootstrap_version=$(echo "$bootstrap_version_out" | awk '{print $3}')
local bootstrap_semver=$(extract_version "$bootstrap_version")

compare_version "$bootstrap_semver" "$req_version"
if [[ $? -ne 2 ]]; then
return 0 # Compatible (>=)
fi

return 1 # Incompatible (<)
}

__gvm_ensure_bootstrap() {
local target_version=$1
local req_version=$(__gvm_get_required_bootstrap_version "$target_version")

if [[ -z "$req_version" ]]; then
return 0
fi

local bootstrap_version=$(__gvm_find_best_installed_bootstrap "$req_version")

if [[ -n "$bootstrap_version" ]]; then
export GOROOT_BOOTSTRAP="$GVM_ROOT/gos/$bootstrap_version"
display_message "Using $bootstrap_version as bootstrap"
return 0
fi

display_message "No suitable bootstrap Go version found. Installing go$req_version binary..."

# Use the absolute path to gvm to ensure we use the right one
"$GVM_ROOT/bin/gvm" install "go$req_version" --binary || {
display_error "Failed to install bootstrap Go version go$req_version"
return 1
}

export GOROOT_BOOTSTRAP="$GVM_ROOT/gos/go$req_version"
return 0
}
12 changes: 9 additions & 3 deletions scripts/install
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,13 @@ compile_go() {
MAKE_SCRIPT=make.bash
;;
esac
[ -z "$GOROOT_BOOTSTRAP" ] && export GOROOT_BOOTSTRAP=$(go env GOROOT)

[ -z "$GOROOT_BOOTSTRAP" ] && [ "$(command -v go)" ] && export GOROOT_BOOTSTRAP=$(go env GOROOT)

if ! __gvm_is_bootstrap_compatible "$GO_NAME" "$GOROOT_BOOTSTRAP"; then
__gvm_ensure_bootstrap "$GO_NAME" || display_fatal "Failed to ensure bootstrap Go version"
fi

unset GOARCH && unset GOOS && unset GOPATH && unset GOBIN && unset GOROOT &&
export GOBIN=$GO_INSTALL_ROOT/bin &&
export PATH=$GOBIN:$PATH &&
Expand Down Expand Up @@ -196,8 +202,8 @@ download_binary() {
GVM_ARCH="s390x"
fi

SEMVER=$(extract_version $VERSION)
compare_version $SEMVER "1.4.3"
SEMVER=$(extract_version "$VERSION")
compare_version "$SEMVER" "1.4.3"
if [ $? -eq 2 ]; then
GO_BINARY_FILE=${VERSION}.${GVM_OS}-${GVM_ARCH}${GVM_OS_VERSION}.tar.gz
else
Expand Down