#!/bin/sh
set -eux
: ${CLANG=21}
: ${MSAN_LIBDIR=..}
: ${PARALLEL=$(nproc)}

export CC=clang-$CLANG CXX=clang++-$CLANG

if [ ! -f /etc/apt/sources.list.d/llvm-toolchain.list ]; then
    # Put the correct deb URL from https://apt.llvm.org/
    echo "deb http://apt.llvm.org/unstable/ llvm-toolchain-$CLANG main
deb-src http://apt.llvm.org/unstable/ llvm-toolchain-$CLANG main" | \
        sudo tee -a /etc/apt/sources.list.d/llvm-toolchain.list
    wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|
    sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc
    sudo apt update
fi

sudo apt -o APT::Get::Assume-Yes=true install \
    clang-$CLANG libc++-$CLANG-dev libc++abi-$CLANG-dev \
    libclang-$CLANG-dev libllvmlibc-$CLANG-dev automake \
    pkg-config gperf gengetopt libtool autopoint
apt -o APT::Get::Assume-Yes=true source \
    llvm-toolchain-$CLANG libgnutls28-dev libnettle8t64 libidn2 libgmp10

mkdir -p ll-build
cd ll-build
cmake ../llvm-toolchain-$CLANG-$CLANG.*/runtimes -DCMAKE_BUILD_TYPE=Release \
      -DLLVM_ENABLE_RUNTIMES="libc;libcxx;libcxxabi;libunwind" \
      -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_DOCS=OFF \
      -DLLVM_ENABLE_SPHINX=OFF \
      -DCMAKE_C_COMPILER=clang-$CLANG \
      -DCMAKE_CXX_COMPILER=clang++-$CLANG \
      -DLLVM_USE_SANITIZER=MemoryWithOrigins
# build the libraries
cmake --build . -- cxx cxxabi -j$PARALLEL
cd ..

export CFLAGS="-fno-omit-frame-pointer -O2 -g -fsanitize=memory"
export CXXFLAGS="$CFLAGS"
export LDFLAGS=-fsanitize=memory

cd gnutls28-*/
aclocal
automake --add-missing
test -f config.h ||
./configure --with-included-libtasn1 --with-included-unistring \
	    --without-p11-kit --disable-hardware-acceleration --disable-doc
make -j$PARALLEL
cd ..

cd nettle-*/
test -f config.h ||
./configure --disable-assembler
make -j$PARALLEL
cd ..

cd libidn2-*/
# libidn2-2.3.8 no longer ships ./configure.
# The ./bootstrap will do a very slow git pull of gnulib.
test -f configure || ./bootstrap
test -f config.h ||
./configure --enable-valgrind-tests=no --enable-doc=no
make -j$PARALLEL
cd ..

cd gmp-*/
# The Debian packaging removes the documentation but not consistently
sed -e '/^.*"doc\/Makefile".*/d;s/doc\/Makefile //;' -i.bak configure
sed -e 's/^\(SUBDIRS = .*\) doc$/\1/;' -i.bak Makefile.in
test -f config.h ||
./configure --disable-assembly
make -j$PARALLEL
cd ..

copy_libs()
{
    cp -a "$@" ll-build/lib/libc++*.so* \
        gnutls28-*/lib/.libs/libgnutls.so* \
        nettle-*/.lib/lib*.so.* \
        gmp-*/.libs/libgmp.so* \
        libidn2-*/lib/.libs/libidn2.so* \
        "$MSAN_LIBDIR"
    # starting with clang-15 this is a text file, not a symlink
    ln -sf libc++.so.1 "$MSAN_LIBDIR"/libc++.so

    cp -aL nettle-*/.lib/lib*.so "$MSAN_LIBDIR"
}

rm -f "$MSAN_LIBDIR"/*.so*
# If some links are broken, use copy_libs -L
copy_libs

cp -a ll-build/include/c++/v1 "$MSAN_LIBDIR/include"

set +x
msan_libs=`readlink -f "$MSAN_LIBDIR"`
echo "Use the following clang++ options:"
echo "-std=c++11 -stdlib=libc++ -lc++abi \\"
echo "-O2 -Wno-unused-command-line-argument \\"
echo "-L${msan_libs} \\"
echo "-I${msan_libs}/include \\"
echo "-Wl,-rpath,${msan_libs}"
echo "Note: -O2 is required (-O0 segfaults)!"
