diff --git a/Makefile.inc1 b/Makefile.inc1 --- a/Makefile.inc1 +++ b/Makefile.inc1 @@ -603,6 +603,11 @@ SOURCE_DATE_EPOCH= ${PKG_TIMESTAMP} .endif +MTREE_DIST= mtree -c -i -p . +.if ${MK_REPRODUCIBLE_BUILD} == "yes" +MTREE_DIST+= -R time | awk '/^\/set / { $$(NF+1)="time=${SOURCE_DATE_EPOCH}.000000000" }; { print }' +.endif + PKG_NAME_PREFIX?= FreeBSD PKG_MAINTAINER?= re@FreeBSD.org PKG_WWW?= https://www.FreeBSD.org @@ -1569,7 +1574,8 @@ ${XZ_CMD} > ${PACKAGEDIR}/${dist}.txz .else ${_+_}cd ${DESTDIR}/${DISTDIR}/${dist}; \ - ${TAR_CMD} cvf - --exclude usr/lib/debug . | \ + ${MTREE_DIST} > ${WORLDTMP}/package-${dist}.mtree; \ + ${TAR_CMD} cvf - --exclude usr/lib/debug @${WORLDTMP}/package-${dist}.mtree | \ ${XZ_CMD} > ${PACKAGEDIR}/${dist}.txz .endif .endfor @@ -1581,7 +1587,7 @@ ${XZ_CMD} > ${PACKAGEDIR}/${dist}-dbg.txz . else ${_+_}cd ${DESTDIR}/${DISTDIR}/${dist}; \ - ${TAR_CMD} cvLf - usr/lib/debug | \ + ${TAR_CMD} cvLf - --include usr/lib/debug @${WORLDTMP}/package-${dist}.mtree | \ ${XZ_CMD} > ${PACKAGEDIR}/${dist}-dbg.txz . endif .endfor @@ -1974,22 +1980,24 @@ .else .if !defined(NO_INSTALLKERNEL) cd ${DESTDIR}/${DISTDIR}/kernel; \ - ${TAR_CMD} cvf - --exclude '*.debug' . | \ + ${MTREE_DIST} > ${WORLDTMP}/package-kernel.mtree; \ + ${TAR_CMD} cvf - --exclude '*.debug' @${WORLDTMP}/package-kernel.mtree | \ ${XZ_CMD} > ${PACKAGEDIR}/kernel.txz .endif .if ${MK_DEBUG_FILES} != "no" cd ${DESTDIR}/${DISTDIR}/kernel; \ - ${TAR_CMD} cvf - --include '*/*/*.debug' $$(eval find .) | \ + ${TAR_CMD} cvf - --include '*/*/*.debug' @${WORLDTMP}/package-kernel.mtree | \ ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/kernel-dbg.txz .endif .if ${BUILDKERNELS:[#]} > 1 && ${NO_INSTALLEXTRAKERNELS} != "yes" .for _kernel in ${BUILDKERNELS:[2..-1]} cd ${DESTDIR}/${DISTDIR}/kernel.${_kernel}; \ - ${TAR_CMD} cvf - --exclude '*.debug' . | \ + ${MTREE_DIST} > ${WORLDTMP}/package-kernel.${_kernel}.mtree; \ + ${TAR_CMD} cvf - --exclude '*.debug' @${WORLDTMP}/package-kernel.${_kernel}.mtree | \ ${XZ_CMD} > ${PACKAGEDIR}/kernel.${_kernel}.txz .if ${MK_DEBUG_FILES} != "no" cd ${DESTDIR}/${DISTDIR}/kernel.${_kernel}; \ - ${TAR_CMD} cvf - --include '*/*/*.debug' $$(eval find .) | \ + ${TAR_CMD} cvf - --include '*/*/*.debug' @${WORLDTMP}/package-kernel.${_kernel}.mtree | \ ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/kernel.${_kernel}-dbg.txz .endif .endfor diff --git a/release/scripts/reproducible.sh b/release/scripts/reproducible.sh new file mode 100644 --- /dev/null +++ b/release/scripts/reproducible.sh @@ -0,0 +1,35 @@ +#!/bin/sh +# +# sh reproducible.sh /tmp/norepro -DWITHOUT_REPRODUCIBLE_BUILD +# sh reproducible.sh /tmp/repro1 -DWITH_REPRODUCIBLE_BUILD +# sh reproducible.sh /tmp/repro2 -DWITH_REPRODUCIBLE_BUILD +# comm -1 -2 /tmp/repro1 /tmp/norepro +# comm -1 -2 /tmp/repro1 /tmp/repro2 + +set -eu + +RELEASE_ROOT=$(realpath $(dirname $(realpath $0))/..) +TIMESTAMP=1733729386 + +make="env TZ=UTC PKG_TIMESTAMP=${TIMESTAMP} make -s -C ${RELEASE_ROOT} -DNOPORTS -DNOSRC" +objdir=$(${make} -V .OBJDIR) + +main() { + local dest args + parse_args "${@}" + + ${make} clean + ${make} ${args} packagesystem + cp ${objdir}/MANIFEST ${dest} +} + +parse_args() { + dest=${1:?missing arg}; shift + args="${@}" + # check dest dir + local d + d=$(dirname ${dest}) + realpath ${d} > /dev/null +} + +main "${@}" diff --git a/share/man/man7/release.7 b/share/man/man7/release.7 --- a/share/man/man7/release.7 +++ b/share/man/man7/release.7 @@ -283,6 +283,17 @@ .Fa /usr/ports is expected to exist by alternative means. .El +.Sh REPRODUCIBLE BUILDS +Official releases of FreeBSD include TIMESTAMP and REVISION, which can +be used to make bit-identical release tarballs. + +git checkout + +make -DWITH_REPRODUCIBLE_BUILD buildworld buildkernel + +make -DWITH_REPRODUCIBLE_BUILD TZ=UTC PKG_TIMESTAMP= packagesystem + +Note: make packagesystem must be run without -j. .Sh EMBEDDED BUILDS The following .Fa release.conf