#!/bin/sh
set -eu

src=$(pwd)
work=$(mktemp -d)
trap 'rm -rf "$work"' EXIT HUP INT TERM

# Use upstream examples and sample data to exercise the installed libraries.
cp examples/tagwriter.cpp examples/tagreader_c.c "$work/"
cd "$work"

static_flags()
{
    pkg-config --static --libs "$1" |
        sed -e 's/-ltag_c\b/-l:libtag_c.a/g' -e 's/-ltag\b/-l:libtag.a/g'
}

check_programs()
{
    kind=$1
    writer=$2
    reader=$3
    for program in "$writer" "$reader"; do
        readelf -d "$program" > "$program.dynamic"
        if [ "$kind" = static ]; then
            if grep -Eq 'Shared library: \[libtag(_c)?\.so' "$program.dynamic"; then
                echo "Unexpected TagLib shared dependency in $program" >&2
                exit 1
            fi
        else
            grep -Eq 'Shared library: \[libtag(_c)?\.so' "$program.dynamic"
        fi
    done
    cp "$src/tests/data/xing.mp3" sample.mp3
    "$writer" -t 'Debian static linking test' sample.mp3
    "$reader" sample.mp3 > tags.txt
    grep -F 'title   - "Debian static linking test"' tags.txt
}

for mode in static-pie static-nopie shared; do
    case "$mode" in
        static-pie) flags='-fPIE -pie'; link=static ;;
        static-nopie) flags='-fno-pie -no-pie'; link=static ;;
        shared) flags=''; link=shared ;;
    esac
    if [ "$link" = static ]; then
        cpp_libs=$(static_flags taglib)
        c_libs=$(static_flags taglib_c)
    else
        cpp_libs=$(pkg-config --libs taglib)
        c_libs=$(pkg-config --libs taglib_c)
    fi
    # -fno-lto also checks the native code in the installed archives.
    # Word splitting of compiler and pkg-config flags is intentional.
    c++ -std=c++17 -fno-lto $flags $(pkg-config --cflags taglib) \
        tagwriter.cpp $cpp_libs -o "writer-$mode"
    cc -fno-lto $flags $(pkg-config --cflags taglib_c) \
        tagreader_c.c $c_libs -o "reader-$mode"
    check_programs "$link" "./writer-$mode" "./reader-$mode"
    case "$mode" in
        static-pie) elf_type=DYN ;;
        static-nopie) elf_type=EXEC ;;
        shared) elf_type='' ;;
    esac
    if [ -n "$elf_type" ]; then
        for program in "writer-$mode" "reader-$mode"; do
            readelf -h "$program" | grep -E "Type: +$elf_type"
        done
    fi
    echo "PASS: $mode (C++ write, C read, ELF dependencies)"
done

cat > CMakeLists.txt <<'EOF'
cmake_minimum_required(VERSION 3.14)
project(taglib_consumer LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 17)
find_package(TagLib REQUIRED CONFIG)
foreach(target TagLib::tag TagLib::tag_c)
    get_target_property(kind ${target} TYPE)
    if(NOT kind STREQUAL "SHARED_LIBRARY")
        message(FATAL_ERROR "${target} no longer selects the shared library")
    endif()
endforeach()
add_executable(writer tagwriter.cpp)
target_link_libraries(writer PRIVATE TagLib::tag)
add_executable(reader tagreader_c.c)
target_link_libraries(reader PRIVATE TagLib::tag_c)
EOF
cmake -S . -B cmake-build
cmake --build cmake-build
check_programs shared ./cmake-build/writer ./cmake-build/reader
echo 'PASS: shared CMake targets (C++ write, C read, ELF dependencies)'
