#!/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


include "${BASH_SOURCE[0]}" ../gcc/export.bash
false && source ../gcc/export.bash


include "${BASH_SOURCE[0]}" ../Qt/export.bash
false && source ../Qt/export.bash




# gcc_env
export gev_target_env
export gev_target_sysroot
export gev_cross_dir
export gev_canadian_dir
export gev_stage1_dir
export gev_local_dir
export gev_cur_env_name
export gev_cur_toolchain_name
# 构建sysroot所需
export gev_linux_ver #   下载linux 内核源码的 url
export gev_linux_arch    #   linux arch架构名称
export gev_glibc_ver gev_glibc_suffix_opts
export gev_stage1_gcc_ver gev_stage1_gcc_suffix_opts
# 自动计算
export gev_local_triplet gev_local_triplet_no_vendor
export gev_target
export gev_build


# 这个函数不能放到gcc编译的开头因为gcc编译的开头需要外部的参数  如果设置了外部参数就失效了
gev_init_params() {
  gev_target_env=""
  gev_target_sysroot=""
  gev_cross_dir=""
  gev_canadian_dir=""
  gev_stage1_dir=""
  gev_local_dir=""
  gev_cur_env_name=""
  gev_cur_toolchain_name=""
  gev_linux_ver="v5.15.139"
  gev_linux_arch="x86_64"
  gev_glibc_ver="glibc-2.31"
  gev_glibc_suffix_opts=""
  gev_stage1_gcc_ver="releases/gcc-10.5.0"
  gev_stage1_gcc_suffix_opts=""
}
# 初始化全局变量参数值
gev_init_params
init_by_env_name() {
  detect_platform_triplet gev_local_triplet gev_local_triplet_no_vendor
  gev_build=${gev_local_triplet}
  gev_cur_env_name="${1}"
  gev_cur_toolchain_name="${gev_cur_env_name}"
  gev_target="${2}"
  gev_target_env="/ae/env/${gev_cur_env_name}"
  # 这个地方可以改 sysroot 叫什么名称
  gev_target_sysroot="${gev_target_env}/sysroot_${gev_target}"
  gev_cross_dir="${gev_target_env}"
  gev_canadian_dir="${gev_target_env}"
  gev_stage1_dir="${gev_target_env}/stage1"
  gev_local_dir="${gev_target_env}/local"
  check_and_create_dir "$gev_target_sysroot"
  # 设置当前日志路径
  LOG_PATH="${gev_target_env}/build.log"
  log_info "init_by_env_name ok！"
}


cacl_toolchain_name(){
  local -n ret="$1"
  local build="$2"
  local host="$3"
  local target="$4"
  local ver="$5"
  ver="${ver//\//_}"
  ret="${ver}_${host}"
}

cacl_toolchain_name_cross(){
  local ver="$2"
  cacl_toolchain_name "${1}" "${gev_build}" "${gev_build}" "${gev_target}" "${ver}"
}

# env_name source_sysroot
init_env() {
  init_by_env_name "${1}" "${3}"
  local source_sysroot="${2}"
  #  cp -a "$source_sysroot/." "$gev_target_sysroot/"
  if [[ -d "$gev_target_sysroot" ]] && [[ "$(ls -A "$gev_target_sysroot" 2>/dev/null)" ]]; then
    log_info "sysroot already exists, skip copy: $gev_target_sysroot\n"
  else
    log_info "copy sysroot: [$source_sysroot] -> [$gev_target_sysroot]\n"
    mkdir -p "$gev_target_sysroot"
    check_directory_var source_sysroot
    cp -a "$source_sysroot/." "$gev_target_sysroot/"

#    rsync -aH --numeric-ids \
#      --exclude='/dev/*' \
#      --exclude='/proc/*' \
#      --exclude='/sys/*' \
#      --exclude='/run/*' \
#      "$source_sysroot/" \
#      "$gev_target_sysroot/"


#    rsync -aH --numeric-ids \
#      --include='/usr/' \
#      --include='/usr/include/***' \
#      --include='/usr/lib/***' \
#      --include='/lib/***' \
#      --include='/lib64/***' \
#      --include='/etc/' \
#      --include='/etc/ld.so.conf' \
#      --include='/etc/ld.so.conf.d/***' \
#      --exclude='*' \
#      "$source_sysroot/" \
#      "$gev_target_sysroot/"

#    rsync -aH --numeric-ids \
#      --include='/usr/' \
#      --include='/usr/include/***' \
#      --include='/usr/lib/' \
#      --include="/usr/lib/${bge_target}/***" \
#      --include='/usr/lib/gcc/' \
#      --include="/usr/lib/gcc/${bge_target}/***" \
#      --include='/lib/' \
#      --include="/lib/${bge_target}/***" \
#      --include='/lib64/***' \
#      --include='/etc/' \
#      --include='/etc/ld.so.conf' \
#      --include='/etc/ld.so.conf.d/***' \
#      --exclude='*' \
#      "$source_sysroot/" \
#      "$gev_target_sysroot/"

    #copy_compile_sysroot_files  "$source_sysroot" "$gev_target_sysroot" "$bge_target"

  fi
  log_info "env initialized: env=[${gev_target_env}] sysroot=[${gev_target_sysroot}]\n"
}

attach_env_stage1_gcc() {
  log_info "attach_env_stage1_gcc start"
  local target="$1"
  local local_triplet local_triplet_no_vendor
  detect_platform_triplet local_triplet local_triplet_no_vendor
  bge_gcc_ver="${gev_stage1_gcc_ver}"
  bge_stage1=1
  bge_install_prefix="${gev_stage1_dir}/gcc_stage1_${target}"
  bge_build="$local_triplet"
  bge_host="$local_triplet"
  bge_target="$target" #注意这一点  即使是cross 编译  stage1 gcc  永远是本机gcc
  bge_sysroot_use_mode="link"
  bge_source_sysroot="$bge_install_prefix/sysroot"
  bge_toolchain_name="${gev_cur_toolchain_name}"
  check_and_create_dir "${bge_source_sysroot}"
  build_gcc_ex
  log_info "attach_env_stage1_gcc end"
}



# env_name target  选项没配置对  目前编译到 glibc checking host system type... Invalid configuration `aarch64-linux-gnu': machine `aarch64' not recognized
init_env_build_sysroot() {

  #  https://stackoverflow.com/questions/28904902/how-do-i-change-gccs-default-search-directory-for-crti-o?utm_source=chatgpt.com
  #  https://gcc.gnu.org/onlinedocs/gcc/Spec-Files.html?utm_source=chatgpt.com
  #  https://gcc.gnu.org/onlinedocs/gccint/Driver.html?utm_source=chatgpt.com
  #  第一处是 GCC 的 spec 机制文档。官方明确写了：
  #  %S：处理 startfile spec，也就是“决定哪些对象文件作为最先传给 linker 的文件”，典型就是 crt0.o、crt1.o、crti.o 这类启动文件。
  #  %E：处理 endfile spec，也就是“决定哪些对象文件作为最后传给 linker 的文件”，典型就是 crtn.o 这类收尾文件。
  #  第二处是 GCC Internals 的 Driver 文档。里面把这些宏的职责写得更直接：
  #  STARTFILE_SPEC 指定标准 C startup file。
  #  ENDFILE_SPEC 指定标准 C end file。
  #  文档还说明，如果没有定义这些宏，就会用默认值。
  #  这意味着：
  #  crti.o、crt1.o 这类不是普通 -lxxx 库
  #  它们走的是 STARTFILE_SPEC
  #  crtn.o 这类走的是 ENDFILE_SPEC
  #  所以它们和 -lc、-lm 这类普通库的搜索规则不是一回事
  # /ae/bash/0_git_cache_dir/gcc/build/gcc/specs


  init_by_env_name "${1}"
  local target="${2}"
  local t_cpu t_vendor t_os t_abi
  parse_triplet "$target" t_cpu t_vendor t_os t_abi

  local linuxarch=$t_cpu
  if [[ $linuxarch == "aarch64" ]]; then
    linuxarch="arm64"
  elif [[ $linuxarch =~ i[3-6]86 ]]; then
    linuxarch="x86"
  elif [[ $linuxarch != x86_64 ]]; then
    linuxarch="${linuxarch%%[0-9]*}"
  fi
  # 参数检查：确保必要参数存在
  if [[ -z "$target" ]]; then
    log_error "ERROR: target is required for init_env_build_sysroot\n"
    exit 1
  fi
  local build_triplet build_triplet_no_vendor
  detect_platform_triplet build_triplet build_triplet_no_vendor
  (
    log_info "step 1 stage1_gcc构建失败  Starting kernel header installation...\n"
    attach_env_stage1_gcc "${target}"
  )
  check_ret_exit "stage1_gcc构建失败！"
  (
    log_info "step 2 安装内核头文件  Starting kernel header installation... ${linuxarch}  ${gev_linux_ver}\n"
    local install_prefix="${gev_target_sysroot}/usr"
    local src_dir
    ensure_repo_version src_dir "linux" "${gev_linux_ver}"
    cd $src_dir || exit 89
    check_and_create_dir "${install_prefix}"
    exec_record "make headers_install ARCH=${linuxarch} -j$(nproc) INSTALL_HDR_PATH=\"${install_prefix}\""
  )
  check_ret_exit "安装内核头文件失败！"
  (
    load_toolchains_under "$gev_stage1_dir"
    local glibc_triplet
    local glibc_cpu="${t_cpu}"
    compose_triplet glibc_triplet "${glibc_cpu}" "" "${t_os}" "${t_abi}"
    log_info "glibc_triplet  ${glibc_triplet}\n"
    local glibc_opts="\
        --build=${build_triplet} \
    --host=${target} \
    --with-headers=${gev_target_sysroot}/usr/include \
    --prefix=/usr \
    --disable-werror \
    --disable-nls \
    ${gev_glibc_suffix_opts}"
    log_info " step 3 编译glibc Compiling glibc with options: $gev_target_sysroot\n"
    log_info " glibc_opts: $glibc_opts\n"
    local src_dir
    ensure_repo_version src_dir "glibc" "${gev_glibc_ver}"
    configure_gnu_ex "${src_dir}" "$glibc_opts"
    exec_record_fast_fail "make -j $(nproc)"
    exec_record_fast_fail "make -h"
    exec_record_fast_fail "make install install_root=$gev_target_sysroot -j $(nproc)"

    local src_dir="${gev_target_sysroot}/usr/lib64"
    local dest_dir="${gev_target_sysroot}/lib"
    check_directory "${src_dir}"
    check_directory "${dest_dir}"
    local array=(crt1.o crti.o crtn.o gcrt1.o Scrt1.o rcrt1.o)
    log_info "cp [${array[*]}]  ${src_dir} ==> ${dest_dir} "
    for f in "${array[@]}"; do
      local src_file="$src_dir/$f"
      if [ -e "$src_file" ]; then
        echo "copy $f"
        cp -f "$src_file" "${dest_dir}"
      fi
    done


  )
  check_ret_exit "glibc 安装失败"
  log_info " 自构建sysroot环境搭建完成 env initialized: env=${gev_target_env} sysroot=${gev_target_sysroot}\n"
}


cacl_toolchain_name_canadian(){
  local host="$2"
  local ver="$3"
  cacl_toolchain_name "${1}" "${gev_build}" "${host}" "${gev_target}" "${ver}"
}

# target ver
attach_env_local_cross() {
  log_info "attach_env_local_cross start"
  local ver="$1"
  local target="$gev_target"
  [[ -z "$target" ]] && log_error "ERROR: target required\n" && exit 1
  [[ -z "$ver" ]] && log_error "ERROR: ver required\n" && exit 1
  (
    [[ ! -d "$gev_target_sysroot" ]] && log_error "ERROR: env sysroot not found: $gev_target_sysroot\n" && exit 1
    bge_build="$gev_local_triplet"
    bge_host="$gev_local_triplet"
    bge_target="$target"
    local toolchain_name
    cacl_toolchain_name_cross toolchain_name  "${ver}"
    bge_install_prefix="${gev_cross_dir}/${toolchain_name}"
    bge_source_sysroot="$gev_target_sysroot"
    bge_sysroot_use_mode="link"
    bge_gcc_ver="${ver}"
    bge_toolchain_name="${gev_cur_toolchain_name}"
    build_gcc_ex
  )
  log_info "attach_env_local_cross end"
}

load_toolchains_under() {
  local base="$1"
  [[ -d "$base" ]] || return 0

  local prefix trip

  # base 下每个子目录当作一个工具链 prefix（例如 cross/gcc_xxx 或 canadian/gcc_xxx）
  for prefix in "$base"/*; do
    [[ -d "$prefix" ]] || continue
    [[ -d "$prefix/bin" ]] || continue

    # prefix 下可能有 triplet 目录（aarch64-xxx-gnu 这类）
    for trip in "$prefix"/*; do
      [[ -d "$trip" ]] || continue
      local n
      n="$(basename "$trip")"

      # 跳过常见非 triplet 目录
      case "$n" in
      bin | lib | lib64 | include | share | etc | var | tmp | sysroot | cross | canadian | libexec) continue ;;
      esac
      load_toolchain "$prefix" "$n"
      log_info "loaded toolchain: prefix=$prefix triplet=$n\n"
      # 满足目录形态才加载
      if [[ -d "$prefix/$n/usr" || -d "$prefix/$n/sysroot/usr" || -d "$prefix/$n/sysroot/lib" ]]; then
        load_toolchain "$prefix" "$n"
        log_info "loaded toolchain: prefix=$prefix triplet=$n\n"
      fi
    done
  done
}

# sudo apt install -y mingw-w64 gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64
# 注意这个函数调用前需要加载 前两个交叉编译环境  默认的windows "x86_64-w64-mingw32"
# host target ver
# TODO: host是windows时 要编译mingw运行时库 和 移动 gmp mpc mpfr等库 到 ${root}/bin 里去
attach_env_canadian_stage3() {
  log_info "attach_env_canadian_stage3 start"
  local host="$1"
  local ver="$2"
  local target="$gev_target"
  bge_build="$gev_local_triplet"
  bge_host="$host"
  bge_target="$target"
  local toolchain_name

  local toolchain_name
  cacl_toolchain_name_canadian toolchain_name "${host}" "${ver}"
  bge_install_prefix="${gev_canadian_dir}/${toolchain_name}"
  (
    local target_toolchain_name host_toolchain_name
    cacl_toolchain_name_cross target_toolchain_name  "${ver}"
    cacl_toolchain_name host_toolchain_name  "${bge_build}" "${bge_build}" "${bge_host}" "${ver}"
    local target_tool_chain="${gev_cross_dir}/${target_toolchain_name}"
    local host_tool_chain="${gev_cross_dir}/${host_toolchain_name}"
    if [[ -d "$target_tool_chain" ]]; then
      load_toolchain "${target_tool_chain}" "${target}"
    else
      log_warn "target_tool_chain not exists: $target_tool_chain"
    fi
    if [[ -d "$host_tool_chain" ]]; then
      load_toolchain "${host_tool_chain}" "${host}"
    else
      log_warn "host_tool_chain not exists: $host_tool_chain"
    fi
    bge_source_sysroot="$gev_target_sysroot"
    bge_sysroot_use_mode="link"
    bge_gcc_ver="${ver}"
    bge_toolchain_name="${gev_cur_toolchain_name}"
    build_gcc_ex
  )
  log_info "attach_env_canadian_stage3 end"
}


attach_host_tool_qt(){
 bq_sysroot="${gev_target_sysroot}"
 bq_cross=0
 bq_install_prefix="${gev_local_dir}/Qt/${bq_ver}"
 build_qt
}


attach_cross_tool_qt(){
  bq_sysroot="${gev_target_sysroot}"
  bq_cross=1
  bq_host_tool_install_prefix="${gev_local_dir}/Qt/${bq_ver}"
  bq_platform="linux-g++"
  bq_xplatform="linux-aarch64-gnu-g++"
  bq_install_prefix="${gev_cross_dir}/Qt/${bq_xplatform}/${bq_ver}"

  log_info "attach_cross_tool_qt ${bq_install_prefix}"

  build_qt
}

attach_cross_win_qt(){
  bq_sysroot="${gev_target_sysroot}"
  bq_cross=1

  bq_platform="linux-g++"
  bq_xplatform="linux-aarch64-gnu-g++"
  bq_host_platform="win32-g++"
  bq_install_prefix="${gev_target_env}/Qt/${bq_host_platform}_${bq_xplatform}/${bq_ver}"

  bq_host_triplet="x86_64-w64-mingw32"
  bq_target_triplet="aarch64-linux-gnu"
  local h_cpu h_vendor h_os h_abi
  local t_cpu t_vendor t_os t_abi
  parse_triplet "${bq_host_triplet}" h_cpu h_vendor h_os h_abi
  parse_triplet "${bq_target_triplet}" t_cpu t_vendor t_os t_abi
  log_info "host    cpu[${h_cpu}] vendor[${h_vendor}] os[${h_os}] abi[${h_abi}] \n"
  log_info "target  cpu[${t_cpu}] vendor[${t_vendor}] os[${t_os}] abi[${t_abi}] \n"

  log_info "attach_cross_tool_qt ${bq_install_prefix}"
  build_qt
}

attach_win_2_arm_qt(){
  bq_sysroot="${gev_target_sysroot}"
  bq_cross=1
  bq_host_tool_install_prefix="${gev_local_dir}/Qt/${bq_ver}"
  bq_platform="linux-g++"
  bq_xplatform="linux-aarch64-gnu-g++"
  bq_install_prefix="${gev_cross_dir}/Qt/${bq_xplatform}/${bq_ver}"

  log_info "attach_cross_tool_qt ${bq_install_prefix}"

  build_qt
}

