ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/external/subpack/lang/golang/golang-build.sh b/external/subpack/lang/golang/golang-build.sh
new file mode 100644
index 0000000..5e40436
--- /dev/null
+++ b/external/subpack/lang/golang/golang-build.sh
@@ -0,0 +1,204 @@
+#!/bin/sh
+
+nl="
+"
+
+log() {
+	# shellcheck disable=SC2039
+	local IFS=" "
+	printf '%s\n' "$*"
+}
+
+log_error() {
+	# shellcheck disable=SC2039
+	local IFS=" "
+	printf 'Error: %s\n' "$*" >&2
+}
+
+link_contents() {
+	# shellcheck disable=SC2039
+	local src="$1" dest="$2" IFS="$nl" dirs dir base
+
+	if [ -n "$(find "$src" -mindepth 1 -maxdepth 1 -name "*.go" -not -type d)" ]; then
+		log_error "$src is already a Go library"
+		return 1
+	fi
+
+	dirs="$(find "$src" -mindepth 1 -maxdepth 1 -type d)"
+	for dir in $dirs; do
+		base="${dir##*/}"
+		if [ -d "$dest/$base" ]; then
+			case "$dir" in
+			*$GO_BUILD_DEPENDS_SRC/$GO_PKG)
+				log "$GO_PKG is already installed. Please check for circular dependencies."
+				;;
+			*)
+				link_contents "$src/$base" "$dest/$base"
+				;;
+			esac
+		else
+			log "...${src#$GO_BUILD_DEPENDS_SRC}/$base"
+			ln -sf "$src/$base" "$dest/$base"
+		fi
+	done
+
+	return 0
+}
+
+configure() {
+	# shellcheck disable=SC2039
+	local files code testdata gomod pattern extra IFS file dest
+
+	cd "$BUILD_DIR" || return 1
+
+	files="$(find ./ -path "*/.*" -prune -o -not -type d -print)"
+
+	if [ "$GO_INSTALL_ALL" != 1 ]; then
+		code="$(printf '%s\n' "$files" | grep '\.\(c\|cc\|cpp\|go\|h\|hh\|hpp\|proto\|s\)$')"
+		testdata="$(printf '%s\n' "$files" | grep '/testdata/')"
+		gomod="$(printf '%s\n' "$files" | grep '/go\.\(mod\|sum\)$')"
+
+		for pattern in $GO_INSTALL_EXTRA; do
+			extra="$(printf '%s\n' "$extra"; printf '%s\n' "$files" | grep -e "$pattern")"
+		done
+
+		files="$(printf '%s\n%s\n%s\n%s\n' "$code" "$testdata" "$gomod" "$extra" | grep -v '^[[:space:]]*$' | sort -u)"
+	fi
+
+	IFS="$nl"
+
+	log "Copying files from $BUILD_DIR into $GO_BUILD_DIR/src/$GO_PKG"
+	mkdir -p "$GO_BUILD_DIR/src"
+	for file in $files; do
+		log "${file#./}"
+		dest="$GO_BUILD_DIR/src/$GO_PKG/${file#./}"
+		mkdir -p "${dest%/*}"
+		cp -fpR "$file" "$dest"
+	done
+	log
+
+	if [ "$GO_SOURCE_ONLY" != 1 ]; then
+		if [ -d "$GO_BUILD_DEPENDS_SRC" ]; then
+			log "Symlinking directories from $GO_BUILD_DEPENDS_SRC into $GO_BUILD_DIR/src"
+			link_contents "$GO_BUILD_DEPENDS_SRC" "$GO_BUILD_DIR/src"
+		else
+			log "$GO_BUILD_DEPENDS_SRC does not exist, skipping symlinks"
+		fi
+	else
+		log "Not building binaries, skipping symlinks"
+	fi
+	log
+
+	return 0
+}
+
+build() {
+	# shellcheck disable=SC2039
+	local modargs pattern targets retval
+
+	cd "$GO_BUILD_DIR" || return 1
+
+	if [ -f "$BUILD_DIR/go.mod" ] ; then
+		mkdir -p "$GO_MOD_CACHE_DIR"
+		modargs="$GO_MOD_ARGS"
+	fi
+
+	log "Finding targets"
+	# shellcheck disable=SC2086
+	targets="$(go list $modargs $GO_BUILD_PKG)"
+	for pattern in $GO_EXCLUDES; do
+		targets="$(printf '%s\n' "$targets" | grep -v "$pattern")"
+	done
+	log
+
+	if [ "$GO_GO_GENERATE" = 1 ]; then
+		log "Calling go generate"
+		# shellcheck disable=SC2086
+		GOOS='' GOARCH='' GO386='' GOARM='' GOMIPS='' GOMIPS64='' \
+		go generate -v $targets
+		log
+	fi
+
+	if [ "$GO_SOURCE_ONLY" = 1 ]; then
+		return 0
+	fi
+
+	log "Building targets"
+	mkdir -p "$GO_BUILD_DIR/bin" "$GO_BUILD_CACHE_DIR"
+	# shellcheck disable=SC2086
+	go install $modargs "$@" $targets
+	retval="$?"
+	log
+
+	if [ "$retval" -eq 0 ] && [ -z "$(find "$GO_BUILD_BIN_DIR" -maxdepth 0 -type d -not -empty 2>/dev/null)" ]; then
+		log_error "No binaries were built"
+		retval=1
+	fi
+
+	if [ "$retval" -ne 0 ]; then
+		cache_cleanup
+	fi
+
+	return "$retval"
+}
+
+install_bin() {
+	# shellcheck disable=SC2039
+	local dest="$1"
+	install -d -m0755 "$dest/$GO_INSTALL_BIN_PATH"
+	install -m0755 "$GO_BUILD_BIN_DIR"/* "$dest/$GO_INSTALL_BIN_PATH/"
+}
+
+install_src() {
+	# shellcheck disable=SC2039
+	local dest="$1" dir="${GO_PKG%/*}"
+	install -d -m0755 "$dest/$GO_BUILD_DEPENDS_PATH/src/$dir"
+	cp -fpR "$GO_BUILD_DIR/src/$GO_PKG" "$dest/$GO_BUILD_DEPENDS_PATH/src/$dir/"
+}
+
+cache_cleanup() {
+	if ! [ -d "$GO_MOD_CACHE_DIR" ]; then
+		return 0
+	fi
+
+	# in case go is called without -modcacherw
+	find "$GO_MOD_CACHE_DIR" -type d -not -perm -u+w -exec chmod u+w '{}' +
+
+	if [ -n "$CONFIG_GOLANG_MOD_CACHE_WORLD_READABLE" ]; then
+		find "$GO_MOD_CACHE_DIR"      -type d -not -perm -go+rx -exec chmod go+rx '{}' +
+		find "$GO_MOD_CACHE_DIR" -not -type d -not -perm -go+r  -exec chmod go+r  '{}' +
+	fi
+
+	return 0
+}
+
+
+if [ "$#" -lt 1 ]; then
+	log_error "Missing command"
+	exit 1
+fi
+
+command="$1"
+shift 1
+
+case "$command" in
+	configure)
+		configure
+		;;
+	build)
+		build "$@"
+		;;
+	install_bin)
+		install_bin "$@"
+		;;
+	install_src)
+		install_src "$@"
+		;;
+	cache_cleanup)
+		cache_cleanup
+		;;
+	*)
+		log_error "Invalid command \"$command\""
+		exit 1
+		;;
+esac
diff --git a/external/subpack/lang/golang/golang-compiler.mk b/external/subpack/lang/golang/golang-compiler.mk
new file mode 100644
index 0000000..c6c8360
--- /dev/null
+++ b/external/subpack/lang/golang/golang-compiler.mk
@@ -0,0 +1,186 @@
+#
+# Copyright (C) 2018, 2020 Jeffery To
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+ifeq ($(origin GO_INCLUDE_DIR),undefined)
+  GO_INCLUDE_DIR:=$(dir $(lastword $(MAKEFILE_LIST)))
+endif
+
+include $(GO_INCLUDE_DIR)/golang-values.mk
+
+
+# $(1) valid GOOS_GOARCH combinations
+# $(2) go version id
+define GoCompiler/Default/CheckHost
+	$(if $(filter $(GO_HOST_OS_ARCH),$(1)),,$(error go-$(2) cannot be installed on $(GO_HOST_OS)/$(GO_HOST_ARCH)))
+endef
+
+# $(1) source go root
+# $(2) destination prefix
+# $(3) go version id
+# $(4) additional environment variables (optional)
+define GoCompiler/Default/Make
+	( \
+		cd "$(1)/src" ; \
+		$(if $(2),GOROOT_FINAL="$(2)/lib/go-$(3)") \
+		$(4) \
+		$(BASH) make.bash --no-banner ; \
+	)
+endef
+
+# $(1) destination prefix
+# $(2) go version id
+define GoCompiler/Default/Install/make-dirs
+	$(INSTALL_DIR) "$(1)/lib/go-$(2)"
+	$(INSTALL_DIR) "$(1)/share/go-$(2)"
+endef
+
+# $(1) source go root
+# $(2) destination prefix
+# $(3) go version id
+# $(4) file/directory name
+define GoCompiler/Default/Install/install-share-data
+	$(CP) "$(1)/$(4)" "$(2)/share/go-$(3)/"
+	$(LN) "../../share/go-$(3)/$(4)" "$(2)/lib/go-$(3)/"
+endef
+
+# $(1) source go root
+# $(2) destination prefix
+# $(3) go version id
+# $(4) GOOS_GOARCH
+# $(5) install suffix (optional)
+define GoCompiler/Default/Install/Bin
+	$(call GoCompiler/Default/Install/make-dirs,$(2),$(3))
+
+	$(call GoCompiler/Default/Install/install-share-data,$(1),$(2),$(3),api)
+
+	$(INSTALL_DATA) -p "$(1)/VERSION" "$(2)/lib/go-$(3)/"
+
+	for file in AUTHORS CONTRIBUTING.md CONTRIBUTORS LICENSE PATENTS README.md SECURITY.md; do \
+		if [ -f "$(1)/$$$$file" ]; then \
+			$(INSTALL_DATA) -p "$(1)/$$$$file" "$(2)/share/go-$(3)/" ; \
+		fi ; \
+	done
+
+	$(INSTALL_DIR) "$(2)/lib/go-$(3)/bin"
+
+  ifeq ($(4),$(GO_HOST_OS_ARCH))
+	$(INSTALL_BIN) -p "$(1)/bin"/* "$(2)/lib/go-$(3)/bin/"
+  else
+	$(INSTALL_BIN) -p "$(1)/bin/$(4)"/* "$(2)/lib/go-$(3)/bin/"
+  endif
+
+	$(INSTALL_DIR) "$(2)/lib/go-$(3)/pkg"
+	$(CP) "$(1)/pkg/$(4)$(if $(5),_$(5))" "$(2)/lib/go-$(3)/pkg/"
+
+	$(INSTALL_DIR) "$(2)/lib/go-$(3)/pkg/tool/$(4)"
+	$(INSTALL_BIN) -p "$(1)/pkg/tool/$(4)"/* "$(2)/lib/go-$(3)/pkg/tool/$(4)/"
+endef
+
+# $(1) destination prefix
+# $(2) go version id
+define GoCompiler/Default/Install/BinLinks
+	$(INSTALL_DIR) "$(1)/bin"
+	$(LN) "../lib/go-$(2)/bin/go" "$(1)/bin/go"
+	$(LN) "../lib/go-$(2)/bin/gofmt" "$(1)/bin/gofmt"
+endef
+
+# $(1) source go root
+# $(2) destination prefix
+# $(3) go version id
+define GoCompiler/Default/Install/Doc
+	$(call GoCompiler/Default/Install/make-dirs,$(2),$(3))
+
+	$(call GoCompiler/Default/Install/install-share-data,$(1),$(2),$(3),doc)
+endef
+
+# $(1) source go root
+# $(2) destination prefix
+# $(3) go version id
+define GoCompiler/Default/Install/Src
+	$(call GoCompiler/Default/Install/make-dirs,$(2),$(3))
+
+	$(call GoCompiler/Default/Install/install-share-data,$(1),$(2),$(3),lib)
+	$(call GoCompiler/Default/Install/install-share-data,$(1),$(2),$(3),misc)
+	$(call GoCompiler/Default/Install/install-share-data,$(1),$(2),$(3),src)
+	$(call GoCompiler/Default/Install/install-share-data,$(1),$(2),$(3),test)
+
+	$(FIND) \
+		"$(2)/share/go-$(3)/src/" \
+		\! -type d -a \( -name "*.bat" -o -name "*.rc" \) \
+		-delete
+
+	if [ -d "$(1)/pkg/include" ]; then \
+		$(INSTALL_DIR) "$(2)/lib/go-$(3)/pkg" ; \
+		$(INSTALL_DIR) "$(2)/share/go-$(3)/pkg" ; \
+		$(CP) "$(1)/pkg/include" "$(2)/share/go-$(3)/pkg/" ; \
+		$(LN) "../../../share/go-$(3)/pkg/include" "$(2)/lib/go-$(3)/pkg/" ; \
+	fi
+endef
+
+# $(1) destination prefix
+# $(2) go version id
+define GoCompiler/Default/Uninstall
+	rm -rf "$(1)/lib/go-$(2)"
+	rm -rf "$(1)/share/go-$(2)"
+endef
+
+# $(1) destination prefix
+define GoCompiler/Default/Uninstall/BinLinks
+	rm -f "$(1)/bin/go"
+	rm -f "$(1)/bin/gofmt"
+endef
+
+
+# $(1) profile name
+# $(2) source go root
+# $(3) destination prefix
+# $(4) go version id
+# $(5) GOOS_GOARCH
+# $(6) install suffix (optional)
+define GoCompiler/AddProfile
+
+  # $$(1) valid GOOS_GOARCH combinations
+  define GoCompiler/$(1)/CheckHost
+	$$(call GoCompiler/Default/CheckHost,$$(1),$(4))
+  endef
+
+  # $$(1) additional environment variables (optional)
+  define GoCompiler/$(1)/Make
+	$$(call GoCompiler/Default/Make,$(2),$(3),$(4),$$(1))
+  endef
+
+  # $$(1) override install prefix (optional)
+  define GoCompiler/$(1)/Install/Bin
+	$$(call GoCompiler/Default/Install/Bin,$(2),$$(or $$(1),$(3)),$(4),$(5),$(6))
+  endef
+
+  # $$(1) override install prefix (optional)
+  define GoCompiler/$(1)/Install/BinLinks
+	$$(call GoCompiler/Default/Install/BinLinks,$$(or $$(1),$(3)),$(4))
+  endef
+
+  # $$(1) override install prefix (optional)
+  define GoCompiler/$(1)/Install/Doc
+	$$(call GoCompiler/Default/Install/Doc,$(2),$$(or $$(1),$(3)),$(4))
+  endef
+
+  # $$(1) override install prefix (optional)
+  define GoCompiler/$(1)/Install/Src
+	$$(call GoCompiler/Default/Install/Src,$(2),$$(or $$(1),$(3)),$(4))
+  endef
+
+  # $$(1) override install prefix (optional)
+  define GoCompiler/$(1)/Uninstall
+	$$(call GoCompiler/Default/Uninstall,$$(or $$(1),$(3)),$(4))
+  endef
+
+  # $$(1) override install prefix (optional)
+  define GoCompiler/$(1)/Uninstall/BinLinks
+	$$(call GoCompiler/Default/Uninstall/BinLinks,$$(or $$(1),$(3)))
+  endef
+
+endef
diff --git a/external/subpack/lang/golang/golang-host-build.mk b/external/subpack/lang/golang/golang-host-build.mk
new file mode 100644
index 0000000..ee4f1ea
--- /dev/null
+++ b/external/subpack/lang/golang/golang-host-build.mk
@@ -0,0 +1,220 @@
+#
+# Copyright (C) 2020 Jeffery To
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+ifeq ($(origin GO_INCLUDE_DIR),undefined)
+  GO_INCLUDE_DIR:=$(dir $(lastword $(MAKEFILE_LIST)))
+endif
+
+include $(GO_INCLUDE_DIR)/golang-values.mk
+
+
+# these variables have the same meanings as in golang-package.mk
+GO_HOST_INSTALL_EXTRA?=$(GO_PKG_INSTALL_EXTRA)
+GO_HOST_INSTALL_ALL?=$(GO_PKG_INSTALL_ALL)
+GO_HOST_SOURCE_ONLY?=$(GO_PKG_SOURCE_ONLY)
+GO_HOST_BUILD_PKG?=$(GO_PKG_BUILD_PKG)
+GO_HOST_EXCLUDES?=$(GO_PKG_EXCLUDES)
+GO_HOST_GO_GENERATE?=$(GO_PKG_GO_GENERATE)
+GO_HOST_GCFLAGS?=$(GO_PKG_GCFLAGS)
+GO_HOST_LDFLAGS?=$(GO_PKG_LDFLAGS)
+GO_HOST_LDFLAGS_X?=$(GO_PKG_LDFLAGS_X)
+GO_HOST_TAGS?=$(GO_PKG_TAGS)
+GO_HOST_INSTALL_BIN_PATH?=/bin
+
+
+# need to repeat this here in case golang-package.mk is not included
+GO_PKG_BUILD_PKG?=$(strip $(GO_PKG))/...
+
+GO_HOST_WORK_DIR_NAME:=.go_work
+GO_HOST_BUILD_DIR=$(HOST_BUILD_DIR)/$(GO_HOST_WORK_DIR_NAME)/build
+GO_HOST_BUILD_BIN_DIR=$(GO_HOST_BUILD_DIR)/bin
+
+GO_HOST_BUILD_DEPENDS_PATH:=/share/gocode
+GO_HOST_BUILD_DEPENDS_SRC=$(STAGING_DIR_HOSTPKG)$(GO_HOST_BUILD_DEPENDS_PATH)/src
+
+GO_HOST_DIR_NAME:=$(lastword $(subst /,$(space),$(CURDIR)))
+GO_HOST_STAGING_DIR:=$(TMP_DIR)/host-stage-$(GO_HOST_DIR_NAME)
+GO_HOST_STAGING_FILES_LIST_DIR:=$(HOST_BUILD_PREFIX)/stamp
+GO_HOST_BIN_STAGING_FILES_LIST:=$(GO_HOST_STAGING_FILES_LIST_DIR)/$(GO_HOST_DIR_NAME)-bin.list
+GO_HOST_SRC_STAGING_FILES_LIST:=$(GO_HOST_STAGING_FILES_LIST_DIR)/$(GO_HOST_DIR_NAME)-src.list
+
+ifeq ($(GO_HOST_PIE_SUPPORTED),1)
+  GO_HOST_ENABLE_PIE:=1
+endif
+
+GO_HOST_BUILD_CONFIG_VARS= \
+	GO_PKG="$(strip $(GO_PKG))" \
+	GO_INSTALL_EXTRA="$(strip $(GO_HOST_INSTALL_EXTRA))" \
+	GO_INSTALL_ALL="$(strip $(GO_HOST_INSTALL_ALL))" \
+	GO_SOURCE_ONLY="$(strip $(GO_HOST_SOURCE_ONLY))" \
+	GO_BUILD_PKG="$(strip $(GO_HOST_BUILD_PKG))" \
+	GO_EXCLUDES="$(strip $(GO_HOST_EXCLUDES))" \
+	GO_GO_GENERATE="$(strip $(GO_HOST_GO_GENERATE))" \
+	GO_INSTALL_BIN_PATH="$(strip $(GO_HOST_INSTALL_BIN_PATH))" \
+	BUILD_DIR="$(HOST_BUILD_DIR)" \
+	GO_BUILD_DIR="$(GO_HOST_BUILD_DIR)" \
+	GO_BUILD_BIN_DIR="$(GO_HOST_BUILD_BIN_DIR)" \
+	GO_BUILD_DEPENDS_PATH="$(GO_HOST_BUILD_DEPENDS_PATH)" \
+	GO_BUILD_DEPENDS_SRC="$(GO_HOST_BUILD_DEPENDS_SRC)"
+
+GO_HOST_MORE_CFLAGS?= \
+	-Wformat -Werror=format-security \
+	-fstack-protector-strong \
+	-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 \
+	-Wl,-z,now -Wl,-z,relro \
+	$(if $(GO_HOST_ENABLE_PIE),$(FPIC))
+
+GO_HOST_MORE_LDFLAGS?= \
+	-znow -zrelro \
+	$(if $(GO_HOST_ENABLE_PIE),$(FPIC) -specs=$(INCLUDE_DIR)/hardened-ld-pie.specs)
+
+GO_HOST_TARGET_VARS= \
+	CGO_ENABLED=1 \
+	CC=gcc \
+	CXX=g++ \
+	PKG_CONFIG=pkg-config \
+	CGO_CFLAGS="$(HOST_CFLAGS) $(GO_HOST_MORE_CFLAGS)" \
+	CGO_CPPFLAGS="$(HOST_CPPFLAGS) $(GO_HOST_MORE_CPPFLAGS)" \
+	CGO_CXXFLAGS="$(HOST_CFLAGS) $(GO_HOST_MORE_CFLAGS)" \
+	CGO_LDFLAGS="$(HOST_LDFLAGS) $(GO_HOST_MORE_LDFLAGS)" \
+	GO_GCC_HELPER_CC="$(HOSTCC)" \
+	GO_GCC_HELPER_CXX="$(HOSTCXX)" \
+	GO_GCC_HELPER_PATH="$$$$PATH" \
+	PATH="$(STAGING_DIR_HOSTPKG)/lib/go-cross/openwrt:$$$$PATH"
+
+GO_HOST_BUILD_VARS= \
+	GOPATH="$(GO_HOST_BUILD_DIR)" \
+	GOCACHE="$(GO_BUILD_CACHE_DIR)" \
+	GOMODCACHE="$(GO_MOD_CACHE_DIR)" \
+	GOENV=off
+
+GO_HOST_VARS= \
+	$(GO_HOST_TARGET_VARS) \
+	$(GO_HOST_BUILD_VARS)
+
+GO_HOST_DEFAULT_LDFLAGS= \
+	-linkmode external \
+	-extldflags '$(patsubst -z%,-Wl$(comma)-z$(comma)%,$(HOST_LDFLAGS) $(GO_HOST_MORE_LDFLAGS))'
+
+GO_HOST_CUSTOM_LDFLAGS= \
+	$(GO_HOST_LDFLAGS) \
+	$(patsubst %,-X %,$(GO_HOST_LDFLAGS_X))
+
+GO_HOST_INSTALL_ARGS= \
+	-v \
+	-ldflags "all=$(GO_HOST_DEFAULT_LDFLAGS)" \
+	$(if $(filter $(GO_HOST_ENABLE_PIE),1),-buildmode pie) \
+	$(if $(GO_HOST_GCFLAGS),-gcflags "$(GO_HOST_GCFLAGS)") \
+	$(if $(GO_HOST_CUSTOM_LDFLAGS),-ldflags "$(GO_HOST_CUSTOM_LDFLAGS) $(GO_HOST_DEFAULT_LDFLAGS)") \
+	$(if $(GO_HOST_TAGS),-tags "$(GO_HOST_TAGS)")
+
+define GoHost/Host/Configure
+	$(GO_GENERAL_BUILD_CONFIG_VARS) \
+	$(GO_HOST_BUILD_CONFIG_VARS) \
+	$(SHELL) $(GO_INCLUDE_DIR)/golang-build.sh configure
+endef
+
+# $(1) additional arguments for go command line (optional)
+define GoHost/Host/Compile
+	$(GO_GENERAL_BUILD_CONFIG_VARS) \
+	$(GO_HOST_BUILD_CONFIG_VARS) \
+	$(GO_HOST_VARS) \
+	$(SHELL) $(GO_INCLUDE_DIR)/golang-build.sh build $(GO_HOST_INSTALL_ARGS) $(1)
+endef
+
+define GoHost/Host/Install/Bin
+	rm -rf "$(GO_HOST_STAGING_DIR)"
+	mkdir -p "$(GO_HOST_STAGING_DIR)" "$(GO_HOST_STAGING_FILES_LIST_DIR)"
+
+	$(GO_GENERAL_BUILD_CONFIG_VARS) \
+	$(GO_HOST_BUILD_CONFIG_VARS) \
+	$(SHELL) $(GO_INCLUDE_DIR)/golang-build.sh install_bin "$(GO_HOST_STAGING_DIR)"
+
+	if [ -f "$(GO_HOST_BIN_STAGING_FILES_LIST)" ]; then \
+		"$(SCRIPT_DIR)/clean-package.sh" \
+			"$(GO_HOST_BIN_STAGING_FILES_LIST)" \
+			"$(1)" ; \
+	fi
+
+	cd "$(GO_HOST_STAGING_DIR)" && find ./ > "$(GO_HOST_STAGING_DIR).files"
+
+	$(call locked, \
+		mv "$(GO_HOST_STAGING_DIR).files" "$(GO_HOST_BIN_STAGING_FILES_LIST)" && \
+		$(CP) "$(GO_HOST_STAGING_DIR)"/* "$(1)/", \
+		host-staging-dir \
+	)
+
+	rm -rf "$(GO_HOST_STAGING_DIR)"
+endef
+
+define GoHost/Host/Install/Src
+	rm -rf "$(GO_HOST_STAGING_DIR)"
+	mkdir -p "$(GO_HOST_STAGING_DIR)" "$(GO_HOST_STAGING_FILES_LIST_DIR)"
+
+	$(GO_GENERAL_BUILD_CONFIG_VARS) \
+	$(GO_HOST_BUILD_CONFIG_VARS) \
+	$(SHELL) $(GO_INCLUDE_DIR)/golang-build.sh install_src "$(GO_HOST_STAGING_DIR)"
+
+	if [ -f "$(GO_HOST_SRC_STAGING_FILES_LIST)" ]; then \
+		"$(SCRIPT_DIR)/clean-package.sh" \
+			"$(GO_HOST_SRC_STAGING_FILES_LIST)" \
+			"$(1)" ; \
+	fi
+
+	cd "$(GO_HOST_STAGING_DIR)" && find ./ > "$(GO_HOST_STAGING_DIR).files"
+
+	$(call locked, \
+		mv "$(GO_HOST_STAGING_DIR).files" "$(GO_HOST_SRC_STAGING_FILES_LIST)" && \
+		$(CP) "$(GO_HOST_STAGING_DIR)"/* "$(1)/", \
+		host-staging-dir \
+	)
+
+	rm -rf "$(GO_HOST_STAGING_DIR)"
+endef
+
+define GoHost/Host/Install
+	$(if $(filter $(GO_HOST_SOURCE_ONLY),1),, \
+		$(call GoHost/Host/Install/Bin,$(1)) \
+	)
+	$(call GoHost/Host/Install/Src,$(1))
+endef
+
+define GoHost/Host/Uninstall
+	if [ -f "$(GO_HOST_BIN_STAGING_FILES_LIST)" ]; then \
+		"$(SCRIPT_DIR)/clean-package.sh" \
+			"$(GO_HOST_BIN_STAGING_FILES_LIST)" \
+			"$(HOST_BUILD_PREFIX)" ; \
+		rm -f "$(GO_HOST_BIN_STAGING_FILES_LIST)" ; \
+	fi
+
+	if [ -f "$(GO_HOST_SRC_STAGING_FILES_LIST)" ]; then \
+		"$(SCRIPT_DIR)/clean-package.sh" \
+			"$(GO_HOST_SRC_STAGING_FILES_LIST)" \
+			"$(HOST_BUILD_PREFIX)" ; \
+		rm -f "$(GO_HOST_SRC_STAGING_FILES_LIST)" ; \
+	fi
+endef
+
+
+ifneq ($(strip $(GO_PKG)),)
+  Host/Configure=$(call GoHost/Host/Configure)
+  Host/Compile=$(call GoHost/Host/Compile)
+  Hooks/HostCompile/Post+=Go/CacheCleanup
+  Host/Uninstall=$(call GoHost/Host/Uninstall,$(1))
+endif
+
+define GoHostBuild
+  Host/Install=$$(call GoHost/Host/Install,$$(1))
+endef
+
+define GoBinHostBuild
+  Host/Install=$$(call GoHost/Host/Install/Bin,$$(1))
+endef
+
+define GoSrcHostBuild
+  Host/Install=$$(call GoHost/Host/Install/Src,$$(1))
+endef
diff --git a/external/subpack/lang/golang/golang-package.mk b/external/subpack/lang/golang/golang-package.mk
new file mode 100644
index 0000000..7144a45
--- /dev/null
+++ b/external/subpack/lang/golang/golang-package.mk
@@ -0,0 +1,327 @@
+#
+# Copyright (C) 2018-2020 Jeffery To
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+ifeq ($(origin GO_INCLUDE_DIR),undefined)
+  GO_INCLUDE_DIR:=$(dir $(lastword $(MAKEFILE_LIST)))
+endif
+
+include $(GO_INCLUDE_DIR)/golang-values.mk
+
+
+# Variables (all optional, except GO_PKG) to be set in package
+# Makefiles:
+#
+# GO_PKG (required) - name of Go package
+#
+#   Go name of the package.
+#
+#   e.g. GO_PKG:=golang.org/x/text
+#
+#
+# GO_PKG_INSTALL_EXTRA - list of regular expressions, default empty
+#
+#   Additional files/directories to install. By default, only these
+#   files are installed:
+#
+#   * Files with one of these extensions:
+#     .go, .c, .cc, .cpp, .h, .hh, .hpp, .proto, .s
+#
+#   * Files in any 'testdata' directory
+#
+#   * go.mod and go.sum, in any directory
+#
+#   e.g. GO_PKG_INSTALL_EXTRA:=example.toml marshal_test.toml
+#
+#
+# GO_PKG_INSTALL_ALL - boolean (0 or 1), default false
+#
+#   If true, install all files regardless of extension or directory.
+#
+#   e.g. GO_PKG_INSTALL_ALL:=1
+#
+#
+# GO_PKG_SOURCE_ONLY - boolean (0 or 1), default false
+#
+#   If true, 'go install' will not be called. If the package does not
+#   (or should not) build any binaries, then specifying this option will
+#   save build time.
+#
+#   e.g. GO_PKG_SOURCE_ONLY:=1
+#
+#
+# GO_PKG_BUILD_PKG - list of build targets, default GO_PKG/...
+#
+#   Build targets for compiling this Go package, i.e. arguments passed
+#   to 'go install'.
+#
+#   e.g. GO_PKG_BUILD_PKG:=github.com/debian/ratt/cmd/...
+#
+#
+# GO_PKG_EXCLUDES - list of regular expressions, default empty
+#
+#   Patterns to exclude from the build targets expanded from
+#   GO_PKG_BUILD_PKG.
+#
+#   e.g. GO_PKG_EXCLUDES:=examples/
+#
+#
+# GO_PKG_GO_GENERATE - boolean (0 or 1), default false
+#
+#   If true, 'go generate' will be called on all build targets (as
+#   determined by GO_PKG_BUILD_PKG and GO_PKG_EXCLUDES). This is usually
+#   not necessary.
+#
+#   e.g. GO_PKG_GO_GENERATE:=1
+#
+#
+# GO_PKG_GCFLAGS - list of options, default empty
+#
+#   Additional go tool compile options to use when building targets.
+#
+#   e.g. GO_PKG_GCFLAGS:=-N -l
+#
+#
+# GO_PKG_LDFLAGS - list of options, default empty
+#
+#   Additional go tool link options to use when building targets.
+#
+#   Note that the OpenWrt build system has an option to strip binaries
+#   (enabled by default), so -s (Omit the symbol table and debug
+#   information) and -w (Omit the DWARF symbol table) flags are not
+#   necessary.
+#
+#   e.g. GO_PKG_LDFLAGS:=-r dir1:dir2 -u
+#
+#
+# GO_PKG_LDFLAGS_X - list of string variable definitions, default empty
+#
+#   Each definition will be passed as the parameter to the -X go tool
+#   link option, i.e. -ldflags "-X importpath.name=value".
+#
+#   e.g. GO_PKG_LDFLAGS_X:=main.Version=$(PKG_VERSION) main.BuildStamp=$(SOURCE_DATE_EPOCH)
+#
+#
+# GO_PKG_TAGS - list of build tags, default empty
+#
+#   Build tags to consider satisfied during the build, passed as the
+#   parameter to the -tags option for 'go install'.
+#
+#   e.g. GO_PKG_TAGS:=release,noupgrade
+#
+#
+# GO_PKG_INSTALL_BIN_PATH - target directory path, default /usr/bin
+#
+#   Directory path under "dest_dir" where binaries will be installed by
+#   '$(call GoPackage/Package/Install/Bin,dest_dir)'.
+#
+#   e.g. GO_PKG_INSTALL_BIN_PATH:=/sbin
+
+# Credit for this package build process (GoPackage/Build/Configure and
+# GoPackage/Build/Compile) belong to Debian's dh-golang completely.
+# https://salsa.debian.org/go-team/packages/dh-golang
+
+
+GO_PKG_BUILD_PKG?=$(strip $(GO_PKG))/...
+GO_PKG_INSTALL_BIN_PATH?=/usr/bin
+
+GO_PKG_WORK_DIR_NAME:=.go_work
+GO_PKG_BUILD_DIR=$(PKG_BUILD_DIR)/$(GO_PKG_WORK_DIR_NAME)/build
+GO_PKG_BUILD_BIN_DIR=$(GO_PKG_BUILD_DIR)/bin$(if $(GO_HOST_TARGET_DIFFERENT),/$(GO_OS_ARCH))
+
+GO_PKG_BUILD_DEPENDS_PATH:=/usr/share/gocode
+GO_PKG_BUILD_DEPENDS_SRC=$(STAGING_DIR)$(GO_PKG_BUILD_DEPENDS_PATH)/src
+
+ifdef CONFIG_PKG_ASLR_PIE_ALL
+  ifeq ($(strip $(PKG_ASLR_PIE)),1)
+    ifeq ($(GO_TARGET_PIE_SUPPORTED),1)
+      GO_PKG_ENABLE_PIE:=1
+    else
+      $(warning PIE buildmode is not supported for $(GO_OS)/$(GO_ARCH))
+    endif
+  endif
+endif
+
+ifdef CONFIG_PKG_ASLR_PIE_REGULAR
+  ifeq ($(strip $(PKG_ASLR_PIE_REGULAR)),1)
+    ifeq ($(GO_TARGET_PIE_SUPPORTED),1)
+      GO_PKG_ENABLE_PIE:=1
+    else
+      $(warning PIE buildmode is not supported for $(GO_OS)/$(GO_ARCH))
+    endif
+  endif
+endif
+
+ifdef CONFIG_GOLANG_SPECTRE
+  ifeq ($(GO_TARGET_SPECTRE_SUPPORTED),1)
+    GO_PKG_ENABLE_SPECTRE:=1
+  else
+    $(warning Spectre mitigations are not supported for $(GO_ARCH))
+  endif
+endif
+
+# sstrip causes corrupted section header size
+ifneq ($(CONFIG_USE_SSTRIP),)
+  ifneq ($(CONFIG_DEBUG),)
+    GO_PKG_STRIP_ARGS:=--strip-unneeded --remove-section=.comment --remove-section=.note
+  else
+    GO_PKG_STRIP_ARGS:=--strip-all
+  endif
+  STRIP:=$(TARGET_CROSS)strip $(GO_PKG_STRIP_ARGS)
+endif
+
+define GoPackage/GoSubMenu
+  SUBMENU:=Go
+  SECTION:=lang
+  CATEGORY:=Languages
+endef
+
+GO_PKG_BUILD_CONFIG_VARS= \
+	GO_PKG="$(strip $(GO_PKG))" \
+	GO_INSTALL_EXTRA="$(strip $(GO_PKG_INSTALL_EXTRA))" \
+	GO_INSTALL_ALL="$(strip $(GO_PKG_INSTALL_ALL))" \
+	GO_SOURCE_ONLY="$(strip $(GO_PKG_SOURCE_ONLY))" \
+	GO_BUILD_PKG="$(strip $(GO_PKG_BUILD_PKG))" \
+	GO_EXCLUDES="$(strip $(GO_PKG_EXCLUDES))" \
+	GO_GO_GENERATE="$(strip $(GO_PKG_GO_GENERATE))" \
+	GO_INSTALL_BIN_PATH="$(strip $(GO_PKG_INSTALL_BIN_PATH))" \
+	BUILD_DIR="$(PKG_BUILD_DIR)" \
+	GO_BUILD_DIR="$(GO_PKG_BUILD_DIR)" \
+	GO_BUILD_BIN_DIR="$(GO_PKG_BUILD_BIN_DIR)" \
+	GO_BUILD_DEPENDS_PATH="$(GO_PKG_BUILD_DEPENDS_PATH)" \
+	GO_BUILD_DEPENDS_SRC="$(GO_PKG_BUILD_DEPENDS_SRC)"
+
+GO_PKG_TARGET_VARS= \
+	GOOS="$(GO_OS)" \
+	GOARCH="$(GO_ARCH)" \
+	GO386="$(GO_386)" \
+	GOARM="$(GO_ARM)" \
+	GOMIPS="$(GO_MIPS)" \
+	GOMIPS64="$(GO_MIPS64)" \
+	CGO_ENABLED=1 \
+	CC="$(TARGET_CC)" \
+	CXX="$(TARGET_CXX)" \
+	CGO_CFLAGS="$(filter-out $(GO_CFLAGS_TO_REMOVE),$(TARGET_CFLAGS))" \
+	CGO_CPPFLAGS="$(TARGET_CPPFLAGS)" \
+	CGO_CXXFLAGS="$(filter-out $(GO_CFLAGS_TO_REMOVE),$(TARGET_CXXFLAGS))" \
+	CGO_LDFLAGS="$(TARGET_LDFLAGS)"
+
+GO_PKG_BUILD_VARS= \
+	GOPATH="$(GO_PKG_BUILD_DIR)" \
+	GOCACHE="$(GO_BUILD_CACHE_DIR)" \
+	GOMODCACHE="$(GO_MOD_CACHE_DIR)" \
+	GOENV=off
+
+GO_PKG_VARS= \
+	$(GO_PKG_TARGET_VARS) \
+	$(GO_PKG_BUILD_VARS)
+
+GO_PKG_DEFAULT_GCFLAGS= \
+	$(if $(GO_PKG_ENABLE_SPECTRE),-spectre all)
+
+GO_PKG_DEFAULT_ASMFLAGS= \
+	$(if $(GO_PKG_ENABLE_SPECTRE),-spectre all)
+
+GO_PKG_DEFAULT_LDFLAGS= \
+	-buildid '$(SOURCE_DATE_EPOCH)' \
+	-linkmode external \
+	-extldflags '$(patsubst -z%,-Wl$(comma)-z$(comma)%,$(TARGET_LDFLAGS))'
+
+GO_PKG_CUSTOM_LDFLAGS= \
+	$(GO_PKG_LDFLAGS) \
+	$(patsubst %,-X %,$(GO_PKG_LDFLAGS_X))
+
+GO_PKG_INSTALL_ARGS= \
+	-v \
+	-trimpath \
+	-ldflags "all=$(GO_PKG_DEFAULT_LDFLAGS)" \
+	$(if $(GO_PKG_DEFAULT_GCFLAGS),-gcflags "all=$(GO_PKG_DEFAULT_GCFLAGS)") \
+	$(if $(GO_PKG_DEFAULT_ASMFLAGS),-asmflags "all=$(GO_PKG_DEFAULT_ASMFLAGS)") \
+	$(if $(filter $(GO_PKG_ENABLE_PIE),1),-buildmode pie) \
+	$(if $(filter $(GO_ARCH),arm),-installsuffix "v$(GO_ARM)") \
+	$(if $(filter $(GO_ARCH),mips mipsle),-installsuffix "$(GO_MIPS)") \
+	$(if $(filter $(GO_ARCH),mips64 mips64le),-installsuffix "$(GO_MIPS64)") \
+	$(if $(GO_PKG_GCFLAGS),-gcflags "$(GO_PKG_GCFLAGS) $(GO_PKG_DEFAULT_GCFLAGS)") \
+	$(if $(GO_PKG_CUSTOM_LDFLAGS),-ldflags "$(GO_PKG_CUSTOM_LDFLAGS) $(GO_PKG_DEFAULT_LDFLAGS)") \
+	$(if $(GO_PKG_TAGS),-tags "$(GO_PKG_TAGS)")
+
+define GoPackage/Build/Configure
+	$(GO_GENERAL_BUILD_CONFIG_VARS) \
+	$(GO_PKG_BUILD_CONFIG_VARS) \
+	$(SHELL) $(GO_INCLUDE_DIR)/golang-build.sh configure
+endef
+
+# $(1) additional arguments for go command line (optional)
+define GoPackage/Build/Compile
+	$(GO_GENERAL_BUILD_CONFIG_VARS) \
+	$(GO_PKG_BUILD_CONFIG_VARS) \
+	$(GO_PKG_VARS) \
+	$(SHELL) $(GO_INCLUDE_DIR)/golang-build.sh build $(GO_PKG_INSTALL_ARGS) $(1)
+endef
+
+define GoPackage/Build/InstallDev
+	$(call GoPackage/Package/Install/Src,$(1))
+endef
+
+define GoPackage/Package/Install/Bin
+	$(GO_GENERAL_BUILD_CONFIG_VARS) \
+	$(GO_PKG_BUILD_CONFIG_VARS) \
+	$(SHELL) $(GO_INCLUDE_DIR)/golang-build.sh install_bin "$(1)"
+endef
+
+define GoPackage/Package/Install/Src
+	$(GO_GENERAL_BUILD_CONFIG_VARS) \
+	$(GO_PKG_BUILD_CONFIG_VARS) \
+	$(SHELL) $(GO_INCLUDE_DIR)/golang-build.sh install_src "$(1)"
+endef
+
+define GoPackage/Package/Install
+	$(if $(filter $(GO_PKG_SOURCE_ONLY),1),, \
+		$(call GoPackage/Package/Install/Bin,$(1)) \
+	)
+	$(call GoPackage/Package/Install/Src,$(1))
+endef
+
+
+ifneq ($(strip $(GO_PKG)),)
+  ifeq ($(GO_TARGET_SPECTRE_SUPPORTED),1)
+    PKG_CONFIG_DEPENDS+=CONFIG_GOLANG_SPECTRE
+  endif
+
+  Build/Configure=$(call GoPackage/Build/Configure)
+  Build/Compile=$(call GoPackage/Build/Compile)
+  Hooks/Compile/Post+=Go/CacheCleanup
+  Build/InstallDev=$(call GoPackage/Build/InstallDev,$(1))
+endif
+
+define GoPackage
+  ifndef Package/$(1)/install
+    Package/$(1)/install=$$(call GoPackage/Package/Install,$$(1))
+  endif
+endef
+
+define GoBinPackage
+  ifndef Package/$(1)/install
+    Package/$(1)/install=$$(call GoPackage/Package/Install/Bin,$$(1))
+  endif
+endef
+
+define GoSrcPackage
+  ifndef Package/$(1)/install
+    Package/$(1)/install=$$(call GoPackage/Package/Install/Src,$$(1))
+  endif
+endef
+
+
+# Deprecated variables - these will be removed after the next OpenWrt release
+GO_PKG_PATH=$(GO_PKG_BUILD_DEPENDS_PATH)
+GO_PKG_WORK_DIR=$(PKG_BUILD_DIR)/$(GO_PKG_WORK_DIR_NAME)
+GO_PKG_CACHE_DIR=$(GO_BUILD_CACHE_DIR)
+GO_PKG_DEFAULT_VARS=$(GO_PKG_VARS)
+GoPackage/Environment=$(GO_PKG_VARS)
+GoPackage/is_dir_not_empty=$$$$($(FIND) "$(1)" -maxdepth 0 -type d \! -empty 2>/dev/null)
+GoPackage/has_binaries=$(call GoPackage/is_dir_not_empty,$(GO_PKG_BUILD_BIN_DIR))
+# End of deprecated variables
diff --git a/external/subpack/lang/golang/golang-values.mk b/external/subpack/lang/golang/golang-values.mk
new file mode 100644
index 0000000..34c9c1c
--- /dev/null
+++ b/external/subpack/lang/golang/golang-values.mk
@@ -0,0 +1,256 @@
+#
+# Copyright (C) 2018, 2020 Jeffery To
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+ifeq ($(origin GO_INCLUDE_DIR),undefined)
+  GO_INCLUDE_DIR:=$(dir $(lastword $(MAKEFILE_LIST)))
+endif
+
+
+# Unset environment variables
+# There are more magic variables to track down, but ain't nobody got time for that
+
+# From https://pkg.go.dev/cmd/go#hdr-Environment_variables
+
+# General-purpose environment variables:
+unexport \
+  GO111MODULE \
+  GCCGO \
+  GOARCH \
+  GOBIN \
+  GOCACHE \
+  GOMODCACHE \
+  GODEBUG \
+  GOENV \
+  GOFLAGS \
+  GOOS \
+  GOPATH \
+  GOROOT \
+  GOTMPDIR
+# Unmodified:
+#   GOINSECURE
+#   GOPRIVATE
+#   GOPROXY
+#   GONOPROXY
+#   GOSUMDB
+#   GONOSUMDB
+#   GOVCS
+
+# Environment variables for use with cgo:
+unexport \
+  AR \
+  CC \
+  CGO_ENABLED \
+  CGO_CFLAGS   CGO_CFLAGS_ALLOW   CGO_CFLAGS_DISALLOW \
+  CGO_CPPFLAGS CGO_CPPFLAGS_ALLOW CGO_CPPFLAGS_DISALLOW \
+  CGO_CXXFLAGS CGO_CXXFLAGS_ALLOW CGO_CXXFLAGS_DISALLOW \
+  CGO_FFLAGS   CGO_FFLAGS_ALLOW   CGO_FFLAGS_DISALLOW \
+  CGO_LDFLAGS  CGO_LDFLAGS_ALLOW  CGO_LDFLAGS_DISALLOW \
+  CXX \
+  FC
+# Unmodified:
+#   PKG_CONFIG
+
+# Architecture-specific environment variables:
+unexport \
+  GOARM \
+  GO386 \
+  GOMIPS \
+  GOMIPS64 \
+  GOWASM
+
+# Special-purpose environment variables:
+unexport \
+  GCCGOTOOLDIR \
+  GOEXPERIMENT \
+  GOROOT_FINAL \
+  GO_EXTLINK_ENABLED
+# Unmodified:
+#   GIT_ALLOW_PROTOCOL
+
+# From https://pkg.go.dev/runtime#hdr-Environment_Variables
+unexport \
+  GOGC \
+  GOMAXPROCS \
+  GORACE \
+  GOTRACEBACK
+
+# From https://pkg.go.dev/cmd/cgo#hdr-Using_cgo_with_the_go_command
+unexport \
+  CC_FOR_TARGET \
+  CXX_FOR_TARGET
+# Todo:
+#   CC_FOR_${GOOS}_${GOARCH}
+#   CXX_FOR_${GOOS}_${GOARCH}
+
+# From https://golang.org/doc/install/source#environment
+unexport \
+  GOHOSTOS \
+  GOHOSTARCH \
+  GOPPC64
+
+# From https://golang.org/src/make.bash
+unexport \
+  GO_GCFLAGS \
+  GO_LDFLAGS \
+  GO_LDSO \
+  GO_DISTFLAGS \
+  GOBUILDTIMELOGFILE \
+  GOROOT_BOOTSTRAP
+
+# From https://golang.org/doc/go1.9#parallel-compile
+unexport \
+  GO19CONCURRENTCOMPILATION
+
+# From https://golang.org/src/cmd/dist/build.go
+unexport \
+  BOOT_GO_GCFLAGS \
+  BOOT_GO_LDFLAGS
+
+# From https://golang.org/src/cmd/dist/buildtool.go
+unexport \
+  GOBOOTSTRAP_TOOLEXEC
+
+
+# GOOS / GOARCH
+
+go_arch=$(subst \
+  aarch64,arm64,$(subst \
+  i386,386,$(subst \
+  mipsel,mipsle,$(subst \
+  mips64el,mips64le,$(subst \
+  powerpc64,ppc64,$(subst \
+  x86_64,amd64,$(1)))))))
+
+GO_OS:=linux
+GO_ARCH:=$(call go_arch,$(ARCH))
+GO_OS_ARCH:=$(GO_OS)_$(GO_ARCH)
+
+GO_HOST_OS:=$(call tolower,$(HOST_OS))
+GO_HOST_ARCH:=$(call go_arch,$(subst \
+  armv6l,arm,$(subst \
+  armv7l,arm,$(subst \
+  i686,i386,$(HOST_ARCH)))))
+GO_HOST_OS_ARCH:=$(GO_HOST_OS)_$(GO_HOST_ARCH)
+
+ifeq ($(GO_OS_ARCH),$(GO_HOST_OS_ARCH))
+  GO_HOST_TARGET_SAME:=1
+else
+  GO_HOST_TARGET_DIFFERENT:=1
+endif
+
+ifeq ($(GO_ARCH),386)
+  ifeq ($(CONFIG_TARGET_x86_geode)$(CONFIG_TARGET_x86_legacy),y)
+    GO_386:=softfloat
+  else
+    GO_386:=sse2
+  endif
+
+  # -fno-plt: causes "unexpected GOT reloc for non-dynamic symbol" errors
+  GO_CFLAGS_TO_REMOVE:=-fno-plt
+
+else ifeq ($(GO_ARCH),arm)
+  GO_TARGET_FPU:=$(word 2,$(subst +,$(space),$(call qstrip,$(CONFIG_CPU_TYPE))))
+
+  # FPU names from https://gcc.gnu.org/onlinedocs/gcc-8.4.0/gcc/ARM-Options.html#index-mfpu-1
+  # see also https://github.com/gcc-mirror/gcc/blob/releases/gcc-8.4.0/gcc/config/arm/arm-cpus.in
+
+  ifeq ($(GO_TARGET_FPU),)
+    GO_ARM:=5
+  else ifneq ($(filter $(GO_TARGET_FPU),vfp vfpv2),)
+    GO_ARM:=6
+  else
+    GO_ARM:=7
+  endif
+
+else ifneq ($(filter $(GO_ARCH),mips mipsle),)
+  ifeq ($(CONFIG_HAS_FPU),y)
+    GO_MIPS:=hardfloat
+  else
+    GO_MIPS:=softfloat
+  endif
+
+  # -mips32r2: conflicts with -march=mips32 set by go
+  GO_CFLAGS_TO_REMOVE:=-mips32r2
+
+else ifneq ($(filter $(GO_ARCH),mips64 mips64le),)
+  ifeq ($(CONFIG_HAS_FPU),y)
+    GO_MIPS64:=hardfloat
+  else
+    GO_MIPS64:=softfloat
+  endif
+
+endif
+
+
+# Target Go
+
+GO_ARCH_DEPENDS:=@(aarch64||arm||i386||i686||mips||mips64||mips64el||mipsel||powerpc64||x86_64)
+
+
+# ASLR/PIE
+
+# From https://golang.org/src/cmd/internal/sys/supported.go
+GO_PIE_SUPPORTED_OS_ARCH:= \
+  android_386  android_amd64  android_arm  android_arm64 \
+  linux_386    linux_amd64    linux_arm    linux_arm64 \
+  \
+  windows_386  windows_amd64  windows_arm \
+  \
+  darwin_amd64 darwin_arm64 \
+  ios_amd64    ios_arm64 \
+  \
+  freebsd_amd64 \
+  \
+  aix_ppc64 \
+  \
+  linux_ppc64le linux_riscv64 linux_s390x
+
+# From https://golang.org/src/cmd/go/internal/work/init.go
+go_pie_install_suffix=$(if $(filter $(1),aix_ppc64 windows_386 windows_amd64 windows_arm),,shared)
+
+ifneq ($(filter $(GO_HOST_OS_ARCH),$(GO_PIE_SUPPORTED_OS_ARCH)),)
+  GO_HOST_PIE_SUPPORTED:=1
+  GO_HOST_PIE_INSTALL_SUFFIX:=$(call go_pie_install_suffix,$(GO_HOST_OS_ARCH))
+endif
+
+ifneq ($(filter $(GO_OS_ARCH),$(GO_PIE_SUPPORTED_OS_ARCH)),)
+  GO_TARGET_PIE_SUPPORTED:=1
+  GO_TARGET_PIE_INSTALL_SUFFIX:=$(call go_pie_install_suffix,$(GO_OS_ARCH))
+endif
+
+
+# Spectre mitigations
+
+GO_SPECTRE_SUPPORTED_ARCH:=amd64
+
+ifneq ($(filter $(GO_HOST_ARCH),$(GO_SPECTRE_SUPPORTED_ARCH)),)
+  GO_HOST_SPECTRE_SUPPORTED:=1
+endif
+
+ifneq ($(filter $(GO_ARCH),$(GO_SPECTRE_SUPPORTED_ARCH)),)
+  GO_TARGET_SPECTRE_SUPPORTED:=1
+endif
+
+
+# General build info
+
+GO_BUILD_CACHE_DIR:=$(or $(call qstrip,$(CONFIG_GOLANG_BUILD_CACHE_DIR)),$(TMP_DIR)/go-build)
+GO_MOD_CACHE_DIR:=$(DL_DIR)/go-mod-cache
+
+GO_MOD_ARGS= \
+	-modcacherw
+
+GO_GENERAL_BUILD_CONFIG_VARS= \
+	CONFIG_GOLANG_MOD_CACHE_WORLD_READABLE="$(CONFIG_GOLANG_MOD_CACHE_WORLD_READABLE)" \
+	GO_BUILD_CACHE_DIR="$(GO_BUILD_CACHE_DIR)" \
+	GO_MOD_CACHE_DIR="$(GO_MOD_CACHE_DIR)" \
+	GO_MOD_ARGS="$(GO_MOD_ARGS)"
+
+define Go/CacheCleanup
+	$(GO_GENERAL_BUILD_CONFIG_VARS) \
+	$(SHELL) $(GO_INCLUDE_DIR)/golang-build.sh cache_cleanup
+endef
diff --git a/external/subpack/lang/golang/golang/Config.in b/external/subpack/lang/golang/golang/Config.in
new file mode 100644
index 0000000..76fd85c
--- /dev/null
+++ b/external/subpack/lang/golang/golang/Config.in
@@ -0,0 +1,33 @@
+menu "Configuration"
+
+config GOLANG_EXTERNAL_BOOTSTRAP_ROOT
+	string "External bootstrap Go root directory"
+	default ""
+	help
+	  Path to a working Go tree (>= Go 1.4), with bin, pkg, and src
+	  subdirectories and the Go compiler at bin/go.
+
+	  If specified, the existing Go installation will be used to
+	  compile host (buildroot) Go.
+
+	  Leave blank to compile the default bootstrap Go.
+
+config GOLANG_BUILD_CACHE_DIR
+	string "Go build cache directory"
+	default ""
+	help
+	  Store the Go build cache in this directory.
+	  If not set, uses '$(TMP_DIR)/go-build'.
+
+config GOLANG_MOD_CACHE_WORLD_READABLE
+	bool "Ensure Go module cache is world-readable"
+	default n
+
+config GOLANG_SPECTRE
+	bool "Enable Spectre mitigations"
+	default n
+	depends on x86_64
+	help
+	  Currently only available for x86-64 (amd64).
+
+endmenu
diff --git a/external/subpack/lang/golang/golang/Makefile b/external/subpack/lang/golang/golang/Makefile
new file mode 100644
index 0000000..4b8f962
--- /dev/null
+++ b/external/subpack/lang/golang/golang/Makefile
@@ -0,0 +1,368 @@
+#
+# Copyright (C) 2018, 2020 Jeffery To
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+GO_VERSION_MAJOR_MINOR:=1.17
+GO_VERSION_PATCH:=12
+
+PKG_NAME:=golang
+PKG_VERSION:=$(GO_VERSION_MAJOR_MINOR)$(if $(GO_VERSION_PATCH),.$(GO_VERSION_PATCH))
+PKG_RELEASE:=1
+
+GO_SOURCE_URLS:=https://dl.google.com/go/ \
+                https://mirrors.ustc.edu.cn/golang/ \
+                https://mirrors.nju.edu.cn/golang/
+
+PKG_SOURCE:=go$(PKG_VERSION).src.tar.gz
+PKG_SOURCE_URL:=$(GO_SOURCE_URLS)
+PKG_HASH:=0d51b5b3f280c0f01f534598c0219db5878f337da6137a9ee698777413607209
+
+PKG_MAINTAINER:=Jeffery To <jeffery.to@gmail.com>
+PKG_LICENSE:=BSD-3-Clause
+PKG_LICENSE_FILES:=LICENSE
+PKG_CPE_ID:=cpe:/a:golang:go
+
+PKG_BUILD_DEPENDS:=golang/host
+PKG_BUILD_DIR:=$(BUILD_DIR)/go-$(PKG_VERSION)
+PKG_BUILD_PARALLEL:=1
+PKG_USE_MIPS16:=0
+
+PKG_GO_PREFIX:=/usr
+PKG_GO_VERSION_ID:=$(GO_VERSION_MAJOR_MINOR)
+PKG_GO_ROOT:=$(PKG_GO_PREFIX)/lib/go-$(PKG_GO_VERSION_ID)
+
+HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/go-$(PKG_VERSION)
+HOST_BUILD_PARALLEL:=1
+
+HOST_GO_PREFIX:=$(STAGING_DIR_HOSTPKG)
+HOST_GO_VERSION_ID:=cross
+HOST_GO_ROOT:=$(HOST_GO_PREFIX)/lib/go-$(HOST_GO_VERSION_ID)
+
+HOST_GO_VALID_OS_ARCH:= \
+  android_386  android_amd64  android_arm  android_arm64 \
+  freebsd_386  freebsd_amd64  freebsd_arm  freebsd_arm64 \
+  linux_386    linux_amd64    linux_arm    linux_arm64 \
+  openbsd_386  openbsd_amd64  openbsd_arm  openbsd_arm64 \
+  netbsd_386   netbsd_amd64   netbsd_arm   netbsd_arm64 \
+  windows_386  windows_amd64  windows_arm  windows_arm64 \
+  \
+  plan9_386    plan9_amd64    plan9_arm \
+  \
+  darwin_amd64 darwin_arm64 \
+  ios_amd64    ios_arm64 \
+  \
+  dragonfly_amd64 \
+  illumos_amd64 \
+  solaris_amd64 \
+  \
+  aix_ppc64 \
+  js_wasm \
+  \
+  linux_ppc64 linux_ppc64le \
+  linux_mips linux_mipsle linux_mips64 linux_mips64le \
+  linux_riscv64 linux_s390x \
+  \
+  openbsd_mips64
+
+BOOTSTRAP_SOURCE:=go1.4-bootstrap-20171003.tar.gz
+BOOTSTRAP_SOURCE_URL:=$(GO_SOURCE_URLS)
+BOOTSTRAP_HASH:=f4ff5b5eb3a3cae1c993723f3eab519c5bae18866b5e5f96fe1102f0cb5c3e52
+
+BOOTSTRAP_BUILD_DIR:=$(HOST_BUILD_DIR)/.go_bootstrap
+
+BOOTSTRAP_GO_VALID_OS_ARCH:= \
+  darwin_386     darwin_amd64 \
+  dragonfly_386  dragonfly_amd64 \
+  freebsd_386    freebsd_amd64    freebsd_arm \
+  linux_386      linux_amd64      linux_arm \
+  netbsd_386     netbsd_amd64     netbsd_arm \
+  openbsd_386    openbsd_amd64 \
+  plan9_386      plan9_amd64 \
+                 solaris_amd64 \
+  windows_386    windows_amd64
+
+include $(INCLUDE_DIR)/host-build.mk
+include $(INCLUDE_DIR)/package.mk
+include ../golang-compiler.mk
+include ../golang-package.mk
+
+PKG_UNPACK:=$(HOST_TAR) -C "$(PKG_BUILD_DIR)" --strip-components=1 -xzf "$(DL_DIR)/$(PKG_SOURCE)"
+HOST_UNPACK:=$(HOST_TAR) -C "$(HOST_BUILD_DIR)" --strip-components=1 -xzf "$(DL_DIR)/$(PKG_SOURCE)"
+BOOTSTRAP_UNPACK:=$(HOST_TAR) -C "$(BOOTSTRAP_BUILD_DIR)" --strip-components=1 -xzf "$(DL_DIR)/$(BOOTSTRAP_SOURCE)"
+
+# don't strip ELF executables in test data
+RSTRIP:=:
+STRIP:=:
+
+ifeq ($(GO_TARGET_SPECTRE_SUPPORTED),1)
+  PKG_CONFIG_DEPENDS+=CONFIG_GOLANG_SPECTRE
+endif
+
+define Package/golang/Default
+$(call GoPackage/GoSubMenu)
+  TITLE:=Go programming language
+  URL:=https://go.dev/
+  DEPENDS:=$(GO_ARCH_DEPENDS)
+endef
+
+define Package/golang/Default/description
+The Go programming language is an open source project to make
+programmers more productive.
+
+Go is expressive, concise, clean, and efficient. Its concurrency
+mechanisms make it easy to write programs that get the most out of
+multicore and networked machines, while its novel type system enables
+flexible and modular program construction. Go compiles quickly to
+machine code yet has the convenience of garbage collection and the power
+of run-time reflection. It's a fast, statically typed, compiled language
+that feels like a dynamically typed, interpreted language.
+endef
+
+# go tool requires source present:
+# https://github.com/golang/go/issues/4635
+define Package/golang
+$(call Package/golang/Default)
+  TITLE+= (compiler)
+  DEPENDS+= +golang-src
+endef
+
+define Package/golang/description
+$(call Package/golang/Default/description)
+
+This package provides an assembler, compiler, linker, and compiled
+libraries for the Go programming language.
+endef
+
+define Package/golang/config
+  source "$(SOURCE)/Config.in"
+endef
+
+define Package/golang-doc
+$(call Package/golang/Default)
+  TITLE+= (documentation)
+endef
+
+define Package/golang-doc/description
+$(call Package/golang/Default/description)
+
+This package provides the documentation for the Go programming language.
+endef
+
+define Package/golang-src
+$(call Package/golang/Default)
+  TITLE+= (source files)
+endef
+
+define Package/golang-src/description
+$(call Package/golang/Default/description)
+
+This package provides the Go programming language source files needed
+for cross-compilation.
+endef
+
+
+# Bootstrap
+
+BOOTSTRAP_ROOT_DIR:=$(call qstrip,$(CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT))
+
+ifeq ($(BOOTSTRAP_ROOT_DIR),)
+  BOOTSTRAP_ROOT_DIR:=$(BOOTSTRAP_BUILD_DIR)
+
+  define Download/golang-bootstrap
+    FILE:=$(BOOTSTRAP_SOURCE)
+    URL:=$(BOOTSTRAP_SOURCE_URL)
+    HASH:=$(BOOTSTRAP_HASH)
+  endef
+  $(eval $(call Download,golang-bootstrap))
+
+  define Bootstrap/Prepare
+	mkdir -p "$(BOOTSTRAP_BUILD_DIR)"
+	$(BOOTSTRAP_UNPACK)
+  endef
+  Hooks/HostPrepare/Post+=Bootstrap/Prepare
+
+  $(eval $(call GoCompiler/AddProfile,Bootstrap,$(BOOTSTRAP_BUILD_DIR),,bootstrap,$(GO_HOST_OS_ARCH)))
+endif
+
+
+# Host
+
+ifeq ($(GO_HOST_PIE_SUPPORTED),1)
+  HOST_GO_ENABLE_PIE:=1
+endif
+
+# when using GO_LDFLAGS to set buildmode=pie, the PIE install suffix
+# does not apply (we also delete the std lib during Host/Install)
+
+$(eval $(call GoCompiler/AddProfile,Host,$(HOST_BUILD_DIR),$(HOST_GO_PREFIX),$(HOST_GO_VERSION_ID),$(GO_HOST_OS_ARCH),$(HOST_GO_INSTALL_SUFFIX)))
+
+HOST_GO_VARS= \
+	GOCACHE="$(GO_BUILD_CACHE_DIR)" \
+	GOENV=off \
+	CC="$(HOSTCC_NOCACHE)" \
+	CXX="$(HOSTCXX_NOCACHE)"
+
+define Host/Compile
+	$(call GoCompiler/Bootstrap/CheckHost,$(BOOTSTRAP_GO_VALID_OS_ARCH))
+	$(call GoCompiler/Host/CheckHost,$(HOST_GO_VALID_OS_ARCH))
+
+	mkdir -p "$(GO_BUILD_CACHE_DIR)"
+
+	$(call GoCompiler/Bootstrap/Make, \
+		$(HOST_GO_VARS) \
+	)
+
+	$(call GoCompiler/Host/Make, \
+		GOROOT_BOOTSTRAP="$(BOOTSTRAP_ROOT_DIR)" \
+		$(if $(HOST_GO_ENABLE_PIE),GO_LDFLAGS="-buildmode pie") \
+		$(HOST_GO_VARS) \
+	)
+endef
+
+# if host and target os/arch are the same,
+# when go compiles a program, it will use the host std lib
+# so remove it now and force go to rebuild std for target later
+define Host/Install
+	$(call Host/Uninstall)
+
+	$(call GoCompiler/Host/Install/Bin,)
+	$(call GoCompiler/Host/Install/Src,)
+
+	$(call GoCompiler/Host/Install/BinLinks,)
+
+	rm -rf "$(HOST_GO_ROOT)/pkg/$(GO_HOST_OS_ARCH)$(if $(HOST_GO_INSTALL_SUFFIX),_$(HOST_GO_INSTALL_SUFFIX))"
+
+	$(INSTALL_DIR) "$(HOST_GO_ROOT)/openwrt"
+	$(INSTALL_BIN) ./files/go-gcc-helper "$(HOST_GO_ROOT)/openwrt/"
+	$(LN) go-gcc-helper "$(HOST_GO_ROOT)/openwrt/gcc"
+	$(LN) go-gcc-helper "$(HOST_GO_ROOT)/openwrt/g++"
+endef
+
+define Host/Uninstall
+	rm -rf "$(HOST_GO_ROOT)/openwrt"
+
+	$(call GoCompiler/Host/Uninstall/BinLinks,)
+
+	$(call GoCompiler/Host/Uninstall,)
+endef
+
+
+# Target
+
+ifeq ($(GO_PKG_ENABLE_PIE),1)
+  PKG_GO_INSTALL_SUFFIX:=$(GO_TARGET_PIE_INSTALL_SUFFIX)
+endif
+
+$(eval $(call GoCompiler/AddProfile,Package,$(PKG_BUILD_DIR),$(PKG_GO_PREFIX),$(PKG_GO_VERSION_ID),$(GO_OS_ARCH),$(PKG_GO_INSTALL_SUFFIX)))
+
+PKG_GO_ZBOOTSTRAP_MODS:= \
+	s/defaultGO386 = `[^`]*`/defaultGO386 = `$(or $(GO_386),sse2)`/; \
+	s/defaultGOARM = `[^`]*`/defaultGOARM = `$(or $(GO_ARM),5)`/; \
+	s/defaultGOMIPS = `[^`]*`/defaultGOMIPS = `$(or $(GO_MIPS),hardfloat)`/; \
+	s/defaultGOMIPS64 = `[^`]*`/defaultGOMIPS64 = `$(or $(GO_MIPS64),hardfloat)`/; \
+	s/defaultGOPPC64 = `[^`]*`/defaultGOPPC64 = `power8`/;
+
+PKG_GO_ZBOOTSTRAP_PATH:=$(PKG_BUILD_DIR)/src/internal/buildcfg/zbootstrap.go
+
+PKG_GO_VARS= \
+	GOCACHE="$(GO_BUILD_CACHE_DIR)" \
+	GOENV=off \
+	GO_GCC_HELPER_PATH="$$$$PATH" \
+	CC=gcc \
+	CXX=g++ \
+	PKG_CONFIG=pkg-config \
+	PATH="$(HOST_GO_ROOT)/openwrt:$$$$PATH"
+
+PKG_GO_GCFLAGS= \
+	$(if $(GO_PKG_ENABLE_SPECTRE),-spectre all)
+
+PKG_GO_ASMFLAGS= \
+	$(if $(GO_PKG_ENABLE_SPECTRE),-spectre all)
+
+PKG_GO_LDFLAGS= \
+	-buildid '$(SOURCE_DATE_EPOCH)' \
+	-linkmode external \
+	-extldflags '$(patsubst -z%,-Wl$(comma)-z$(comma)%,$(TARGET_LDFLAGS))' \
+	$(if $(CONFIG_NO_STRIP)$(CONFIG_DEBUG),,-s -w)
+
+# setting -trimpath is not necessary here because the paths inside the
+# compiler binary are relative to GOROOT_FINAL (PKG_GO_ROOT), which is
+# static / not dependent on the build environment
+PKG_GO_INSTALL_ARGS= \
+	-ldflags "all=$(PKG_GO_LDFLAGS)" \
+	$(if $(PKG_GO_GCFLAGS),-gcflags "all=$(PKG_GO_GCFLAGS)") \
+	$(if $(PKG_GO_ASMFLAGS),-asmflags "all=$(PKG_GO_ASMFLAGS)") \
+	$(if $(filter $(GO_PKG_ENABLE_PIE),1),-buildmode pie)
+
+define Build/Compile
+	mkdir -p "$(GO_BUILD_CACHE_DIR)"
+
+	@echo "Building target Go first stage"
+
+	$(call GoCompiler/Package/Make, \
+		GOROOT_BOOTSTRAP="$(HOST_GO_ROOT)" \
+		GO_GCC_HELPER_CC="$(HOSTCC)" \
+		GO_GCC_HELPER_CXX="$(HOSTCXX)" \
+		$(PKG_GO_VARS) \
+	)
+
+	$(SED) '$(PKG_GO_ZBOOTSTRAP_MODS)' "$(PKG_GO_ZBOOTSTRAP_PATH)"
+
+	( \
+		if echo 'int main() { return 0; }' | $(TARGET_CC) -o $(PKG_BUILD_DIR)/test-ldso -x c - > /dev/null 2>&1; then \
+			LDSO=$$$$( \
+				readelf -l $(PKG_BUILD_DIR)/test-ldso | \
+				sed -n -e 's/^.*interpreter: \(.*\)[]]/\1/p' \
+			) ; \
+		fi ; \
+		$(SED) "s,defaultGO_LDSO = \`[^\`]*\`,defaultGO_LDSO = \`$$$$LDSO\`," "$(PKG_GO_ZBOOTSTRAP_PATH)" ; \
+	)
+
+	@echo "Building target Go second stage"
+
+	( \
+		cd "$(PKG_BUILD_DIR)/bin" ; \
+		export $(GO_PKG_TARGET_VARS) ; \
+		$(CP) go go-host ; \
+		GOROOT_FINAL="$(PKG_GO_ROOT)" \
+		GO_GCC_HELPER_CC="$(TARGET_CC)" \
+		GO_GCC_HELPER_CXX="$(TARGET_CXX)" \
+		$(PKG_GO_VARS) \
+		./go-host install -a $(PKG_GO_INSTALL_ARGS) std cmd ; \
+		retval="$$$$?" ; \
+		rm -f go-host ; \
+		exit "$$$$retval" ; \
+	)
+endef
+
+define Package/golang/install
+	$(call GoCompiler/Package/Install/Bin,$(1)$(PKG_GO_PREFIX))
+	$(call GoCompiler/Package/Install/BinLinks,$(1)$(PKG_GO_PREFIX))
+endef
+
+define Package/golang-doc/install
+	$(call GoCompiler/Package/Install/Doc,$(1)$(PKG_GO_PREFIX))
+endef
+
+define Package/golang-src/install
+	$(call GoCompiler/Package/Install/Src,$(1)$(PKG_GO_PREFIX))
+endef
+
+# src/debug contains ELF executables as test data
+# and they reference these libraries
+# we need to call this in Package/$(1)/extra_provides
+# to pass CheckDependencies in include/package-ipkg.mk
+define Package/golang-src/extra_provides
+	echo 'libc.so.6'
+endef
+
+
+$(eval $(call HostBuild))
+$(eval $(call BuildPackage,golang))
+$(eval $(call BuildPackage,golang-doc))
+$(eval $(call BuildPackage,golang-src))
diff --git a/external/subpack/lang/golang/golang/files/go-gcc-helper b/external/subpack/lang/golang/golang/files/go-gcc-helper
new file mode 100644
index 0000000..b396e30
--- /dev/null
+++ b/external/subpack/lang/golang/golang/files/go-gcc-helper
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+me=go-gcc-helper
+name="${0##*/}"
+
+log() {
+	# shellcheck disable=SC2039
+	local IFS=" "
+	printf '%s\n' "$me: $*"
+}
+
+case "$name" in
+gcc)
+	if [ -z "$GO_GCC_HELPER_CC" ]; then
+		log "missing GO_GCC_HELPER_CC"
+		exit 1
+	fi
+	cmd="$GO_GCC_HELPER_CC"
+	;;
+g++)
+	if [ -z "$GO_GCC_HELPER_CXX" ]; then
+		log "missing GO_GCC_HELPER_CXX"
+		exit 1
+	fi
+	cmd="$GO_GCC_HELPER_CXX"
+	;;
+*)
+	log "unknown command \"$name\""
+	exit 1
+	;;
+esac
+
+if [ -n "$GO_GCC_HELPER_PATH" ]; then
+	export PATH="$GO_GCC_HELPER_PATH"
+else
+	log "missing GO_GCC_HELPER_PATH"
+fi
+
+log "running $cmd $*"
+
+$cmd "$@"
diff --git a/external/subpack/lang/golang/golang/patches/001-cmd-link-use-gold-on-ARM-ARM64-only-if-gold-is-available.patch b/external/subpack/lang/golang/golang/patches/001-cmd-link-use-gold-on-ARM-ARM64-only-if-gold-is-available.patch
new file mode 100644
index 0000000..4d93ad2
--- /dev/null
+++ b/external/subpack/lang/golang/golang/patches/001-cmd-link-use-gold-on-ARM-ARM64-only-if-gold-is-available.patch
@@ -0,0 +1,35 @@
+This is https://github.com/golang/go/pull/49748 backported for Go 1.17.
+
+--- a/src/cmd/link/internal/ld/lib.go
++++ b/src/cmd/link/internal/ld/lib.go
+@@ -1391,23 +1391,18 @@ func (ctxt *Link) hostlink() {
+ 		}
+ 
+ 		if ctxt.Arch.InFamily(sys.ARM, sys.ARM64) && buildcfg.GOOS == "linux" {
+-			// On ARM, the GNU linker will generate COPY relocations
+-			// even with -znocopyreloc set.
++			// On ARM, older versions of the GNU linker will generate
++			// COPY relocations even with -znocopyreloc set.
+ 			// https://sourceware.org/bugzilla/show_bug.cgi?id=19962
+ 			//
+-			// On ARM64, the GNU linker will fail instead of
+-			// generating COPY relocations.
++			// On ARM64, older versions of the GNU linker will fail
++			// instead of generating COPY relocations.
+ 			//
+-			// In both cases, switch to gold.
+-			altLinker = "gold"
+-
+-			// If gold is not installed, gcc will silently switch
+-			// back to ld.bfd. So we parse the version information
+-			// and provide a useful error if gold is missing.
++			// In both cases, switch to gold if gold is available.
+ 			cmd := exec.Command(*flagExtld, "-fuse-ld=gold", "-Wl,--version")
+ 			if out, err := cmd.CombinedOutput(); err == nil {
+-				if !bytes.Contains(out, []byte("GNU gold")) {
+-					log.Fatalf("ARM external linker must be gold (issue #15696), but is not: %s", out)
++				if bytes.Contains(out, []byte("GNU gold")) {
++					altLinker = "gold"
+ 				}
+ 			}
+ 		}