diff mbox

[U-Boot,v2] Reproducible U-Boot build support, using SOURCE_DATE_EPOCH

Message ID 1437929295-9642-1-git-send-email-contact@paulk.fr
State Accepted
Delegated to: Tom Rini
Headers show

Commit Message

Paul Kocialkowski July 26, 2015, 4:48 p.m. UTC
In order to achieve reproducible builds in U-Boot, timestamps that are defined
at build-time have to be somewhat eliminated. The SOURCE_DATE_EPOCH environment
variable allows setting a fixed value for those timestamps.

Simply by setting SOURCE_DATE_EPOCH to a fixed value, a number of targets can be
built reproducibly. This is the case for e.g. sunxi devices.

However, some other devices might need some more tweaks, especially regarding
the image generation tools.

Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
---
 Makefile              |  7 ++++---
 README                | 12 ++++++++++++
 tools/default_image.c | 21 ++++++++++++++++++++-
 3 files changed, 36 insertions(+), 4 deletions(-)

Comments

Tom Rini July 28, 2015, 3 p.m. UTC | #1
On Sun, Jul 26, 2015 at 06:48:15PM +0200, Paul Kocialkowski wrote:

> In order to achieve reproducible builds in U-Boot, timestamps that are defined
> at build-time have to be somewhat eliminated. The SOURCE_DATE_EPOCH environment
> variable allows setting a fixed value for those timestamps.
> 
> Simply by setting SOURCE_DATE_EPOCH to a fixed value, a number of targets can be
> built reproducibly. This is the case for e.g. sunxi devices.
> 
> However, some other devices might need some more tweaks, especially regarding
> the image generation tools.
> 
> Signed-off-by: Paul Kocialkowski <contact@paulk.fr>

Applied to u-boot/master, thanks!
Bin Meng July 31, 2015, 2:54 a.m. UTC | #2
Hi,

On Tue, Jul 28, 2015 at 11:00 PM, Tom Rini <trini@konsulko.com> wrote:
> On Sun, Jul 26, 2015 at 06:48:15PM +0200, Paul Kocialkowski wrote:
>
>> In order to achieve reproducible builds in U-Boot, timestamps that are defined
>> at build-time have to be somewhat eliminated. The SOURCE_DATE_EPOCH environment
>> variable allows setting a fixed value for those timestamps.
>>
>> Simply by setting SOURCE_DATE_EPOCH to a fixed value, a number of targets can be
>> built reproducibly. This is the case for e.g. sunxi devices.
>>
>> However, some other devices might need some more tweaks, especially regarding
>> the image generation tools.
>>
>> Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
>
> Applied to u-boot/master, thanks!
>
> --

This commit breaks the following commit:

commit f3f431a712729a1af94d01bd1bfde17a252ff02c
Author: Chris Packham <judge.packham@gmail.com>
Date:   Sun May 10 21:02:09 2015 +1200

    Makefile: Add U_BOOT_TZ and include in version

    Define U_BOOT_TZ alongside U_BOOT_TIME and U_BOOT_DATE and use it to
    include the timezone in the version output.

    Acked-by: Simon Glass <sjg@chromium.org>
    Signed-off-by: Chris Packham <judge.packham@gmail.com>

Before this commit I have:
U-Boot 2015.07-00345-g9c57487 (Jul 31 2015 - 10:49:31 +0800)

After this commit I have:
U-Boot 2015.07-00346-gf3f431a (Jul 31 2015 - 02:50:54 +0000)

As you see: the timezone information is missing, and U-Boot's
timestamp is now GMT+0 (the correct one should be GMT+8)

Is this intended behavior? Or if not, please fix it.

Regards,
Bin
Chris Packham July 31, 2015, 5:25 a.m. UTC | #3
On Fri, Jul 31, 2015 at 2:54 PM, Bin Meng <bmeng.cn@gmail.com> wrote:
> Hi,
>
> On Tue, Jul 28, 2015 at 11:00 PM, Tom Rini <trini@konsulko.com> wrote:
>> On Sun, Jul 26, 2015 at 06:48:15PM +0200, Paul Kocialkowski wrote:
>>
>>> In order to achieve reproducible builds in U-Boot, timestamps that are defined
>>> at build-time have to be somewhat eliminated. The SOURCE_DATE_EPOCH environment
>>> variable allows setting a fixed value for those timestamps.
>>>
>>> Simply by setting SOURCE_DATE_EPOCH to a fixed value, a number of targets can be
>>> built reproducibly. This is the case for e.g. sunxi devices.
>>>
>>> However, some other devices might need some more tweaks, especially regarding
>>> the image generation tools.
>>>
>>> Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
>>
>> Applied to u-boot/master, thanks!
>>
>> --
>
> This commit breaks the following commit:
>
> commit f3f431a712729a1af94d01bd1bfde17a252ff02c
> Author: Chris Packham <judge.packham@gmail.com>
> Date:   Sun May 10 21:02:09 2015 +1200
>
>     Makefile: Add U_BOOT_TZ and include in version
>
>     Define U_BOOT_TZ alongside U_BOOT_TIME and U_BOOT_DATE and use it to
>     include the timezone in the version output.
>
>     Acked-by: Simon Glass <sjg@chromium.org>
>     Signed-off-by: Chris Packham <judge.packham@gmail.com>
>
> Before this commit I have:
> U-Boot 2015.07-00345-g9c57487 (Jul 31 2015 - 10:49:31 +0800)
>
> After this commit I have:
> U-Boot 2015.07-00346-gf3f431a (Jul 31 2015 - 02:50:54 +0000)
>
> As you see: the timezone information is missing, and U-Boot's
> timestamp is now GMT+0 (the correct one should be GMT+8)
>
> Is this intended behavior? Or if not, please fix it.
>
> Regards,
> Bin

The problem is that date -u implies UTC. So +0000 is right if you do
want the time to be displayed in UTC (for me living at +12/+13 UTC
makes my head hurt because all the dates are yesterday).

The intent of f3f431a7 was to reflect the timezone that the build
machine was set to. Dropping the -u would probably be sufficient but
perhaps it would be better to make whole lot conditional on
SOURCE_DATE_EPOCH being set. Something like this (untested, apologies
gmail web interface)

ifneq ($(SOURCE_DATE_EPOCH),)
define filechk_timestamp.h
       (SOURCE_DATE="$(SOURCE_DATE_EPOCH)"; \
       LC_ALL=C date -u -d "$${SOURCE_DATE}" +'#define U_BOOT_DATE "%b
%d %C%y"'; \
       LC_ALL=C date -u -d "$${SOURCE_DATE}" +'#define U_BOOT_TIME "%T"'; \
       LC_ALL=C date -u -d "$${SOURCE_DATE}" +'#define U_BOOT_TZ "%z"' )
endef
else
define filechk_timestamp.h
       (LC_ALL=C date +'#define U_BOOT_DATE "%b %d %C%y"'; \
       LC_ALL=C date +'#define U_BOOT_TIME "%T"'; \
       LC_ALL=C date +'#define U_BOOT_TZ "%z"')
endef
endif
Ximin Luo July 31, 2015, 10:19 a.m. UTC | #4
On 31/07/15 07:25, Chris Packham wrote:
> The problem is that date -u implies UTC. So +0000 is right if you do
> want the time to be displayed in UTC (for me living at +12/+13 UTC
> makes my head hurt because all the dates are yesterday).
> 

One of the main problems with human-readable date/time is that it implies a calendar, with all its exceptions like leap years, changing DST, etc. Many RFCs, and the POSIX date functions, are highly flawed and conflate calendars with absolute time, e.g. don't specify they mean the Gregorian calendar, and don't specify what to do with dates before when the Gregorian calendar was introduced.

If you want to be precise about these things (so as to not cause problems in the future), then you need to specify all of that when dealing with human-readable dates. This is why for now, the Reproducible Builds timestamps proposal only defines SOURCE_DATE_EPOCH. We might extend it later, though.

> The intent of f3f431a7 was to reflect the timezone that the build
> machine was set to. Dropping the -u would probably be sufficient but
> perhaps it would be better to make whole lot conditional on
> SOURCE_DATE_EPOCH being set. Something like this (untested, apologies
> gmail web interface)
> 
> ifneq ($(SOURCE_DATE_EPOCH),)
> define filechk_timestamp.h
>        (SOURCE_DATE="$(SOURCE_DATE_EPOCH)"; \
>        LC_ALL=C date -u -d "$${SOURCE_DATE}" +'#define U_BOOT_DATE "%b
> %d %C%y"'; \
>        LC_ALL=C date -u -d "$${SOURCE_DATE}" +'#define U_BOOT_TIME "%T"'; \
>        LC_ALL=C date -u -d "$${SOURCE_DATE}" +'#define U_BOOT_TZ "%z"' )
> endef
> else
> define filechk_timestamp.h
>        (LC_ALL=C date +'#define U_BOOT_DATE "%b %d %C%y"'; \
>        LC_ALL=C date +'#define U_BOOT_TIME "%T"'; \
>        LC_ALL=C date +'#define U_BOOT_TZ "%z"')
> endef
> endif
> 

Yes, it is best to force the TZ as UTC for now, if SOURCE_DATE_EPOCH is set.

At some point later, we might add SOURCE_DATE_TZOFFSET, or other formats that include a timezone offset, or something. (That would match Git's internal timestamp format, which is "$epochts $tzoffset", and can be translated unambiguously into ISO8601 and RFC2822 formats). For now though, we decided to keep things simple. But please say so, if you think that is something you (or others who use timestamps in build systems) would really want.

BTW, you need to do "@$${SOURCE_DATE_EPOCH}" when giving timestamps to date(1):

$ date -d @1438330000 +%s
1438330000
$ date -d 1438330000 +%s
date: invalid date ‘1438330000’
1

X
Andreas Bießmann Aug. 25, 2015, 8:49 a.m. UTC | #5
On 07/28/2015 05:00 PM, Tom Rini wrote:
> On Sun, Jul 26, 2015 at 06:48:15PM +0200, Paul Kocialkowski wrote:
> 
>> In order to achieve reproducible builds in U-Boot, timestamps that are defined
>> at build-time have to be somewhat eliminated. The SOURCE_DATE_EPOCH environment
>> variable allows setting a fixed value for those timestamps.
>>
>> Simply by setting SOURCE_DATE_EPOCH to a fixed value, a number of targets can be
>> built reproducibly. This is the case for e.g. sunxi devices.
>>
>> However, some other devices might need some more tweaks, especially regarding
>> the image generation tools.
>>
>> Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
> 
> Applied to u-boot/master, thanks!

This commit breaks build on non GNU hosts (like OS X and persumably
other *BSD hosts). Before, those hosts where supported, so for me this
has to be fixed for 2015.10

We need a) some mechanism to search for the GNU date variant or b) some
wrapper to provide the correct output on those host machines.

I vote for a), it is acceptable to have the GNU date available but we
should error on 'no GNU date available'. Furthermore we need to have the
date command exchangeable by e.g. gdate, gnudate, ... maybe with full path.

Andreas
Vagrant Cascadian Aug. 25, 2015, 9:55 a.m. UTC | #6
On 2015-08-25, Andreas Bießmann wrote:
> On 07/28/2015 05:00 PM, Tom Rini wrote:
>> On Sun, Jul 26, 2015 at 06:48:15PM +0200, Paul Kocialkowski wrote:
>>> In order to achieve reproducible builds in U-Boot, timestamps that are defined
>>> at build-time have to be somewhat eliminated. The SOURCE_DATE_EPOCH environment
>>> variable allows setting a fixed value for those timestamps.
>>>
>>> Simply by setting SOURCE_DATE_EPOCH to a fixed value, a number of targets can be
>>> built reproducibly. This is the case for e.g. sunxi devices.
>>>
>>> However, some other devices might need some more tweaks, especially regarding
>>> the image generation tools.
>>>
>>> Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
>> 
>> Applied to u-boot/master, thanks!
>
> This commit breaks build on non GNU hosts (like OS X and persumably
> other *BSD hosts). Before, those hosts where supported, so for me this
> has to be fixed for 2015.10
>
> We need a) some mechanism to search for the GNU date variant or b) some
> wrapper to provide the correct output on those host machines.
>
> I vote for a), it is acceptable to have the GNU date available but we
> should error on 'no GNU date available'. Furthermore we need to have the
> date command exchangeable by e.g. gdate, gnudate, ... maybe with full path.

There was a proposed patch which only uses the GNU date extensions if
SOURCE_DATE_EPOCH environment variable is set, would this sufficiently
address your concerns, at least for the short term?

  Message-Id: <1438337042-30762-1-git-send-email-judge.packham@gmail.com>
  http://lists.denx.de/pipermail/u-boot/2015-August/221429.html


live well,
  vagrant
Fabio Estevam Aug. 25, 2015, 10:08 a.m. UTC | #7
On Thu, Jul 30, 2015 at 11:54 PM, Bin Meng <bmeng.cn@gmail.com> wrote:

> This commit breaks the following commit:
>
> commit f3f431a712729a1af94d01bd1bfde17a252ff02c
> Author: Chris Packham <judge.packham@gmail.com>
> Date:   Sun May 10 21:02:09 2015 +1200
>
>     Makefile: Add U_BOOT_TZ and include in version
>
>     Define U_BOOT_TZ alongside U_BOOT_TIME and U_BOOT_DATE and use it to
>     include the timezone in the version output.
>
>     Acked-by: Simon Glass <sjg@chromium.org>
>     Signed-off-by: Chris Packham <judge.packham@gmail.com>
>
> Before this commit I have:
> U-Boot 2015.07-00345-g9c57487 (Jul 31 2015 - 10:49:31 +0800)
>
> After this commit I have:
> U-Boot 2015.07-00346-gf3f431a (Jul 31 2015 - 02:50:54 +0000)
>
> As you see: the timezone information is missing, and U-Boot's
> timestamp is now GMT+0 (the correct one should be GMT+8)
>
> Is this intended behavior? Or if not, please fix it.

I notice the same behavior here and I agree it would be nice to fix this.

Thanks
Andreas Bießmann Aug. 25, 2015, 10:20 a.m. UTC | #8
On 08/25/2015 11:55 AM, Vagrant Cascadian wrote:
> On 2015-08-25, Andreas Bießmann wrote:
>> On 07/28/2015 05:00 PM, Tom Rini wrote:
>>> On Sun, Jul 26, 2015 at 06:48:15PM +0200, Paul Kocialkowski wrote:
>>>> In order to achieve reproducible builds in U-Boot, timestamps that are defined
>>>> at build-time have to be somewhat eliminated. The SOURCE_DATE_EPOCH environment
>>>> variable allows setting a fixed value for those timestamps.
>>>>
>>>> Simply by setting SOURCE_DATE_EPOCH to a fixed value, a number of targets can be
>>>> built reproducibly. This is the case for e.g. sunxi devices.
>>>>
>>>> However, some other devices might need some more tweaks, especially regarding
>>>> the image generation tools.
>>>>
>>>> Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
>>>
>>> Applied to u-boot/master, thanks!
>>
>> This commit breaks build on non GNU hosts (like OS X and persumably
>> other *BSD hosts). Before, those hosts where supported, so for me this
>> has to be fixed for 2015.10
>>
>> We need a) some mechanism to search for the GNU date variant or b) some
>> wrapper to provide the correct output on those host machines.
>>
>> I vote for a), it is acceptable to have the GNU date available but we
>> should error on 'no GNU date available'. Furthermore we need to have the
>> date command exchangeable by e.g. gdate, gnudate, ... maybe with full path.
> 
> There was a proposed patch which only uses the GNU date extensions if
> SOURCE_DATE_EPOCH environment variable is set, would this sufficiently
> address your concerns, at least for the short term?
> 
>   Message-Id: <1438337042-30762-1-git-send-email-judge.packham@gmail.com>
>   http://lists.denx.de/pipermail/u-boot/2015-August/221429.html

thanks for the pointer, normal builds work with that change.

Andreas
Holger Levsen Aug. 25, 2015, 11:20 a.m. UTC | #9
Hi,

(just stating the (IMHO) obvious here…)

On Dienstag, 25. August 2015, Vagrant Cascadian wrote:
> There was a proposed patch which only uses the GNU date extensions if
> SOURCE_DATE_EPOCH environment variable is set, would this sufficiently
> address your concerns, at least for the short term?

there also should be a solution which works on BSD in the not so long term if 
we want the SOURCE_DATE_EPOCH specification to take off..!

(and this probably also affects other software where we want to (or did) 
introduce SOURCE_DATE_EPOCH!)


cheers,
	Holger
Paul Kocialkowski Aug. 25, 2015, 12:12 p.m. UTC | #10
Le mardi 25 août 2015 à 12:20 +0200, Andreas Bießmann a écrit :
> On 08/25/2015 11:55 AM, Vagrant Cascadian wrote:
> > On 2015-08-25, Andreas Bießmann wrote:
> >> On 07/28/2015 05:00 PM, Tom Rini wrote:
> >>> On Sun, Jul 26, 2015 at 06:48:15PM +0200, Paul Kocialkowski wrote:
> >>>> In order to achieve reproducible builds in U-Boot, timestamps that are defined
> >>>> at build-time have to be somewhat eliminated. The SOURCE_DATE_EPOCH environment
> >>>> variable allows setting a fixed value for those timestamps.
> >>>>
> >>>> Simply by setting SOURCE_DATE_EPOCH to a fixed value, a number of targets can be
> >>>> built reproducibly. This is the case for e.g. sunxi devices.
> >>>>
> >>>> However, some other devices might need some more tweaks, especially regarding
> >>>> the image generation tools.
> >>>>
> >>>> Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
> >>>
> >>> Applied to u-boot/master, thanks!
> >>
> >> This commit breaks build on non GNU hosts (like OS X and persumably
> >> other *BSD hosts). Before, those hosts where supported, so for me this
> >> has to be fixed for 2015.10
> >>
> >> We need a) some mechanism to search for the GNU date variant or b) some
> >> wrapper to provide the correct output on those host machines.
> >>
> >> I vote for a), it is acceptable to have the GNU date available but we
> >> should error on 'no GNU date available'. Furthermore we need to have the
> >> date command exchangeable by e.g. gdate, gnudate, ... maybe with full path.
> > 
> > There was a proposed patch which only uses the GNU date extensions if
> > SOURCE_DATE_EPOCH environment variable is set, would this sufficiently
> > address your concerns, at least for the short term?
> > 
> >   Message-Id: <1438337042-30762-1-git-send-email-judge.packham@gmail.com>
> >   http://lists.denx.de/pipermail/u-boot/2015-August/221429.html
> 
> thanks for the pointer, normal builds work with that change.

I think we should get that patch merged so that it doesn't affect
regular builds on non-GNU hosts. It is also relevant for the purpose it
serves initially, too.
Vagrant Cascadian Sept. 24, 2015, 4:05 p.m. UTC | #11
On 2015-07-26, Paul Kocialkowski wrote:
> In order to achieve reproducible builds in U-Boot, timestamps that are defined
> at build-time have to be somewhat eliminated. The SOURCE_DATE_EPOCH environment
> variable allows setting a fixed value for those timestamps.
...
> However, some other devices might need some more tweaks, especially regarding
> the image generation tools.

With this patch, there is still variation based on timezone in any of
the u-boot.img and u-boot-sunxi-with-spl.bin produced in the Debian
packages:

  https://reproducible.debian.net/rb-pkg/unstable/armhf/u-boot.html

The good news is that all the u-boot.bin targets are produced
reproducibly, so here's to progress!


I think the use of "time = mktime(time_universal);" is where the problem
lies:

> diff --git a/tools/default_image.c b/tools/default_image.c
> index cf5c0d4..18940af 100644
> --- a/tools/default_image.c
> +++ b/tools/default_image.c
> @@ -96,9 +99,25 @@ static void image_set_header(void *ptr, struct stat *sbuf, int ifd,
>  				sizeof(image_header_t)),
>  			sbuf->st_size - sizeof(image_header_t));
>  
> +	source_date_epoch = getenv("SOURCE_DATE_EPOCH");
> +	if (source_date_epoch != NULL) {
> +		time = (time_t) strtol(source_date_epoch, NULL, 10);
> +
> +		time_universal = gmtime(&time);
> +		if (time_universal == NULL) {
> +			fprintf(stderr, "%s: SOURCE_DATE_EPOCH is not valid\n",
> +				__func__);
> +			time = 0;
> +		} else {
> +			time = mktime(time_universal);
> +		}
> +	} else {
> +		time = sbuf->st_mtime;
> +	}
> +
>  	/* Build new header */
>  	image_set_magic(hdr, IH_MAGIC);
> -	image_set_time(hdr, sbuf->st_mtime);
> +	image_set_time(hdr, time);
>  	image_set_size(hdr, sbuf->st_size - sizeof(image_header_t));
>  	image_set_load(hdr, params->addr);
>  	image_set_ep(hdr, params->ep);
> -- 
> 1.9.1

According to the mktime manpage:

       The  mktime()  function converts a broken-down time structure,
       expressed as local time, to calendar time representation.  

So my interpetation is that it's taking the UTC time and converts it
into local time using the configured timezone... not sure what would be
a viable alternative to mktime.

Running with the TZ=UTC environment variable exported works around the
problem; not sure if it would be appropriate to always run with TZ=UTC
when SOURCE_DATE_EPOCH is set...


live well,
  vagrant
Paul Kocialkowski Sept. 28, 2015, 5:42 p.m. UTC | #12
Le jeudi 24 septembre 2015 à 09:05 -0700, Vagrant Cascadian a écrit :
> On 2015-07-26, Paul Kocialkowski wrote:
> > In order to achieve reproducible builds in U-Boot, timestamps that are defined
> > at build-time have to be somewhat eliminated. The SOURCE_DATE_EPOCH environment
> > variable allows setting a fixed value for those timestamps.
> ...
> > However, some other devices might need some more tweaks, especially regarding
> > the image generation tools.
> 
> With this patch, there is still variation based on timezone in any of
> the u-boot.img and u-boot-sunxi-with-spl.bin produced in the Debian
> packages:
> 
>   https://reproducible.debian.net/rb-pkg/unstable/armhf/u-boot.html

Thanks for reporting this!

> The good news is that all the u-boot.bin targets are produced
> reproducibly, so here's to progress!

Good, that's a nice first step forward.

> I think the use of "time = mktime(time_universal);" is where the problem
> lies:

[…]

> According to the mktime manpage:
> 
>        The  mktime()  function converts a broken-down time structure,
>        expressed as local time, to calendar time representation.  
> 
> So my interpetation is that it's taking the UTC time and converts it
> into local time using the configured timezone... not sure what would be
> a viable alternative to mktime.

That seems to make sense. Come to think of it, it probably was not
necessary to call gmtime in the first place: if SOURCE_DATE_EPOCH is
always in UTC, we should be able to stick that as-is in the time
variable. At best, gmtime + mktime (assuming mktime working in UTC)
would give us back the same timestamp.

What do you think? Please let me know if I'm wrong.

> Running with the TZ=UTC environment variable exported works around the
> problem; not sure if it would be appropriate to always run with TZ=UTC
> when SOURCE_DATE_EPOCH is set...

Well that's too much of a workaround to be a reliable solution for the
long term, IMHO.
Siarhei Siamashka Sept. 28, 2015, 6:59 p.m. UTC | #13
On Thu, 24 Sep 2015 09:05:10 -0700
Vagrant Cascadian <vagrant@debian.org> wrote:

> On 2015-07-26, Paul Kocialkowski wrote:
> > In order to achieve reproducible builds in U-Boot, timestamps that are defined
> > at build-time have to be somewhat eliminated. The SOURCE_DATE_EPOCH environment
> > variable allows setting a fixed value for those timestamps.
> ...
> > However, some other devices might need some more tweaks, especially regarding
> > the image generation tools.
> 
> With this patch, there is still variation based on timezone in any of
> the u-boot.img and u-boot-sunxi-with-spl.bin produced in the Debian
> packages:
> 
>   https://reproducible.debian.net/rb-pkg/unstable/armhf/u-boot.html
> 
> The good news is that all the u-boot.bin targets are produced
> reproducibly, so here's to progress!

Hello,

I see that Debian is building U-Boot 2015.07 according to the
information from that link. It may be a good idea to ensure that
the following simple patch is also applied:
    http://git.denx.de/?p=u-boot.git;a=commitdiff;h=bfb05d0187d70274c77d02dc0de5e728e1f8be05

It had been submitted at the day when somebody (probably you) was
troubleshooting reproducible build issues and asking questions in
the U-Boot IRC channel.
diff mbox

Patch

diff --git a/Makefile b/Makefile
index 54ef2cd..596974c 100644
--- a/Makefile
+++ b/Makefile
@@ -1232,9 +1232,10 @@  define filechk_version.h
 endef
 
 define filechk_timestamp.h
-	(LC_ALL=C date +'#define U_BOOT_DATE "%b %d %C%y"'; \
-	LC_ALL=C date +'#define U_BOOT_TIME "%T"'; \
-	LC_ALL=C date +'#define U_BOOT_TZ "%z"')
+	(SOURCE_DATE="$${SOURCE_DATE_EPOCH:+@$$SOURCE_DATE_EPOCH}"; \
+	LC_ALL=C date -u -d "$${SOURCE_DATE:-now}" +'#define U_BOOT_DATE "%b %d %C%y"'; \
+	LC_ALL=C date -u -d "$${SOURCE_DATE:-now}" +'#define U_BOOT_TIME "%T"'; \
+	LC_ALL=C date -u -d "$${SOURCE_DATE:-now}" +'#define U_BOOT_TZ "%z"' )
 endef
 
 $(version_h): include/config/uboot.release FORCE
diff --git a/README b/README
index 4e0ff9f..1bcb63c 100644
--- a/README
+++ b/README
@@ -5081,6 +5081,18 @@  This firmware often needs to be loaded during U-Boot booting.
 - CONFIG_SYS_MEM_TOP_HIDE_MIN
 	Define minimum DDR size to be hided from top of the DDR memory
 
+Reproducible builds
+-------------------
+
+In order to achieve reproducible builds, timestamps used in the U-Boot build
+process have to be set to a fixed value.
+
+This is done using the SOURCE_DATE_EPOCH environment variable.
+SOURCE_DATE_EPOCH is to be set on the build host's shell, not as a configuration
+option for U-Boot or an environment variable in U-Boot.
+
+SOURCE_DATE_EPOCH should be set to a number of seconds since the epoch, in UTC.
+
 Building the Software:
 ======================
 
diff --git a/tools/default_image.c b/tools/default_image.c
index cf5c0d4..18940af 100644
--- a/tools/default_image.c
+++ b/tools/default_image.c
@@ -88,6 +88,9 @@  static void image_set_header(void *ptr, struct stat *sbuf, int ifd,
 				struct image_tool_params *params)
 {
 	uint32_t checksum;
+	char *source_date_epoch;
+	struct tm *time_universal;
+	time_t time;
 
 	image_header_t * hdr = (image_header_t *)ptr;
 
@@ -96,9 +99,25 @@  static void image_set_header(void *ptr, struct stat *sbuf, int ifd,
 				sizeof(image_header_t)),
 			sbuf->st_size - sizeof(image_header_t));
 
+	source_date_epoch = getenv("SOURCE_DATE_EPOCH");
+	if (source_date_epoch != NULL) {
+		time = (time_t) strtol(source_date_epoch, NULL, 10);
+
+		time_universal = gmtime(&time);
+		if (time_universal == NULL) {
+			fprintf(stderr, "%s: SOURCE_DATE_EPOCH is not valid\n",
+				__func__);
+			time = 0;
+		} else {
+			time = mktime(time_universal);
+		}
+	} else {
+		time = sbuf->st_mtime;
+	}
+
 	/* Build new header */
 	image_set_magic(hdr, IH_MAGIC);
-	image_set_time(hdr, sbuf->st_mtime);
+	image_set_time(hdr, time);
 	image_set_size(hdr, sbuf->st_size - sizeof(image_header_t));
 	image_set_load(hdr, params->addr);
 	image_set_ep(hdr, params->ep);