#!/bin/bash
set -e
CMAKE_FILES_L0=(
"cjson.cmake"
"absl.cmake"
"iconv.cmake"
"jemalloc.cmake"
"libzmq.cmake"
"nlohmann_json.cmake"
"openssl.cmake"
"pcre.cmake"
"rocksdb.cmake"
"securec.cmake"
"spdlog.cmake"
"tbb.cmake"
"xml2.cmake"
"zlib.cmake"
)
CMAKE_FILES_L1=(
"re2.cmake"
"protobuf.cmake"
"libcurl.cmake"
"grpc.cmake"
)
DEPENDENCIES=(
"re2:absl"
"protobuf:absl"
"libcurl:openssl"
"grpc:protobuf:openssl:zlib:re2"
)
function is_on() {
if [[ "X$1" = "Xon" ]]; then
return 0
else
return 1
fi
}
if is_on "${BUILD_TESTCASE}"; then
CMAKE_FILES_L0+=("gtest.cmake")
fi
if is_on "${PACKAGE_PYTHON}"; then
CMAKE_FILES_L0+=("pybind11.cmake")
fi
if is_on "${BUILD_HETERO}"; then
CMAKE_FILES_L0+=("ascend.cmake")
fi
readonly BASE_DIR=$(dirname "$(readlink -f "$0")")
BASEPATH=$(cd "$(dirname $0)"; pwd)
DATASYSTEM_HOME="$(realpath "${BASEPATH}/..")"
BUILD_PATH=$1
MULTI_BUILD_PATH="$(realpath "${BUILD_PATH}/multi_build")"
BUILD_THREAD_NUM=$2
CMAKE_OPTIONS=("${@:3}")
DEPENDENCY_DIR="${MULTI_BUILD_PATH}"/dependency
TIME_DIR="${MULTI_BUILD_PATH}"/timing
PROGRESS_DIR="${MULTI_BUILD_PATH}"/progress
TOTAL_LIBS=$((${#CMAKE_FILES_L0[@]} + ${#CMAKE_FILES_L1[@]}))
function log() {
local progress=$(get_progress_percent)
printf "[%3d%%] %s\n" "$progress" "$1"
}
function log_failed() {
log "$1"
}
function get_progress_percent() {
local completed_count=$(ls -1 "${PROGRESS_DIR}" 2>/dev/null | wc -l)
local percent=$((completed_count * 100 / TOTAL_LIBS))
echo "$percent"
}
function on_exit() {
local exit_status=$?
local lib_name="${cmake_file%%.*}"
local end_time=$(date +%s)
local total_duration=$((end_time - overall_start_time))
if [ $exit_status -eq 0 ]; then
echo "$total_duration" > "${TIME_DIR}/${lib_name}.time"
touch "${PROGRESS_DIR}/${lib_name}.complete"
touch "${DEPENDENCY_DIR}/${lib_name}.complete"
log "$lib_name build success - ${total_duration}s"
else
touch "${DEPENDENCY_DIR}/${lib_name}.failed"
log "$lib_name build failed, see ${tmp_compile_dir}/log for details"
fi
}
function wait_for_dependencies() {
local lib_name=$1
local dependencies=$2
local lib_dependencies=()
if [ -n "$dependencies" ]; then
lib_dependencies_str=$(echo "$dependencies" | tr ':' ' ')
IFS=' ' read -r -a lib_dependencies <<< "${lib_dependencies_str}"
log "$lib_name is still waiting for: ${lib_dependencies_str}"
local timeout=1800
local wait_start_time=$(date +%s)
for ((i=1; i<=timeout; i++)); do
all_files_created=true
missing_deps=()
failed_deps=()
for file in "${lib_dependencies[@]}"; do
if [ -f "${DEPENDENCY_DIR}/${file}.failed" ]; then
failed_deps+=("$file")
elif [ ! -f "${DEPENDENCY_DIR}/${file}.complete" ]; then
all_files_created=false
missing_deps+=("$file")
fi
done
if [ ${#failed_deps[@]} -gt 0 ]; then
log_failed "$lib_name failed because dependencies failed: ${failed_deps[*]}"
return 1
fi
if [ "$all_files_created" = true ]; then
local current_time=$(date +%s)
local wait_duration=$((current_time - wait_start_time))
log "$lib_name all dependencies ready (waited ${wait_duration}s)"
return 0
fi
if [ $((i % 30)) -eq 0 ]; then
local current_time=$(date +%s)
local elapsed=$((current_time - wait_start_time))
log "$lib_name still waiting for: ${missing_deps[*]} (${elapsed}s elapsed)"
fi
sleep 1
done
log_failed "$lib_name timeout waiting for dependencies"
return 1
fi
return 0
}
function main() {
log "Start compiling thirdparty libraries in parallel"
local start_time_s
local end_time_s
local sumTime
start_time_s=$(date +%s)
mkdir -p ${DEPENDENCY_DIR}
mkdir -p ${TIME_DIR}
mkdir -p ${PROGRESS_DIR}
log "Total libraries to compile: $TOTAL_LIBS"
log "Building independent libraries (L0)"
for cmake_file in "${CMAKE_FILES_L0[@]}";
do
tmp_compile_dir="${MULTI_BUILD_PATH}/${cmake_file%%.*}"
mkdir -p "${tmp_compile_dir}"
(
lib_name="${cmake_file%%.*}"
overall_start_time=$(date +%s)
log "Building $lib_name..."
trap on_exit EXIT
cd "${tmp_compile_dir}"
cat > "CMakeLists.txt" << EOF
cmake_minimum_required(VERSION 3.14.1)
set(CMAKE_SOURCE_DIR ${DATASYSTEM_HOME})
set(CMAKE_BINARY_DIR ${BUILD_PATH})
set(EXPORT_TO_USER_ENV_FILE "${MULTI_BUILD_PATH}/L0_ENV")
include(${DATASYSTEM_HOME}/cmake/options.cmake)
include(${DATASYSTEM_HOME}/cmake/util.cmake)
include(${DATASYSTEM_HOME}/cmake/external_libs/${cmake_file})
EOF
mkdir -p build && cd build
cmake "${CMAKE_OPTIONS[@]}" .. >> "${tmp_compile_dir}/log" 2>&1
cmake --build . >> "${tmp_compile_dir}/log" 2>&1
) &
done
touch ${MULTI_BUILD_PATH}/L1_ENV
log "Building dependent libraries (L1)"
for cmake_file in "${CMAKE_FILES_L1[@]}";
do
tmp_compile_dir="${MULTI_BUILD_PATH}/${cmake_file%%.*}"
mkdir -p "${tmp_compile_dir}"
dependencies=""
for dep in "${DEPENDENCIES[@]}"; do
if [[ "$dep" == "${cmake_file%%.*}:"* ]]; then
dependencies=$(echo "${dep}" | cut -d':' -f2-)
break
fi
done
(
lib_name="${cmake_file%%.*}"
overall_start_time=$(date +%s)
if ! wait_for_dependencies "$lib_name" "$dependencies"; then
exit 1
fi
log "Building $lib_name..."
trap on_exit EXIT
cd "${tmp_compile_dir}"
cat > "CMakeLists.txt" << EOF
cmake_minimum_required(VERSION 3.14.1)
set(CMAKE_SOURCE_DIR ${DATASYSTEM_HOME})
set(CMAKE_BINARY_DIR ${BUILD_PATH})
$(cat ${MULTI_BUILD_PATH}/L0_ENV)
$(cat ${MULTI_BUILD_PATH}/L1_ENV)
set(EXPORT_TO_USER_ENV_FILE "${MULTI_BUILD_PATH}/L1_ENV")
include(${DATASYSTEM_HOME}/cmake/options.cmake)
include(${DATASYSTEM_HOME}/cmake/util.cmake)
include(${DATASYSTEM_HOME}/cmake/external_libs/${cmake_file})
EOF
mkdir -p build && cd build
cmake "${CMAKE_OPTIONS[@]}" .. >> "${tmp_compile_dir}/log" 2>&1
cmake --build . -j "${BUILD_THREAD_NUM}" >> "${tmp_compile_dir}/log" 2>&1
) &
done
wait
end_time_s=$(date +%s)
sumTime=$(($end_time_s - $start_time_s))
log "Compile thirdparty libraries success, total wall time: ${sumTime}s"
exit 0
}
main "$@"