# Description: The Rust language for WebAssembly
# URL: https://www.rust-lang.org/
# Maintainer: Tim Biermann, tbier at posteo dot de
# Depends on: lld rust wasi-libc
# Optional: clang ccache libgit2 polly sccache

name=rust-wasm
version=1.87.0
_date=2025-04-03
_rustc=1.86.0
_cargo=$_rustc
release=1

source=(https://static.rust-lang.org/dist/${name/-wasm/}c-$version-src.tar.xz
  https://static.rust-lang.org/dist/$_date/rust-std-$_rustc-x86_64-unknown-linux-gnu.tar.xz
  https://static.rust-lang.org/dist/$_date/rustc-$_rustc-x86_64-unknown-linux-gnu.tar.xz
  https://static.rust-lang.org/dist/$_date/cargo-$_cargo-x86_64-unknown-linux-gnu.tar.xz
  0001-bootstrap-Change-libexec-dir.patch
  0002-bootstrap-Change-bash-completion-dir.patch
  0003-compiler-Change-LLVM-targets.patch
  0004-compiler-Use-wasm-ld-for-wasm-targets.patch
  0006-bootstrap-Use-lld-mode-only-for-host-linked-targets.patch)

unpack_source() { # {{{
  for file in ${source[@]}; do
    case ${file##*/} in
    rustc-${version}-src.tar.xz)
      echo "Unpacking $(get_filename $file)"
      bsdtar -p -o -C ${SRC} -xf $(get_filename $file)
      ;;
    *.tar.xz)
      echo "Copying $(get_filename $file)"
      mkdir -p ${SRC}/${name/-wasm/}c-$version-src/build/cache/${_date} || true
      cp $(get_filename $file) ${SRC}/${name/-wasm/}c-$version-src/build/cache/${_date}
      ;;
    *)
      cp $(get_filename $file) ${SRC}
      ;;
    esac
  done
}                  # }}}
_check_version() { # {{{
  local ERROR
  local DATE="$(awk -F'=' '/^compiler_date=/ {print $2}' $SRC/rustc-$version-src/src/stage0)"
  local RUSTC="$(awk -F'=' '/^compiler_version=/ {print $2}' $SRC/rustc-$version-src/src/stage0)"

  printf '\033[0;32m%s\033[0m\n' "Checking versions for bootstrap compiler.."
  printf '\033[0;32m%s\033[0m\n' "Got _date = $_date && _rustc = $_rustc"

  if [ "$DATE" != "$_date" ]; then
    printf '\e[1;31m%-6s\e[m\n' "Error: _date $_date != $DATE"
    ERROR=1
  fi
  if [ "$RUSTC" != "$_rustc" ]; then
    printf '\e[1;31m%-6s\e[m\n' "Error: _rustc $_rustc != $RUSTC"
    ERROR=1
  fi

  [ $ERROR ] && exit 1
  printf '\033[0;32m%s\033[0m\n' "Versions check out! Proceeding.."
  unset DATE RUSTC ERROR
} # }}}

build() {
  _check_version

  cd "${name/-wasm/}c-$version-src"

  patch -p1 -i $SRC/0001-bootstrap-Change-libexec-dir.patch
  patch -p1 -i $SRC/0002-bootstrap-Change-bash-completion-dir.patch
  patch -p1 -i $SRC/0003-compiler-Change-LLVM-targets.patch
  patch -p1 -i $SRC/0004-compiler-Use-wasm-ld-for-wasm-targets.patch
  patch -p1 -i $SRC/0006-bootstrap-Use-lld-mode-only-for-host-linked-targets.patch

  # bootstrap.toml {{{
  cat <<-EOF >$SRC/bootstrap.toml
  profile = "dist"
  change-id = 138986

  [llvm]
  ninja = true
  link-shared = true
  download-ci-llvm = false
  @POLLY@

  [install]
  prefix = "/usr"

  [rust]
  # LLVM crashes when passing an object through ThinLTO twice.  This is triggered
  # when using rust code in cross-language LTO if libstd was built using ThinLTO.
  # http://blog.llvm.org/2019/09/closing-gap-cross-language-lto-between.html
  # https://github.com/rust-lang/rust/issues/54872
  channel = "stable"
  codegen-units-std = 1
  debuginfo-level = 1
  debuginfo-level-std = 2
  codegen-tests = false
  backtrace-on-ice = true
  remap-debuginfo = true
  jemalloc = true
  debug-assertions = false

  rpath = false
  frame-pointers = true
  deny-warnings = false
  optimize = true
  use-lld = true
  lld = true

  download-rustc = false

  [build]
  build-stage = 1
  dist-stage = 2
  install-stage = 2
  host = ["x86_64-unknown-linux-gnu"]
  target = ["wasm32-unknown-unknown", "wasm32-wasip1", "wasm32-wasip2","wasm32v1-none","wasm32-wasip1-threads"]
  description = "CRUX"
  docs = false
  extended = false
  sanitizers = false
  profiler = true
  python = "/usr/bin/python3"
  @CARGO@
  @RUST@
  @RUSTFMT@

  [target.x86_64-unknown-linux-gnu]
  llvm-config = "/usr/bin/llvm-config"
  llvm-filecheck = "/usr/bin/FileCheck"
  cc = @TARGETCC@
  cxx = @TARGETCXX@
  ar = @TARGETAR@
  ranlib = @TARGETRANLIB@

  [target.i686-unknown-linux-gnu]
  llvm-config = "/usr/bin/llvm-config"
  llvm-filecheck = "/usr/bin/FileCheck"
  cc = @TARGETCC@
  cxx = @TARGETCXX@
  ar = @TARGETAR@
  ranlib = @TARGETRANLIB@

  [target.wasm32-wasi]
  sanitizers = false
  profiler = false
  wasi-root = "/usr/share/wasi-sysroot"
  linker = "/usr/bin/wasm-ld"

  [target.wasm32-unknown-unknown]
  cc = "/usr/bin/clang"
  cxx = "/usr/bin/clang++"
  ar = "/usr/bin/llvm-ar"
  ranlib = "/usr/bin/llvm-ranlib"
  profiler = false
  sanitizers = false
  linker = "/usr/bin/wasm-ld"
  default-linker = "wasm-ld"

  [target.wasm32-wasip1]
  cc = "/usr/bin/clang"
  cxx = "/usr/bin/clang++"
  ar = "/usr/bin/llvm-ar"
  ranlib = "/usr/bin/llvm-ranlib"
  linker = "/usr/bin/wasm-ld"
  default-linker = "wasm-ld"
  sanitizers = false
  profiler = false
  wasi-root = "/usr/share/wasi-sysroot"

  [target.wasm32-wasip2]
  cc = "/usr/bin/clang"
  cxx = "/usr/bin/clang++"
  ar = "/usr/bin/llvm-ar"
  ranlib = "/usr/bin/llvm-ranlib"
  linker = "/usr/bin/wasm-ld"
  default-linker = "wasm-ld"
  sanitizers = false
  profiler = false
  wasi-root = "/usr/share/wasi-sysroot"

  [target.wasm32v1-none]
  cc = "/usr/bin/clang"
  cxx = "/usr/bin/clang++"
  ar = "/usr/bin/llvm-ar"
  ranlib = "/usr/bin/llvm-ranlib"
  linker = "/usr/bin/wasm-ld"
  default-linker = "wasm-ld"
  sanitizers = false
  profiler = false

  [target.wasm32-wasip1-threads]
  cc = "/usr/bin/clang"
  cxx = "/usr/bin/clang++"
  ar = "/usr/bin/llvm-ar"
  ranlib = "/usr/bin/llvm-ranlib"
  linker = "/usr/bin/wasm-ld"
  default-linker = "wasm-ld"
  sanitizers = false
  profiler = false
  wasi-root = "/usr/share/wasi-sysroot"
EOF
  # }}}

  if [ -e '/usr/bin/rustc' ]; then
    if ! /usr/bin/ldd /usr/bin/rustc | grep -q -E '.*libLLVM.*.so => not found' && \
    ! /usr/bin/ldd /usr/bin/cargo | grep -q -E 'libgit2.so.* => not found'; then
      sed -e 's|@CARGO@|cargo = "/usr/bin/cargo"|' \
        -e 's|@RUST@|rustc = "/usr/bin/rustc"|' \
        -e 's|@RUSTFMT@|rustfmt = "/usr/bin/rustfmt"|' \
        -i $SRC/bootstrap.toml
    else
      sed -e 's|@CARGO@||' -e 's|@RUST@||' -e 's|@RUSTFMT@||' -i $SRC/bootstrap.toml
      printf "\e[031mShared library missing, not using system rust to bootstrap.\033[0m\n"
    fi
  else
    sed -e 's|@CARGO@||' -e 's|@RUST@||' -e 's|@RUSTFMT@||' -i $SRC/bootstrap.toml
  fi

  # needed for other target compilers
  if prt-get isinst clang lld; then
    sed -i \
      -e 's|@TARGETCC@|"/usr/bin/clang"|g' \
      -e 's|@TARGETCXX@|"/usr/bin/clang++"|g' \
      -e 's|@TARGETAR@|"/usr/bin/llvm-ar"|g' \
      -e 's|@TARGETRANLIB@|"/usr/bin/llvm-ranlib"|g' \
      $SRC/bootstrap.toml
  else
    sed -i \
      -e 's|@TARGETCC@|"/usr/bin/gcc"|g' \
      -e 's|@TARGETCXX@|"/usr/bin/g++"|g' \
      -e 's|@TARGETAR@|"/usr/bin/gcc-ar"|g' \
      -e 's|@TARGETRANLIB@|"/usr/bin/gcc-ranlib"|g' \
      $SRC/bootstrap.toml
  fi
  prt-get isinst polly && sed -e 's|@POLLY@|polly = true|' -i $SRC/bootstrap.toml || sed -e 's|@POLLY@||' -i $SRC/bootstrap.toml

  cat $SRC/bootstrap.toml

  mkdir "$PKGMK_SOURCE_DIR/rust" || true
  export CARGO_HOME="$PKGMK_SOURCE_DIR/rust"

  if [ -e '/usr/bin/sccache' ]; then
    export RUSTC_WRAPPER='/usr/bin/sccache'
    export SCCACHE_IDLE_TIMEOUT='1500'
  fi

  #error: field is never read: `id`
  #   --> src/bootstrap/lib.rs:280:5
  #   = note: `-D dead-code` implied by `-D warnings`
  export RUSTFLAGS+=' -A dead_code'

  export RUST_BACKTRACE=full
  export PKG_CONFIG_ALLOW_CROSS=1

  { [ ! -e /usr/include/libssh2.h ] ||
    export LIBSSH2_SYS_USE_PKG_CONFIG=1; }

  unset CFLAGS CXXFLAGS

  /usr/bin/python3 ./x.py build --config="${SRC}"/bootstrap.toml -j ${JOBS-1}
  DESTDIR=$PKG /usr/bin/python3 ./x.py --config="${SRC}"/bootstrap.toml install

  # cleanup
  rm -r $PKG/usr/{bin/,lib/librustc_driver-*}
  rm -r $PKG/usr/share/{doc,man}
  rm -r $PKG/usr/lib/rustlib/{components,manifest-rustc,rust-installer-version,uninstall.sh,etc,install.log}
  rm -rf $PKG/usr/lib/rustlib/x86_64-unknown-linux-gnu/bin

  # Remove analysis data for libs that weren't installed
  local file lib
  while read -rd '' file; do
    lib="${file%.json}.rlib"
    lib="${lib/\/analysis\///lib/}"
    if [[ ! -e $lib ]]; then
      echo "missing '$lib'"
      rm -v "$file"
    fi
  done < <(find "$PKG/usr/lib/rustlib" -path '*/analysis/*.json' -print0)

  install -d $PKG/etc/revdep.d
  echo "/usr/lib/rustlib/wasm32-unknown-unknown/lib" >$PKG/etc/revdep.d/$name
  echo "/usr/lib/rustlib/wasm32-wasi/lib" >$PKG/etc/revdep.d/$name

  #rm -rf $PKG/usr/lib/rustlib/x86_64-unknown-linux-gnu/
  find $PKG/usr/lib/rustlib -type f -perm -600 -exec chmod 644 {} \+
  find $PKG/usr/lib/rustlib -type f -perm -700 -exec chmod 755 {} \+
}
