From c9cfefda12815ad95c580259cc4f9463b02abaa5 Mon Sep 17 00:00:00 2001
From: Christoph Reiter <reiter.christoph@gmail.com>
Date: Mon, 27 Feb 2023 18:28:50 +0100
Subject: [PATCH 09/N] makepkg: port strip/debug to Windows

---
 scripts/libmakepkg/executable/meson.build |   1 -
 scripts/libmakepkg/tidy/strip.sh.in       | 208 +++++++++++++---------
 scripts/makepkg.sh.in                     |   2 +-
 3 files changed, 121 insertions(+), 90 deletions(-)

diff --git a/scripts/libmakepkg/executable/meson.build b/scripts/libmakepkg/executable/meson.build
index f6474eb..535da57 100644
--- a/scripts/libmakepkg/executable/meson.build
+++ b/scripts/libmakepkg/executable/meson.build
@@ -4,7 +4,6 @@ sources = [
   'ccache.sh.in',
   'checksum.sh.in',
   'distcc.sh.in',
-  'debugedit.sh.in',
   'gpg.sh.in',
   'gzip.sh.in',
   'pacman.sh.in',
diff --git a/scripts/libmakepkg/tidy/strip.sh.in b/scripts/libmakepkg/tidy/strip.sh.in
index db35916..8918a0c 100644
--- a/scripts/libmakepkg/tidy/strip.sh.in
+++ b/scripts/libmakepkg/tidy/strip.sh.in
@@ -31,93 +31,55 @@ packaging_options+=('strip' 'debug')
 tidy_modify+=('tidy_strip')
 
 
-build_id() {
-	LANG=C readelf -n "$1" | sed -n '/Build ID/ { s/.*: //p; q; }'
-}
-
-source_files() {
-	# This function does two things:
-	#
-	# 1) rewrites source file locations for packages not respecting prefix-
-	#    map switches.  This ensures all source file references in debug
-	#    info point to $dbgsrcdir.
-	#
-	# 2) outputs a list of files from the package source files to stdout
-	#    while stripping the $dbgsrcdir prefix
-
-	LANG=C debugedit --no-recompute-build-id \
-		--base-dir "${srcdir}" \
-		--dest-dir "${dbgsrcdir}" \
-		--list-file /dev/stdout "$1" \
-		| sort -zu | tr '\0' '\n'
-}
-
-package_source_files() {
-	local binary=$1
-
-	local file dest t
-	while IFS= read -r t; do
-		file="${srcdir}/${t}"
-		dest="${dbgsrc}/${t}"
-		mkdir -p "${dest%/*}"
-		if [[ -f "$file" ]]; then
-			cp -- "$file" "$dest"
-		fi
-	done < <(source_files "$binary")
-}
-
 collect_debug_symbols() {
 	local binary=$1; shift
 
-	if check_option "debug" "y"; then
-		local bid=$(build_id "$binary")
-
-		# has this file already been stripped
-		if [[ -n "$bid" ]]; then
-			if [[ -f "$dbgdir/.build-id/${bid:0:2}/${bid:2}.debug" ]]; then
+	case "$(file -bi "$binary")" in
+	*application/x-dosexec* | *application/vnd.microsoft.portable-executable*)
+		if check_option "debug" "y"; then
+			if [[ -f "$dbgdir/$binary.debug" ]]; then
 				return
 			fi
-		elif [[ -f "$dbgdir/$binary.debug" ]]; then
-			return
-		fi
-
-		# copy source files to debug directory
-		package_source_files "$binary"
 
-		# copy debug symbols to debug directory
-		mkdir -p "$dbgdir/${binary%/*}"
+			# copy debug symbols to debug directory
+			mkdir -p "$dbgdir/${binary%/*}"
+			msg2 "Separating debug info from $binary into $dbgdir/$binary.debug"
+			# create a dbg file with proper debug info:
+			objcopy --only-keep-debug "$binary" "$dbgdir/$binary.debug"
+
+			msg2 "Creating a debuginfo link to $dbgdir/$binary.debug in $binary"
+			local tempfile=$(mktemp "$binary.XXXXXX")
+			objcopy --add-gnu-debuglink="$dbgdir/${binary#/}.debug" "$binary" "$tempfile"
+			cat "$tempfile" > "$binary"
+			rm "$tempfile"
+
+			msg2 "Separating (again) debug info from $binary into $dbgdir/$binary.debug"
+			objcopy --only-keep-debug "$binary" "$dbgdir/$binary.debug"
+
+			msg2 "Removing old .gnu_debuglink section from $binary"
+			objcopy --remove-section=.gnu_debuglink "$binary"
+
+			# strip debug-info from the original file
+			objcopy --strip-debug "$binary"
+			msg2 "Creating (again) a debuginfo link to $dbgdir/$binary.debug in $binary"
+			tempfile=$(mktemp "$binary.XXXXXX")
+			objcopy --add-gnu-debuglink="$dbgdir/${binary#/}.debug" "$binary" "$tempfile"
+			cat "$tempfile" > "$binary"
+			rm "$tempfile"
+			# This way dbg file gets a .gnu_debuglink section (doesn't matter where
+			# it's pointing), and its contents pass the CRC32 check
+
+			# create any needed hardlinks
+			while IFS= read -rd '' file ; do
+				if [[ "${binary}" -ef "${file}" && ! -f "$dbgdir/${file}.debug" ]]; then
+					mkdir -p "$dbgdir/${file%/*}"
+					ln "$dbgdir/${binary}.debug" "$dbgdir/${file}.debug"
+				fi
+			done < <(find . -type f -perm -u+w -print0 2>/dev/null)
 
-		# abandon processing files that are not a recognised format
-		if ! objcopy --only-keep-debug "$binary" "$dbgdir/$binary.debug" 2>/dev/null; then
-			return
 		fi
-
-		local tempfile=$(mktemp "$binary.XXXXXX")
-		objcopy --add-gnu-debuglink="$dbgdir/${binary#/}.debug" "$binary" "$tempfile"
-		cat "$tempfile" > "$binary"
-		rm "$tempfile"
-
-		# create any needed hardlinks
-		while IFS= read -rd '' file ; do
-			if [[ "${binary}" -ef "${file}" && ! -f "$dbgdir/${file}.debug" ]]; then
-				mkdir -p "$dbgdir/${file%/*}"
-				ln "$dbgdir/${binary}.debug" "$dbgdir/${file}.debug"
-			fi
-		done < <(find . -type f -perm -u+w -print0 2>/dev/null)
-
-		if [[ -n "$bid" ]]; then
-			local target
-			mkdir -p "$dbgdir/.build-id/${bid:0:2}"
-
-			target="../../../../../${binary#./}"
-			target="${target/..\/..\/usr\/lib\/}"
-			target="${target/..\/usr\/}"
-			ln -s "$target" "$dbgdir/.build-id/${bid:0:2}/${bid:2}"
-
-			target="../../${binary#./}.debug"
-			ln -s "$target" "$dbgdir/.build-id/${bid:0:2}/${bid:2}.debug"
-		fi
-	fi
+		;;
+	esac
 }
 
 strip_file(){
@@ -148,21 +110,91 @@ tidy_strip() {
 		[[ -z ${STRIP_STATIC+x} ]] && STRIP_STATIC="-S"
 
 		if check_option "debug" "y"; then
-			dbgdir="$pkgdirbase/$pkgbase-@DEBUGSUFFIX@/usr/lib/debug"
+			dbgdir="$pkgdirbase/$pkgbase-@DEBUGSUFFIX@"
 			dbgsrcdir="${DBGSRCDIR:-/usr/src/debug}/${pkgbase}"
 			dbgsrc="$pkgdirbase/$pkgbase-@DEBUGSUFFIX@$dbgsrcdir"
 			mkdir -p "$dbgdir" "$dbgsrc"
 		fi
 
 		local binary strip_flags
-		find . -type f -perm -u+w -print0 2>/dev/null | LC_ALL=C sort -z | while IFS= read -rd '' binary ; do
-			# skip filepaths that cause stripping issues - ideally these should be temporary
-			# guile-2.2
-			[[ "$binary" =~ .*/guile/.*\.go$ ]] && continue
-
-			local STATICLIB=0
-			case "$(LC_ALL=C readelf -h "$binary" 2>/dev/null)" in
-				*Type:*'DYN (Shared object file)'*) # Libraries (.so) or Relocatable binaries
+		# *.so: Apache2 modules, OCaml stublibs, Ruby modules
+		# *.oct: Octave modules
+		# *.cmxs: OCaml natdynlink modules: http://gallium.inria.fr/~frisch/ndl.txt
+		find * -type f ! -name '*.dll.a' ! -name '*.lib' \
+			-a \( -name '*.a' -o -name '*.dll' -o -name '*.exe' -o -name '*.so' -o -name '*.so.*' -o -name '*.oct' -o -name '*.cmxs' \) -print0 \
+			-o -type f -executable ! -name '*.dll' ! -name '*.exe' ! -name '*.so' ! -name '*.so.[0-9]*' ! -name '*.oct' ! -name '*.cmxs' ! -name '*.a' ! -name '*.la' ! -name '*.lib' ! -name '*.exe.manifest' ! -name '*.exe.config' ! -name '*.dll.config' ! -name '*.mdb' ! -name '*-config' ! -name '*.csh' ! -name '*.sh' ! -name '*.pl' ! -name '*.pm' ! -name '*.py' ! -name '*.rb' ! -name '*.tcl' -print0 | \
+		while IFS= read -d $'\0' binary
+		do
+			local STRIPLTO=0
+			# Skip thin archives from stripping
+			case "${binary##*/}" in
+				*.a)
+					if [ "$(head -c 7 "${binary}")" = '!<thin>' ]
+					then
+						continue
+					fi
+				;;
+			esac
+
+			# assure this is actually a binary object
+			if [ "$(head -c 2 "${binary}")" = '#!' ]
+			then
+				# sometimes .exe will be appended where it does not belong
+				case "${exe}" in
+					usr/lib/hevea/*.exe) ;;
+					*.exe)	mv "${binary}" "${binary%.exe}" ;;
+				esac
+				continue
+			fi
+
+			# OCaml bytecode must not be stripped
+			# Magic number is at end of file:
+			# http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=256900#74
+			# http://cygwin.com/ml/cygwin-apps/2010-10/msg00057.html
+			#
+			# Perl Archive (PAR) binaries must not be stripped
+			# https://rt.cpan.org/Public/Bug/Display.html?id=18536
+			# http://cygwin.com/ml/cygwin-apps/2012-07/msg00088.html
+			case $(tail -c 12 "${binary}" | tr '\012\0' '%') in
+				%PAR\.pm%)  continue ;;
+				Caml1999X0[0-9][0-9])  continue ;;
+			esac
+
+			# Mono assemblies must not be stripped, but remove .mdb debug symbols,
+			# and make them non-executable so they're not launched by MS .NET
+			if LC_ALL=C file -b "${binary}" 2>&1 | grep -q "Mono/\.Net assembly"
+			then
+				chmod 0644 "${binary}"
+				rm -f "${binary}.mdb"
+				continue
+			fi
+
+			# check for .exe from non-automake Makefile which install(1) didn't fix
+			# strip(1) used to take care of this, but not anymore
+			case ${CHOST} in
+			*-*-cygwin*|*-*-mingw*|*-*-msys*)
+				case "${binary##*/}" in
+				*.dll|*.exe|*.sfx|*.so|*.so.[0-9]*|*.oct|*.cmxs) ;;
+				# make sure this isn't some oddly named DLL
+				*)	if LANG=en_US.UTF-8 LC_ALL=C objdump -f "${binary}" | grep -Eq '^start address 0x(0000000[01])?00401[0-9a-e][0-9a-e]0'
+					then
+						mv "${binary}" "${binary}.exe"
+						binary+=.exe
+					fi ;;
+				esac
+				;;
+			esac
+			chmod 0755 "${binary}";
+
+			case "$(@FILECMD@ -bi "$binary")" in
+				*application/x-dosexec*) # Windows executables and dlls (file <=5.43)
+					strip_flags="$STRIP_SHARED";;
+				*application/vnd.microsoft.portable-executable*) # Windows executables and dlls (file >=5.44)
+					strip_flags="$STRIP_SHARED";;
+				*application/x-archive*) # Static and Import Libraries (*.a and *.dll.a)
+					strip_flags="$STRIP_STATIC"
+					STRIPLTO=1;;
+				*application/x-sharedlib*)  # Libraries (.so)
 					strip_flags="$STRIP_SHARED";;
 				*Type:*'DYN (Position-Independent Executable file)'*) # Relocatable binaries
 					strip_flags="$STRIP_SHARED";;
diff --git a/scripts/makepkg.sh.in b/scripts/makepkg.sh.in
index aa2d88d..6eefa98 100644
--- a/scripts/makepkg.sh.in
+++ b/scripts/makepkg.sh.in
@@ -627,7 +627,7 @@ create_debug_package() {
 	local pkgdir="$pkgdirbase/$pkgbase-@DEBUGSUFFIX@"
 
 	# check if we have any debug symbols to package
-	if dir_is_empty "$pkgdir/usr/lib/debug"; then
+	if dir_is_empty "$pkgdir"; then
 		return 0
 	fi
 
