之前搞 opentelemetry-cpp 的时候接触了下 bazel 构建系统。这玩意儿用起来有一点坑,特别是使用自定义编译环境的时候。
在使用我自己编译的很新版本的 GCC 和 clang+libc++ 的时候,涉及对libssp的检测和 LD_LIBRARY_PATH
环境变量在 bazel 中各个步骤中的传递,这里记录一下适配脚本。
BAZEL_OPTIONS="--copt=-DENABLE_METRICS_PREVIEW --copt=-DENABLE_LOGS_PREVIEW"
BAZEL_TEST_OPTIONS="$BAZEL_OPTIONS --test_output=errors"
BAZEL_STARTUP_OPTIONS="--output_user_root=$HOME/.cache/bazel/$BK_CI_BUILD_ID"
# https://github.com/bazelbuild/bazel/issues/4341
BAZEL_MACOS_OPTIONS="--features=-supports_dynamic_linker --linkopt -lpthread --linkopt -liconv --linkopt -lresolv --linkopt -ldl --linkopt -lm"
BAZEL_MACOS_OPTIONS="--host_linkopt -lpthread --host_linkopt -liconv --host_linkopt -lresolv --host_linkopt -ldl --host_linkopt -lm"
BAZEL_LINUX_GCC_OPTIONS=""
# Our gcc/llvm
for EXTRA_LD_LIBRARY_PATH in $(echo "$LD_LIBRARY_PATH" | tr ':' ' '); do
BAZEL_LINUX_GCC_OPTIONS="$BAZEL_LINUX_GCC_OPTIONS --host_linkopt=-Wl,-rpath,$EXTRA_LD_LIBRARY_PATH --host_linkopt=-L$EXTRA_LD_LIBRARY_PATH --linkopt=-L$EXTRA_LD_LIBRARY_PATH"
done
if [[ -z "$USE_CC" ]]; then
which clang >/dev/null 2>&1
if [[ $? -eq 0 ]]; then
USE_CC=clang
else
USE_CC=gcc
fi
fi
USE_CC_BASENAME="$(basename "$USE_CC")"
if [[ "x${USE_CC_BASENAME:0:3}" == "xgcc" ]]; then
USE_CC_FULLPATH="$(which "$USE_CC")"
for TEST_GCC_FLAGS in "-Wno-unused-function" "-Wno-error=stringop-overflow" "-Wno-error=array-parameter"; do
TEST_GCC_FLAGS_SUCCESS=1
echo "" | "$USE_CC" -E "$TEST_GCC_FLAGS" - >/dev/null 2>&1 || TEST_GCC_FLAGS_SUCCESS=0
if [[ $TEST_GCC_FLAGS_SUCCESS -ne 0 ]]; then
BAZEL_LINUX_GCC_OPTIONS="$BAZEL_LINUX_GCC_OPTIONS --copt $TEST_GCC_FLAGS"
fi
done
# Test libssp/-fstack-protector-strong/-fstack-protector-all
HAVE_LIBSSP=1
echo "#include <iostream>
int main () { return 0; }
" | "${USE_CC/%gcc/g++}" -x c++ -lssp -o run-test-gcc-with-ssp.exe - || HAVE_LIBSSP=0
if [[ $HAVE_LIBSSP -eq 1 ]]; then
BAZEL_LINUX_GCC_OPTIONS="$BAZEL_LINUX_GCC_OPTIONS --linkopt -lssp --host_linkopt -lssp"
rm -f run-test-gcc-with-ssp.exe
fi
HAVE_FSTACK_PROTECTOR_STRONG=1
echo "" | "$USE_CC" -E "-fstack-protector-strong" - >/dev/null 2>&1 || HAVE_FSTACK_PROTECTOR_STRONG=0
if [[ $HAVE_FSTACK_PROTECTOR_STRONG -eq 1 ]]; then
BAZEL_LINUX_GCC_OPTIONS="$BAZEL_LINUX_GCC_OPTIONS --copt -fstack-protector-strong --host_copt -fstack-protector-strong --linkopt -fstack-protector-strong --host_linkopt -fstack-protector-strong"
else
BAZEL_LINUX_GCC_OPTIONS="$BAZEL_LINUX_GCC_OPTIONS --copt -fstack-protector-all --host_copt -fstack-protector-all --linkopt -fstack-protector-all --host_linkopt -fstack-protector-all"
fi
BAZEL_OPTIONS="$BAZEL_OPTIONS $BAZEL_LINUX_GCC_OPTIONS"
BAZEL_TEST_OPTIONS="$BAZEL_TEST_OPTIONS $BAZEL_LINUX_GCC_OPTIONS"
elif [[ "x${USE_CC_BASENAME:0:5}" == "xclang" ]]; then
USE_CC_FULLPATH="$(which "$USE_CC")"
if [[ "x$GCC_HOME_DIR" == "x" ]] || [[ ! -e "$GCC_HOME_DIR" ]]; then
GCC_HOME_DIR="/opt/gcc-latest";
fi
if [[ ! -e "$GCC_HOME_DIR" ]]; then
GCC_HOME_DIR="/usr/local/gcc-latest";
fi
if [[ -e "$GCC_HOME_DIR" ]] && [[ "${USE_CC_FULLPATH:0:10}" == "/opt/llvm-" ]]; then
if [[ "x$CXXFLAGS" == "x" ]]; then
export CXXFLAGS="--gcc-toolchain=$GCC_HOME_DIR"
else
export CXXFLAGS="$CXXFLAGS --gcc-toolchain=$GCC_HOME_DIR"
fi
if [[ "x$CFLAGS" == "x" ]]; then
export CFLAGS="--gcc-toolchain=$GCC_HOME_DIR"
else
export CFLAGS="$CFLAGS --gcc-toolchain=$GCC_HOME_DIR"
fi
# BAZEL_LINUX_GCC_OPTIONS="$BAZEL_LINUX_GCC_OPTIONS --cxxopt -stdlib=libc++"
fi
for TEST_GCC_FLAGS in "-Wno-unused-function" "-Wno-error=unused-command-line-argument"; do
TEST_GCC_FLAGS_SUCCESS=1
echo "" | "$USE_CC" -E "$TEST_GCC_FLAGS" - >/dev/null 2>&1 || TEST_GCC_FLAGS_SUCCESS=0
if [[ $TEST_GCC_FLAGS_SUCCESS -ne 0 ]]; then
BAZEL_LINUX_GCC_OPTIONS="$BAZEL_LINUX_GCC_OPTIONS --copt $TEST_GCC_FLAGS"
fi
done
BAZEL_OPTIONS="$BAZEL_OPTIONS $BAZEL_LINUX_GCC_OPTIONS"
BAZEL_TEST_OPTIONS="$BAZEL_TEST_OPTIONS $BAZEL_LINUX_GCC_OPTIONS"
fi
然后,就可以直接使用以下脚本启动 bazel :
# ============ build & test ============
if [[ "x$USE_CC" != "x" ]]; then
export CC="$USE_CC"
fi
bazel fetch //...
bazel $BAZEL_STARTUP_OPTIONS build $BAZEL_OPTIONS //...
bazel $BAZEL_STARTUP_OPTIONS test $BAZEL_TEST_OPTIONS //...
# ============ asan ============
# See https://github.com/google/sanitizers/issues/764 when run under docker
if [[ "x$USE_CC" != "x" ]]; then
export CC="$USE_CC"
fi
bazel fetch //...
bazel $BAZEL_STARTUP_OPTIONS test --config=asan $BAZEL_TEST_OPTIONS --linkopt -static-libasan //...
if [[ $RETRY_CLEAN -eq 1 ]]; then
echo "AddressSantinizer results:"
(
cd bazel-out
find . -name test.log -exec bash -c 'echo "============ $@ ============"; cat $@; echo "------------ $@ ------------"' _ {} \;
)
fi
# ============ tsan ============
if [[ "x$USE_CC" != "x" ]]; then
export CC="$USE_CC"
fi
bazel fetch //...
bazel $BAZEL_STARTUP_OPTIONS test --config=tsan $BAZEL_TEST_OPTIONS //...
if [[ $RETRY_CLEAN -eq 1 ]]; then
echo "ThreadSantinizer results:"
(
cd bazel-out
find . -name test.log -exec bash -c 'echo "============ $@ ============"; cat $@; echo "------------ $@ ------------"' _ {} \;
)
fi
# ============ valgrind ============
if [[ "x$USE_CC" != "x" ]]; then
export CC="$USE_CC"
fi
bazel fetch //...
bazel $BAZEL_STARTUP_OPTIONS build $BAZEL_OPTIONS //...
bazel $BAZEL_STARTUP_OPTIONS test --run_under="/usr/bin/valgrind --leak-check=full --error-exitcode=1 --suppressions=\"${PWD}/ci/valgrind-suppressions\"" $BAZEL_TEST_OPTIONS //...
# ============ benchmark ============
if [[ "x$USE_CC" != "x" ]]; then
export CC="$USE_CC"
fi
[ -z "${BENCHMARK_DIR}" ] && export BENCHMARK_DIR=$HOME/benchmark
bazel fetch //...
bazel $BAZEL_STARTUP_OPTIONS build $BAZEL_OPTIONS -c opt -- $(bazel query 'attr("tags", "benchmark_result", ...)')
echo "Benchmark results in $BENCHMARK_DIR:"
(
cd bazel-bin
find . -name \*_result.txt -exec bash -c \
'echo "$@" && mkdir -p "$BENCHMARK_DIR/$(dirname "$@")" && \
cp "$@" "$BENCHMARK_DIR/$@" && chmod +w "$BENCHMARK_DIR/$@"' _ {} \;
)