470 lines
16 KiB
Bash
470 lines
16 KiB
Bash
#!/bin/bash
|
||
# shellcheck disable=SC2155
|
||
if ! type "include" > /dev/null 2>&1; then
|
||
include() {
|
||
. "$(cd "$(dirname "$1")" && pwd)/${2}";
|
||
};
|
||
fi
|
||
include "${BASH_SOURCE[0]}" ../pragma_once.bash
|
||
if ! pragma_once ${BASH_SOURCE[0]}; then return 0; fi
|
||
include "${BASH_SOURCE[0]}" ../base/export.bash
|
||
false && source ../base/export.bash
|
||
|
||
|
||
|
||
# 必选项
|
||
export bge_install_prefix
|
||
# 平台选项
|
||
export bge_build bge_host bge_target
|
||
export bge_source_sysroot # 交叉编译和 拿大编译必填项 使用模式两种 软链接使用和 复制使用
|
||
export bge_sysroot_use_mode # 使用模式两种 软链接(link), 复制(copy) 使用
|
||
|
||
# 1阶段gcc
|
||
export bge_stage1 # 1代表这是不依赖glibc的gcc,用于构建glibc的gcc,0代表是普通的gcc
|
||
|
||
# url选项集合
|
||
export bge_gcc_ver bge_gcc_suffix_opts
|
||
export bge_gmp_url bge_gmp_suffix_opts
|
||
export bge_mpfr_url bge_mpfr_suffix_opts
|
||
export bge_mpc_url bge_mpc_suffix_opts
|
||
export bge_binutils_gdb_ver bge_binutils_gdb_suffix_opts
|
||
export bge_isl_url bge_isl_suffix_opts
|
||
|
||
# 内部自动计算的变量(每次都会刷新)
|
||
export bge_build_mode # native pseudo_native cross canadian_stage3
|
||
export b_cpu b_vendor b_os b_abi
|
||
export h_cpu h_vendor h_os h_abi
|
||
export t_cpu t_vendor t_os t_abi
|
||
|
||
export bge_toolchain_name
|
||
|
||
|
||
bge_dump_config() {
|
||
log_info "========== 【构建gcc 全局选项 BGE CONFIG】 =========="
|
||
|
||
log_info "%-24s = %s" "bge_install_prefix" "${bge_install_prefix}"
|
||
|
||
log_info "%-24s = %s" "bge_build" "${bge_build}"
|
||
log_info "%-24s = %s" "bge_host" "${bge_host}"
|
||
log_info "%-24s = %s" "bge_target" "${bge_target}"
|
||
log_info "%-24s = %s" "bge_build_mode" "${bge_build_mode}"
|
||
|
||
log_info "%-24s = %s" "bge_source_sysroot" "${bge_source_sysroot}"
|
||
log_info "%-24s = %s" "bge_sysroot_use_mode" "${bge_sysroot_use_mode}"
|
||
|
||
log_info "内部自动计算的变量"
|
||
parse_triplet "$bge_build" b_cpu b_vendor b_os b_abi
|
||
parse_triplet "$bge_host" h_cpu h_vendor h_os h_abi
|
||
parse_triplet "$bge_target" t_cpu t_vendor t_os t_abi
|
||
log_info "bge_build_mode:%s" "${bge_build_mode}"
|
||
log_info "%-24s = cpu=%-12s vendor=%-12s os=%-12s abi=%s" "build tuple" "$b_cpu" "$b_vendor" "$b_os" "$b_abi"
|
||
log_info "%-24s = cpu=%-12s vendor=%-12s os=%-12s abi=%s" "host tuple" "$h_cpu" "$h_vendor" "$h_os" "$h_abi"
|
||
log_info "%-24s = cpu=%-12s vendor=%-12s os=%-12s abi=%s" "target tuple" "$t_cpu" "$t_vendor" "$t_os" "$t_abi"
|
||
|
||
|
||
|
||
log_info "每次build_gcc后需要,手动重置的变量"
|
||
log_info "%-24s = %s" "bge_gcc_ver" "${bge_gcc_ver}"
|
||
log_info "%-24s = %s" "bge_gcc_suffix_opts" "${bge_gcc_suffix_opts}"
|
||
log_info "%-24s = %s" "bge_gmp_url" "${bge_gmp_url}"
|
||
log_info "%-24s = %s" "bge_gmp_suffix_opts" "${bge_gmp_suffix_opts}"
|
||
log_info "%-24s = %s" "bge_mpfr_url" "${bge_mpfr_url}"
|
||
log_info "%-24s = %s" "bge_mpfr_suffix_opts" "${bge_mpfr_suffix_opts}"
|
||
log_info "%-24s = %s" "bge_mpc_url" "${bge_mpc_url}"
|
||
log_info "%-24s = %s" "bge_mpc_suffix_opts" "${bge_mpc_suffix_opts}"
|
||
log_info "%-24s = %s" "bge_isl_url" "${bge_isl_url}"
|
||
log_info "%-24s = %s" "bge_isl_suffix_opts" "${bge_isl_suffix_opts}"
|
||
log_info "%-24s = %s" "bge_binutils_gdb_ver" "${bge_binutils_gdb_ver}"
|
||
log_info "%-24s = %s" "bge_binutils_gdb_suffix_opts" "${bge_binutils_gdb_suffix_opts}"
|
||
|
||
|
||
|
||
log_info "%-24s = %s" "bge_toolchain_name" "${bge_toolchain_name}"
|
||
|
||
log_info "========== 【构建gcc 全局选项 BGE CONFIG】 =========="
|
||
}
|
||
|
||
bge_refresh_ver(){
|
||
bge_gcc_ver="releases/gcc-15.1.0"
|
||
bge_gcc_suffix_opts=""
|
||
bge_gmp_url="https://mirrors.tuna.tsinghua.edu.cn/gnu/gmp/gmp-6.2.0.tar.xz"
|
||
bge_gmp_suffix_opts=""
|
||
bge_mpfr_url="https://mirrors.tuna.tsinghua.edu.cn/gnu/mpfr/mpfr-4.2.2.tar.xz"
|
||
bge_mpfr_suffix_opts=""
|
||
bge_mpc_url="https://mirrors.tuna.tsinghua.edu.cn/gnu/mpc/mpc-1.3.1.tar.gz"
|
||
bge_mpc_suffix_opts=""
|
||
bge_isl_url="https://libisl.sourceforge.io/isl-0.26.tar.xz"
|
||
bge_isl_suffix_opts=""
|
||
bge_binutils_gdb_ver="binutils-2_46"
|
||
bge_binutils_gdb_suffix_opts=""
|
||
}
|
||
|
||
bge_init_params() {
|
||
# 必选项
|
||
bge_install_prefix="${_ae_root_}/env/local_gcc_15_1_0"
|
||
# 平台选项
|
||
local local_triplet
|
||
detect_platform_triplet local_triplet local_triplet_no_vendor
|
||
bge_build="${local_triplet}"
|
||
bge_host="${local_triplet}"
|
||
bge_target="${local_triplet}"
|
||
bge_source_sysroot=""
|
||
bge_sysroot_use_mode="link"
|
||
# 1阶段gcc
|
||
bge_stage1=0
|
||
# url选项集合
|
||
bge_refresh_ver
|
||
}
|
||
# 初始化参数值
|
||
bge_init_params
|
||
|
||
bge_check_params() {
|
||
bge_dump_config
|
||
[[ -z "$bge_build" || -z "$bge_host" || -z "$bge_target" ]] && log_error "ERROR:build/host/target not fully set" && exit 1
|
||
log_info "原始 build:$bge_build host:$bge_host target:$bge_target"
|
||
check_value_in_range bge_sysroot_use_mode "link" "copy"
|
||
check_value_in_range bge_stage1 "1" "0"
|
||
|
||
|
||
|
||
local b_full="${b_cpu}-${b_vendor}-${b_os}-${b_abi}"
|
||
local h_full="${h_cpu}-${h_vendor}-${h_os}-${h_abi}"
|
||
local t_full="${t_cpu}-${t_vendor}-${t_os}-${t_abi}"
|
||
|
||
local b_core="${b_cpu}_${b_os}_${b_abi}"
|
||
local h_core="${h_cpu}_${h_os}_${h_abi}"
|
||
local t_core="${t_cpu}_${t_os}_${t_abi}"
|
||
|
||
log_info "核心 build:$b_core host:$h_core target:$t_core"
|
||
|
||
if [[ "$b_full" == "$h_full" && "$h_full" == "$t_full" ]]; then
|
||
bge_build_mode="native"
|
||
|
||
elif [[ "$b_core" == "$h_core" && "$h_core" == "$t_core" ]]; then
|
||
bge_build_mode="pseudo_native"
|
||
|
||
elif [[ "$b_full" == "$h_full" ]]; then
|
||
bge_build_mode="cross"
|
||
else
|
||
bge_build_mode="canadian_stage3"
|
||
fi
|
||
# check_and_create_dir "$bge_source_sysroot"
|
||
if [[ "$bge_build_mode" == "cross" ||
|
||
"$bge_build_mode" == "canadian_stage3" ]]; then
|
||
[[ "$bge_sysroot_use_mode" != "link" && "$bge_sysroot_use_mode" != "copy" ]] && log_error "ERROR:invalid bge_sysroot_use_mode:$bge_sysroot_use_mode" && exit 5
|
||
fi
|
||
log_info "$bge_build_mode check ok!"
|
||
}
|
||
|
||
|
||
bge_setup_canadian_compilers() {
|
||
[[ "$bge_build_mode" == "canadian_stage3" ]] || return 0
|
||
local build_cc
|
||
local build_cxx
|
||
build_cc="$(command -v gcc)"
|
||
build_cxx="$(command -v g++)"
|
||
export CC="${bge_host}-gcc"
|
||
export CXX="${bge_host}-g++"
|
||
export CC_FOR_BUILD="$build_cc"
|
||
export CXX_FOR_BUILD="$build_cxx"
|
||
export CPP_FOR_BUILD="$build_cc -E"
|
||
export CC_FOR_TARGET="${bge_target}-gcc"
|
||
export CXX_FOR_TARGET="${bge_target}-g++"
|
||
log_info "canadian compilers: build=%s host=%s target=%s" "$CC_FOR_BUILD" "$CC" "$CC_FOR_TARGET"
|
||
}
|
||
# sudo apt install flex bison git依赖
|
||
build_gcc_ex() {
|
||
bge_check_params
|
||
bge_setup_canadian_compilers
|
||
local sysroot=""
|
||
|
||
if [[ "$bge_build_mode" == "cross" ||
|
||
"$bge_build_mode" == "canadian_stage3" ]]; then
|
||
local base="${bge_install_prefix}/${bge_target}"
|
||
sysroot="${base}/sysroot"
|
||
exec_record_fast_fail "rm -rf \"${sysroot}\""
|
||
exec_record_fast_fail "mkdir -p \"$(dirname "${sysroot}")\""
|
||
if [[ "$bge_sysroot_use_mode" == "link" ]]; then
|
||
local relative_path
|
||
relative_path=$(realpath --relative-to="$(dirname "${sysroot}")" "${bge_source_sysroot}")
|
||
log_info "sysroot: ${sysroot} bge_source_sysroot:${bge_source_sysroot} relative_path:${relative_path}"
|
||
exec_record_fast_fail "ln -s \"${relative_path}\" \"${sysroot}\""
|
||
elif [[ "$bge_sysroot_use_mode" == "copy" ]]; then
|
||
exec_record_fast_fail "mkdir -p \"${sysroot}\""
|
||
exec_record_fast_fail "cp -a \"${bge_source_sysroot}/.\" \"${sysroot}/\""
|
||
fi
|
||
fi
|
||
if [[ "$bge_build_mode" == "pseudo_native" ]]; then
|
||
sysroot="/"
|
||
fi
|
||
|
||
|
||
|
||
|
||
(
|
||
#GMP(大整数库)在 MinGW/Windows host 场景下的一个明确限制:
|
||
# 在同一次构建里同时启用 --enable-shared 和 --enable-static,
|
||
# 会导致生成的 gmp.h 内容不一致(静态库和 DLL 的 gmp.h 有不同的导出宏/声明),
|
||
# 所以 configure 直接拒绝
|
||
local build_host="--build=$bge_build --host=$bge_host"
|
||
local prefix_opt="--prefix=$bge_install_prefix"
|
||
#local lib_opts="--disable-static --enable-shared"
|
||
local lib_opts="--enable-static --disable-shared"
|
||
|
||
configure_gnu_zip "$bge_gmp_url" "$prefix_opt $build_host $lib_opts $bge_gmp_suffix_opts"
|
||
exec_record_fast_fail "make -j $(nproc)"
|
||
exec_record_fast_fail "make install-strip -j $(nproc)"
|
||
|
||
configure_gnu_zip "$bge_mpfr_url" "$prefix_opt $build_host --with-gmp=$bge_install_prefix $lib_opts $bge_mpfr_suffix_opts"
|
||
exec_record_fast_fail "make -j $(nproc)"
|
||
exec_record_fast_fail "make install-strip -j $(nproc)"
|
||
|
||
configure_gnu_zip "$bge_mpc_url" "$prefix_opt $build_host --with-gmp=$bge_install_prefix --with-mpfr=$bge_install_prefix $lib_opts $bge_mpc_suffix_opts"
|
||
exec_record_fast_fail "make -j $(nproc)"
|
||
exec_record_fast_fail "make install-strip -j $(nproc)"
|
||
|
||
|
||
configure_gnu_zip "$bge_isl_url" "$prefix_opt $build_host --with-gmp-prefix=$bge_install_prefix $lib_opts $bge_isl_suffix_opts"
|
||
exec_record_fast_fail "make -j $(nproc)"
|
||
exec_record_fast_fail "make install-strip -j $(nproc)"
|
||
|
||
# --disable-doc 或者 apt install texinfo
|
||
local binutils_opts
|
||
binutils_opts="$prefix_opt --build=$bge_build --host=$bge_host --target=$bge_target \
|
||
--with-gmp=$bge_install_prefix --with-mpfr=$bge_install_prefix --with-mpc=$bge_install_prefix --with-isl=$bge_install_prefix \
|
||
--disable-doc --disable-werror --disable-nls"
|
||
if [[
|
||
"$bge_build_mode" == "cross" ||
|
||
"$bge_build_mode" == "canadian_stage3" ]] \
|
||
; then
|
||
local ld_search_path="=/lib:=/lib64:=/usr/lib:=/usr/lib64:=/lib/${bge_target}:=/usr/lib/${bge_target}"
|
||
# 这里=会在后续的链接器选项中变成sysroot
|
||
binutils_opts="${binutils_opts} --with-sysroot=$sysroot --with-lib-path=${ld_search_path}"
|
||
fi
|
||
|
||
if [[ "$bge_build_mode" == "pseudo_native" ]]; then
|
||
binutils_opts="${binutils_opts} --with-sysroot=$sysroot"
|
||
fi
|
||
|
||
|
||
|
||
binutils_opts="${binutils_opts} $bge_binutils_gdb_suffix_opts"
|
||
# configure_gnu_zip "$bge_binutils_url" "$binutils_opts"
|
||
|
||
|
||
local src_dir
|
||
ensure_repo_version src_dir "binutils-gdb" "$bge_binutils_gdb_ver"
|
||
configure_gnu "${src_dir}" "$binutils_opts"
|
||
exec_record_fast_fail "make -j $(nproc)"
|
||
exec_record_fast_fail "make install-strip -j $(nproc)"
|
||
)
|
||
|
||
|
||
|
||
# --disable-multiarch \ 怎么确定sysroot是不是 multiarch 布局
|
||
check_ret_exit "构建gcc_rely_${bge_build_mode}失败!"
|
||
(
|
||
# 这里不能加" 加了的话 eval 执行不对了 寻找匹配的“"”时遇到了未预期的文件结束符
|
||
local gcc_opts=" \
|
||
--prefix=$bge_install_prefix \
|
||
--build=$bge_build --host=$bge_host --target=$bge_target \
|
||
--with-gmp=$bge_install_prefix \
|
||
--with-mpfr=$bge_install_prefix \
|
||
--with-mpc=$bge_install_prefix \
|
||
--with-isl=$bge_install_prefix \
|
||
"
|
||
# if [[ "${h_os}" == "w64" ]]; then
|
||
# local exe_dir="${bge_install_prefix}/bin"
|
||
# gcc_opts="\
|
||
# --libexecdir=\"${exe_dir}/\" \
|
||
# ${gcc_opts}"
|
||
# log_info "w64 添加库到exe所在目录, 这样不用配置环境变量"
|
||
# fi
|
||
|
||
if [[ "$bge_stage1" == "0" ]]; then
|
||
log_info "构建普通gcc,依赖glibc"
|
||
gcc_opts="\
|
||
--disable-multilib \
|
||
--enable-languages=c,c++ \
|
||
--enable-shared \
|
||
--enable-static \
|
||
--disable-werror \
|
||
--disable-bootstrap \
|
||
--disable-libsanitizer \
|
||
--disable-libssp \
|
||
${gcc_opts}"
|
||
fi
|
||
|
||
if [[ "$bge_stage1" == "1" ]]; then
|
||
log_info "stage1 gcc(不依赖 glibc,用于构建 glibc)"
|
||
# --enable-shared 这个选项开启 会导致 stage1 链接glibc 所以要关掉
|
||
gcc_opts="\
|
||
--with-newlib \
|
||
--without-headers \
|
||
--without-isl \
|
||
--enable-initfini-array \
|
||
--disable-nls \
|
||
--disable-shared \
|
||
--enable-static \
|
||
--disable-multilib \
|
||
--disable-decimal-float \
|
||
--disable-threads \
|
||
--disable-libatomic \
|
||
--disable-libgomp \
|
||
--disable-libquadmath \
|
||
--disable-libssp \
|
||
--disable-libvtv \
|
||
--disable-libstdcxx \
|
||
--disable-bootstrap \
|
||
--enable-languages=c,c++ \
|
||
${gcc_opts}"
|
||
fi
|
||
|
||
if [[ "$bge_build_mode" == "cross" ||
|
||
"$bge_build_mode" == "canadian_stage3" ]]; then
|
||
gcc_opts="--with-sysroot=$sysroot ${gcc_opts}"
|
||
fi
|
||
if [[ "$bge_build_mode" == "pseudo_native" ]]; then
|
||
# --with-native-system-header-dir=/usr/include
|
||
gcc_opts="--with-sysroot=${sysroot} ${gcc_opts}"
|
||
fi
|
||
gcc_opts="${gcc_opts} ${bge_gcc_suffix_opts}"
|
||
|
||
local src_dir
|
||
ensure_repo_version src_dir "gcc" "$bge_gcc_ver"
|
||
exec_record_fast_fail "rm -rf \"${src_dir}/build\""
|
||
cd "${src_dir}" || exit
|
||
|
||
|
||
# 如果启用了这个选项 共有依赖项就会全部失效
|
||
#exec_record "./contrib/download_prerequisites"
|
||
#export LD_LIBRARY_PATH="${bge_install_prefix}/lib:$LD_LIBRARY_PATH"
|
||
configure_gnu "${src_dir}" "$gcc_opts"
|
||
|
||
if [[ "$bge_stage1" == "0" ]]; then
|
||
exec_record_fast_fail "make -j $(nproc)"
|
||
#exec_record_fast_fail "make install -j $(nproc)"
|
||
exec_record_fast_fail "make install-strip -j $(nproc)"
|
||
fi
|
||
|
||
if [[ "$bge_stage1" == "1" ]]; then
|
||
exec_record_fast_fail "make all-gcc -j $(nproc)"
|
||
exec_record_fast_fail "make install-gcc -j $(nproc)"
|
||
exec_record_fast_fail "make all-target-libgcc -j $(nproc)"
|
||
exec_record_fast_fail "make install-target-libgcc -j $(nproc)"
|
||
fi
|
||
)
|
||
check_ret_exit "构建gcc_${bge_build_mode}失败!"
|
||
|
||
# 创建 cc c++ 软链接, gcc 安装一般不会附带 但是发行版会自己附带来兼容
|
||
local gcc_bin="${bge_install_prefix}/bin"
|
||
cd "${gcc_bin}"
|
||
ln -sf "${bge_target}-gcc" cc
|
||
ln -sf "${bge_target}-g++" c++
|
||
|
||
|
||
# 生成cmake 工具链文件
|
||
local SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
local template="${SCRIPT_DIR}/cmake_template/toolchain_template.cmake"
|
||
|
||
|
||
local cmake_os=""
|
||
local cmake_cpu=""
|
||
gnu_os_to_cmake_system_name "$t_os" cmake_os
|
||
gnu_cpu_to_cmake_system_processor "$t_cpu" cmake_cpu
|
||
log_debug "cmake OS -> $cmake_os"
|
||
log_debug "cmake CPU -> $cmake_cpu"
|
||
|
||
|
||
local exe shared static prefix
|
||
gnu_triple_to_suffixes ${bge_host} exe shared static prefix
|
||
|
||
|
||
template_render_to_file_strict "${template}" "${bge_install_prefix}/${bge_toolchain_name}.cmake" \
|
||
CMAKE_SYSTEM_NAME "${cmake_os}" \
|
||
CMAKE_SYSTEM_PROCESSOR "${cmake_cpu}" \
|
||
exe_suffix "${exe}" \
|
||
build "${bge_build}" \
|
||
host "${bge_host}" \
|
||
target "${bge_target}"
|
||
|
||
|
||
|
||
local preset_template="${SCRIPT_DIR}/cmake_template/toolchain_template.json"
|
||
template_render_to_file_strict "${preset_template}" "${bge_install_prefix}/preset.json" \
|
||
toolchain_name "${bge_toolchain_name}"
|
||
}
|
||
|
||
#https://mirrors.tuna.tsinghua.edu.cn/gnu/gcc/gcc-15.1.0/gcc-15.1.0.tar.xz
|
||
#"15.1.0"
|
||
|
||
upgrade_local_gcc() {
|
||
local ver="$1"
|
||
local vendor="$2" # 空字符串就是local_triplet
|
||
|
||
[[ -z "$ver" ]] && log_error "ERROR:ver required" && exit 1
|
||
[[ -z "$_root_" ]] && log_error "ERROR:_root_ not set" && exit 2
|
||
|
||
local local_triplet local_triplet_no_vendor
|
||
detect_platform_triplet local_triplet local_triplet_no_vendor
|
||
|
||
local new_triplet
|
||
if [[ -z "$vendor" ]]; then
|
||
new_triplet="$local_triplet"
|
||
else
|
||
local local_cpu local_vendor local_os local_abi
|
||
parse_triplet "$local_triplet" local_cpu local_vendor local_os local_abi
|
||
compose_triplet new_triplet "$local_cpu" "$vendor" "$local_os" "$local_abi"
|
||
fi
|
||
local install_prefix="${_ae_root_}/toolchain/${new_triplet}"
|
||
bge_install_prefix="${install_prefix}/$ver"
|
||
|
||
log_info "bge_install_prefix $bge_install_prefix"
|
||
|
||
|
||
bge_gcc_ver="${ver}"
|
||
bge_build="$local_triplet"
|
||
bge_host="$local_triplet"
|
||
bge_target="$new_triplet"
|
||
bge_source_sysroot=""
|
||
bge_sysroot_use_mode="link"
|
||
build_gcc_ex
|
||
}
|
||
|
||
build_local_local_cross_gcc() {
|
||
local target="$1"
|
||
local ver="$2"
|
||
local source_sysroot="$3"
|
||
|
||
[[ -z "$target" ]] && log_error "ERROR: target required" && exit 1
|
||
[[ -z "$ver" ]] && log_error "ERROR: ver required" && exit 1
|
||
[[ -z "$source_sysroot" ]] && log_error "ERROR: source_sysroot required" && exit 1
|
||
[[ ! -d "$source_sysroot" ]] && log_error "ERROR: sysroot not found: $source_sysroot" && exit 1
|
||
[[ -z "$_root_" ]] && log_error "ERROR:_root_ not set" && exit 2
|
||
(
|
||
local local_triplet local_triplet_no_vendor
|
||
detect_platform_triplet local_triplet local_triplet_no_vendor
|
||
|
||
local install_prefix="$_root_/gcc/${target}"
|
||
bge_install_prefix="${install_prefix}_$ver"
|
||
|
||
bge_build="$local_triplet"
|
||
bge_host="$local_triplet"
|
||
bge_target="$target"
|
||
|
||
bge_source_sysroot="$source_sysroot"
|
||
bge_sysroot_use_mode="copy"
|
||
|
||
|
||
bge_gcc_ver="${ver}"
|
||
#bge_gcc_ver="https://mirrors.tuna.tsinghua.edu.cn/gnu/gcc/gcc-$ver/gcc-$ver.tar.xz"
|
||
build_gcc_ex
|
||
)
|
||
check_ret_exit "build_local_local_cross_gcc 编译错误!"
|
||
|
||
}
|
||
|
||
|
||
return 0
|
||
|