Skip to content

Commit

Permalink
[BACKPORT 2.16][#17502] Fix the shared library interpreter used for y…
Browse files Browse the repository at this point in the history
…ugabyted-ui

Summary:
Original commit: 75a83fe / D25752
Recently, around the time we upgraded Go on our build hosts from 1.18 to 1.20, the yugabyted-ui executable stopped working in x86_64 release builds. The yugabyted-ui executable ended up having the wrong dynamic linker (ld.so from Linuxbrew). This is most likely due to changes in the mechanism of linker selection by the Go compiler driver. https://tip.golang.org/doc/go1.20 says "On Linux, the linker now selects the dynamic interpreter for glibc or musl at link time." Apparently, before the change Go would use the system linker (/bin/ld or /usr/bin/ld) and now it uses the ld binary available on the PATH, which happens to be the Linuxbrew version of ld in the Linuxbrew build. The Linuxbrew ld binary makes its output executables use the Linuxbrew dynamic linker.

To counteract this, we are removing Linuxbrew bin directory from PATH when building yugabyted-ui. Also adding a check in yugabyted-ui/build.sh script that a valid system-wide dynamic linker is used, and if that is not the case for whatever reason, attempting to fix it using the patchelf tool.

Test Plan: Jenkins: compile only

Reviewers: mbautin

Reviewed By: mbautin

Subscribers: ybase

Differential Revision: https://phorge.dev.yugabyte.com/D25768
  • Loading branch information
jharveysmith committed May 26, 2023
1 parent 11279fe commit 8303f3a
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 21 deletions.
8 changes: 8 additions & 0 deletions build-support/common-build-env.sh
Expand Up @@ -1528,6 +1528,13 @@ add_brew_bin_to_path() {
fi
}

remove_linuxbrew_bin_from_path() {
if using_linuxbrew; then
ensure_linuxbrew_dir_is_set
remove_path_entry "$YB_LINUXBREW_DIR/bin"
fi
}

detect_num_cpus() {
if [[ ! ${YB_NUM_CPUS:-} =~ ^[0-9]+$ ]]; then
if is_linux; then
Expand Down Expand Up @@ -2196,6 +2203,7 @@ run_shellcheck() {
build-support/jenkins/build-and-test.sh
build-support/jenkins/yb-jenkins-build.sh
build-support/run-test.sh
yugabyted-ui/build.sh
yb_build.sh
)
pushd "$YB_SRC_ROOT"
Expand Down
68 changes: 47 additions & 21 deletions yugabyted-ui/build.sh
Expand Up @@ -2,44 +2,70 @@
set -ue -o pipefail

# Source common-build-env to get "log" function.
# shellcheck source=build-support/common-build-env.sh
. "${BASH_SOURCE[0]%/*}/../build-support/common-build-env.sh"

readonly BASEDIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
(
readonly BASEDIR=$YB_SRC_ROOT/yugabyted-ui

cd "${BASEDIR}"
readonly APISERVERDIR=${BASEDIR}/apiserver/cmd/server
readonly UIDIR=${BASEDIR}/ui
readonly OUTDIR="${BUILD_ROOT:-/tmp/yugabyted-ui}/gobin"
readonly OUTFILE="${OUTDIR}/yugabyted-ui"
mkdir -p "${OUTDIR}"
readonly API_SERVER_DIR=${BASEDIR}/apiserver/cmd/server
readonly UI_DIR=${BASEDIR}/ui
readonly OUT_DIR="${BUILD_ROOT:-/tmp/yugabyted-ui}/gobin"
readonly OUT_FILE="${OUT_DIR}/yugabyted-ui"
mkdir -p "${OUT_DIR}"

if ! command -v npm -version &> /dev/null
then
log "npm could not be found"
exit 1
fatal "npm could not be found"
fi

if ! command -v go version &> /dev/null
then
log "go lang could not be found"
exit 1
fatal "go language (the go executable) could not be found"
fi

(
cd $UIDIR
cd "$UI_DIR"
npm ci
npm run build
tar cz ui | tar -C "${APISERVERDIR}" -xz
tar cz ui | tar -C "${API_SERVER_DIR}" -xz
)

cd $APISERVERDIR
go build -o "${OUTFILE}"
cd "$API_SERVER_DIR"
rm -f "${OUT_FILE}"

if [[ -f "${OUTFILE}" ]]
then
log "Yugabyted UI Binary generated successfully at ${OUTFILE}"
else
log "Build Failed."
exit 1
# Make double sure that the Linuxbrew bin directory is not in the path and Go cannot use the ld
# linker executable from that directory.
remove_linuxbrew_bin_from_path
export PATH=/usr/bin:$PATH

go build -o "${OUT_FILE}"

if [[ ! -f "${OUT_FILE}" ]]; then
fatal "Build Failed: file ${OUT_FILE} not found."
fi

log "Yugabyted UI Binary generated successfully at ${OUT_FILE}"

if is_mac; then
# The shared library interpreter validation below is only relevant for Linux.
exit
fi

echo "Running ldd on ${OUT_FILE}"
ldd "${OUT_FILE}"

ld_interpreter=$( patchelf --print-interpreter "${OUT_FILE}" )
if [[ ${ld_interpreter} == /lib*/ld-linux-* ]]; then
log "${OUT_FILE} is correctly configured with the shared library interpreter: ${ld_interpreter}"
exit
fi

log "WARNING: ${OUT_FILE} is not correctly configured with the shared library interpreter:" \
"${ld_interpreter}. Patching it now."

default_interpreter=$( patchelf --print-interpreter /bin/bash )
(
set -x
patchelf --set-interpreter "${default_interpreter}" "${OUT_FILE}"
)

0 comments on commit 8303f3a

Please sign in to comment.