之前搞 opentelemetry-cpp 的时候接触了下 bazel 构建系统。这玩意儿用起来有一点坑,特别是使用自定义编译环境的时候。

在使用我自己编译的很新版本的 GCCclang+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/$@"' _ {} \;
)