#
# GNU ld linker optimizations plugin
#
sh_join() {
  local delimiter=${1} input=${2}

  if shift 2; then
    printf "%s" "$input" "${@/#/$delimiter}"
  fi
}

gnu_ld_optimize_defaults()
{
  # default optimizations
  LDF=( Strip Relro Now SortCommon )
}

plugin_gnu_ld_optimize()
{
  local wlflags=()

  gnu_ld_optimize_defaults

  if [ -f /etc/lunar/local/optimizations.GNU_LD ]; then
    . /etc/lunar/local/optimizations.GNU_LD
  fi

  for LD in ${LDF[@]}; do
    case $LD in
      Strip)
        LDFLAGS="$LDFLAGS -s"
        ;;
      StripDebug)
        LDFLAGS="$LDFLAGS -S"
        ;;
      Optimize)
        wlflags+=("-O1")
        ;;
      Reduce)
        wlflags+=("--as-needed")
        ;;
      Combreloc)
        wlflags+=("-z,combreloc")
        ;;
      Relro)
        wlflags+=("-z,relro")
        ;;
      Now)
        wlflags+=("-z,now")
        ;;
      SortCommon)
        wlflags+=("--sort-common")
        ;;
    esac
  done

  if [ -n "$wlflags" ]; then
    LDFLAGS+=" $(sh_join , "-Wl" ${wlflags[@]})"
  fi

  export LDFLAGS
  verbose_msg "LDFLAGS=\"$LDFLAGS\""
  return 2
}


plugin_gnu_ld_optimize_menu()
{
  # The main code calls this function WITHOUT $1 to find out which
  # compiler optimization plugins exist. It then returns the version
  # number which will be saved in $LUNAR_COMPILER as the user's
  # choice for COMPILERS
  if [ -z "$1" ]; then
    echo "GNU_LD"
    echo "GNU ld - linker"
    return 2
  elif [ "$1" != "GNU_LD" ]; then
    # we don't display anything when the user selected a
    # different menu
    return 2
  fi

  gnu_ld_optimize_defaults

  # load previous optimizations
  if [ -e /etc/lunar/local/optimizations.GNU_LD ]; then
    . /etc/lunar/local/optimizations.GNU_LD
  fi

  save_optimizations()
  {
    debug_msg "save_optimizations($@)"
    cat > /etc/lunar/local/optimizations.GNU_LD  <<EOF
LDF=( $(echo ${LDF[@]} ) )
EOF
  }

  export IFS=$'\t\n'
  TITLE="Lunar Linker Optimizations"

  OPTIONS=(
    "Strip" "-s (RECOMMENDED)" $( echo ${LDF[@]} | grep -qw "Strip" && echo "on" || echo "off" ) "Strip all symbols"
    "StripDebug" "-S" $( echo ${LDF[@]} | grep -qw "StripDebug" && echo "on" || echo "off" ) "Strip debug symbols only"
    "Optimize" "-Wl,-O1" $( echo ${LDF[@]} | grep -qw "Optimize" && echo "on" || echo "off" ) "Optimize hash tables during linking"
    "Reduce" "-Wl,--as-needed" $( echo ${LDF[@]} | grep -qw "Reduce" && echo "on" || echo "off" ) "Reduce the amount of linked libraries if possible"
    "Combreloc" "-z combreloc" $( echo ${LDF[@]} | grep -qw "Combreloc" && echo "on" || echo "off" ) "Combreloc"
    "Relro" "-Wl,-z,relro" $( echo ${LDF[@]} | grep -qw "Relro" && echo "on" || echo "off" ) "Randomize ELF segments (security)"
    "Now" "-Wl,-z,now" $( echo ${LDF[@]} | grep -qw "Now" && echo "on" || echo "off" ) "Make ELF segments R/O at dl load time (slow, security)"
    "SortCommon" "-Wl,--sort-common" $( echo ${LDF[@]} | grep -qw "SortCommon" && echo "on" || echo "off" ) "Sorts the common symbols by size"
  )
  RESULT=$($DIALOG --item-help --separate-output --checklist "Select linker optimizations. These options only apply to the link stage of binaries." 0 0 0 "${OPTIONS[@]}")
  if [ $? == 0 ]; then
    LDF=($RESULT)
    save_optimizations
  fi
}


plugin_register BUILD_BUILD plugin_gnu_ld_optimize
plugin_register OPTIMIZE_MENU plugin_gnu_ld_optimize_menu
