public inbox for cygwin-apps@cygwin.com
 help / color / mirror / Atom feed
From: Christian Franke <Christian.Franke@t-online.de>
To: cygwin-apps@cygwin.com
Subject: Re: [PATCH cygport] Add initial support for SOURCE_DATE_EPOCH
Date: Mon, 28 Aug 2023 17:12:16 +0200	[thread overview]
Message-ID: <000a4c2b-e6eb-4a16-e3c4-c5cedab1867b@t-online.de> (raw)
In-Reply-To: <d9b666aa-82c7-4143-26ca-8bf87c379a78@t-online.de>

[-- Attachment #1: Type: text/plain, Size: 1663 bytes --]

Christian Franke wrote:
> A small step towards reproducible packaging...
>
> Currently only tested with upcoming smartmontools package - contains 
> only exe, man, doc files (no dll, lib, ...). Multiple cygport runs 
> produce binary identical distribution tarballs if SOURCE_DATE_EPOCH 
> (from the past) is specified in the cygport file.
>

A slightly enhanced patch is attached. For .gz files, 'gzip -n' is now 
used as suggested.


Result from a test with the cygwin-3.4.8-1 source package:

These two lines were added to cygwin.cygport:

  VERSION="3.4.8"
  RELEASE="1"
+export SOURCE_DATE_EPOCH=$(date -d '2023-08-18 UTC' +%s)
+export TZ=UTC

(TZ=UTC is a workaround for a minor bug in SOURCE_DATE_EPOCH handling of 
gropdf)

These distribution files are always identical:
- cygwin-3.4.8-1-src.tar.xz
- cygwin-doc-3.4.8-1.tar.xz

These individual files differ if the build-path of multiple test-builds 
is always the same:

- usr/bin/cygwin1.dll:
-- Contains a build timestamp not based on '__DATE__ __TIME__'. Could be 
easily addressed in scripts/mkvers.sh.
-- The PE Export Tables header contains a timestamp independent from the 
PE header. There is possibly no easy way to fix this without an extra 
tool (or further enhancing peflags).

- usr/lib/lib*.a:
-- Object file time timestamps differ. Could be addressed by adding 'ar' 
option 'D' (deterministic) in Makefiles and scripts/speclib.

- usr/lib/debug/usr/bin/cygwin1.dll.dbg: As expected, because 
cygwin1.dll differ.

If the build-path changes, more files differ (cygcheck.exe, ldd.exe, 
cygserver.exe) because __FILE__ is used and expands to an absolute path 
name.

-- 
Regards,
Christian


[-- Attachment #2: 0001-Add-initial-support-for-SOURCE_DATE_EPOCH.patch --]
[-- Type: text/plain, Size: 5370 bytes --]

From 73dde4d2dabb74b7b9ee40655204f84e1d4086d6 Mon Sep 17 00:00:00 2001
From: Christian Franke <christian.franke@t-online.de>
Date: Mon, 28 Aug 2023 16:24:36 +0200
Subject: [PATCH] Add initial support for SOURCE_DATE_EPOCH

If specified, set the header timestamps of executables and
patch files to SOURCE_DATE_EPOCH.
Suppress the header timestamp of .gz files.
Instruct tar to avoid more recent modification times and
to sort all entries by name.
---
 bin/cygport.in           | 17 +++++++++++++++--
 lib/pkg_pkg.cygpart      | 20 ++++++++++++++++++--
 lib/src_postinst.cygpart | 22 +++++++++++++++++++---
 3 files changed, 52 insertions(+), 7 deletions(-)

diff --git a/bin/cygport.in b/bin/cygport.in
index 3f89ac67..e2fe1785 100755
--- a/bin/cygport.in
+++ b/bin/cygport.in
@@ -231,8 +231,9 @@ source ${_privlibdir}/check_funcs.cygpart
 ###
 
 # check now for all mandatory programs
-for _myprog in bzip2 cat chmod cp diff diffstat dos2unix file find gawk grep gzip \
-               install ln mkdir mv patch rm rsync sed sort tar xargs which xz
+for _myprog in bzip2 cat chmod cp date diff diffstat dos2unix file find gawk grep \
+               gzip install ln mkdir mv patch rm rsync sed sort tar touch which \
+               xargs xz
 do
 	if ! check_prog ${_myprog}
 	then
@@ -490,6 +491,18 @@ do
 done
 unset restrict
 
+if [ "${SOURCE_DATE_EPOCH+y}" = "y" ]
+then
+	if [ -n "$(echo "${SOURCE_DATE_EPOCH}" | sed -e 's/^$/X/' -e 's/[0-9]//g')" ]
+	then
+		error "Malformed SOURCE_DATE_EPOCH: '${SOURCE_DATE_EPOCH}'"
+	fi
+	case $(peflags --version 2>/dev/null | sed -n '1s/^.* //p') in
+		4.6.[6-9]|4.[7-9]*|[5-9]*) ;;
+		*) error "SOURCE_DATE_EPOCH requires peflags 4.6.6 or later"
+	esac
+fi
+
 
 ################################################################################
 #
diff --git a/lib/pkg_pkg.cygpart b/lib/pkg_pkg.cygpart
index 2a2bb663..4e6a7cd2 100644
--- a/lib/pkg_pkg.cygpart
+++ b/lib/pkg_pkg.cygpart
@@ -42,7 +42,7 @@ TAR_COMPRESSION_EXT="${TAR_COMPRESSION_EXT:-xz}"
 #****
 
 __tar() {
-	local TAR_COMPRESSION_OPT;
+	local TAR_COMPRESSION_OPT TAR_SOURCE_DATE_OPTS;
 
 	# We could use --auto-compress, but this also constrains the extension
 	# to the currently valid set. We could probe if tar supports the
@@ -65,7 +65,14 @@ __tar() {
 			error "tar option for TAR_COMPRESSION_EXT='${TAR_COMPRESSION_EXT}' unknown"
 			;;
 	esac
-	tar ${TAR_COMPRESSION_OPT} --owner=Guest:501 --group=None:513 -cvf "$@"
+
+	if [ -n "${SOURCE_DATE_EPOCH}" ]
+	then
+		# Ensure reproducible sort order and last modification times <= SOURCE_DATE_EPOCH
+		TAR_SOURCE_DATE_OPTS="--sort=name --mtime=@${SOURCE_DATE_EPOCH} --clamp-mtime"
+	fi
+
+	tar ${TAR_COMPRESSION_OPT} ${TAR_SOURCE_DATE_OPTS} --owner=Guest:501 --group=None:513 -cvf "$@"
 }
 
 __pkg_binpkg() {
@@ -319,6 +326,7 @@ __pkg_diff() {
 	local difflevel;
 	local exclude;
 	local optional_patchfiles;
+	local source_date;
 
 	default_excludes="CYGWIN-PATCHES aclocal.m4~ aclocal.m4t autom4te.cache
 		config.cache config.guess config.log config.status config.sub
@@ -498,6 +506,14 @@ __pkg_diff() {
 
 	sed -b -e '/^diff -u/d' -i ${optional_patchfiles} ${patchdir}/${src_patchfile};
 
+	if [ -n "${SOURCE_DATE_EPOCH}" ]
+	then
+		# Ensure that the timestamp comment of the new file is reproducible
+		source_date=$(date -d @"${SOURCE_DATE_EPOCH}" -u +'%Y-%m-%d %H:%M:%S.000000000 +0000')
+		sed -b -e  "s|^\(+++ [^\t]*\t\).*\$|\1${source_date}|" \
+			-i ${optional_patchfiles} ${patchdir}/${src_patchfile}
+	fi
+
 	diffstat -p${difflevel} ${optional_patchfiles} ${patchdir}/${src_patchfile};
 }
 
diff --git a/lib/src_postinst.cygpart b/lib/src_postinst.cygpart
index dd947311..53eaa71a 100644
--- a/lib/src_postinst.cygpart
+++ b/lib/src_postinst.cygpart
@@ -41,7 +41,7 @@ __prep_fonts_dir() {
 	for catalogue in ${D}${cataloguedir}/*
 	do
 		fontdir=$(readlink -f ${catalogue})
-		find ${D}${fontdir} -name '*.pcf' -exec gzip -q '{}' +
+		find ${D}${fontdir} -name '*.pcf' -exec gzip -q ${SOURCE_DATE_EPOCH:+-n} '{}' +
 		mkfontscale ${D}${fontdir}
 		mkfontdir ${D}${fontdir}
 	done
@@ -775,7 +775,7 @@ __prepman() {
 		while read -d $'\0' manpage
 		do
 			echo "        ${manpage##*/}";
-			gzip -q "${manpage}";
+			gzip -q ${SOURCE_DATE_EPOCH:+-n} "${manpage}";
 		done
 	fi
 }
@@ -819,7 +819,7 @@ __prepinfo() {
 		while read -d $'\0' infopage
 		do
 			echo "        ${infopage##*/}";
-			gzip -q "${infopage}";
+			gzip -q ${SOURCE_DATE_EPOCH:+-n} "${infopage}";
 		done
 	fi
 }
@@ -989,6 +989,12 @@ __prepstrip_one() {
 
 	objdump=${objcopy/copy/dump}
 
+	if [ -n "${SOURCE_DATE_EPOCH}" ]
+	then
+		# Let objcopy preserve the timestamps
+		objcopy+=" --enable-deterministic-archives --preserve-dates"
+	fi
+
 	# Static libraries should not be fully stripped, but we can
 	# still provide split debuginfo if desired
 	case "${exe}" in
@@ -1074,6 +1080,16 @@ __prepstrip_one() {
 	# keep sticky bit if present
 	chmod u+w,a+x "${exe}";
 
+	if [ -n "${SOURCE_DATE_EPOCH}" ]
+	then
+		case "${exe}" in
+		*.exe|*.dll|*.so|*.so.*|*.oct|*.mex|*.cmxs)
+			# Ensure PE header timestamp is reproducible and checksum is correct
+			# objcopy later inherits the timestamp to debug info and stripped file
+			peflags --checksum=1 --timestamp=${SOURCE_DATE_EPOCH} ${exe} >/dev/null ;;
+		esac
+	fi
+
 	if defined _CYGPORT_RESTRICT_debuginfo_
 	then
 		${objcopy} --strip-all "${exe}";
-- 
2.39.0


  parent reply	other threads:[~2023-08-28 15:12 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-08-23 17:39 Christian Franke
2023-08-24  2:45 ` Brian Inglis
2023-08-24  6:09   ` Christian Franke
2023-08-24  6:27     ` ASSI
2023-08-24  6:36       ` Christian Franke
2023-08-28 15:12 ` Christian Franke [this message]
2023-08-28 15:51   ` ASSI
2023-08-29  8:52     ` Christian Franke
2023-10-29 16:05   ` Jon Turney
2023-10-30 17:43     ` Christian Franke

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=000a4c2b-e6eb-4a16-e3c4-c5cedab1867b@t-online.de \
    --to=christian.franke@t-online.de \
    --cc=cygwin-apps@cygwin.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).