diff mbox series

bitbake.conf: add new variable FIXED_SOURCE_DATE_EPOCH

Message ID 20251120114041.193806-1-changqing.li@windriver.com
State New
Headers show
Series bitbake.conf: add new variable FIXED_SOURCE_DATE_EPOCH | expand

Commit Message

Changqing Li Nov. 20, 2025, 11:40 a.m. UTC
From: Changqing Li <changqing.li@windriver.com>

Here is SRC_URI of jquery:
SRC_URI = "\
    https://code.jquery.com/${BP}.js;name=js;subdir=${BP} \
    https://code.jquery.com/${BP}.min.js;name=min;subdir=${BP} \
    https://code.jquery.com/${BP}.min.map;name=map;subdir=${BP} \
    "
When ${BP}.js/${BP}.min.js/${BP}.min.map are downloaded in a git repo,
and this git repo is cloned locally as a PREMIRRORS. In this case, mtime
of these files will be current time when checking out. For this recipe,
source_date_epoch will get by function
get_source_date_epoch_from_youngest_file, mtime of
${BP}.js/${BP}.min.js/${BP}.min.map are not stable, so cause the
generated package not reproducible.

A new variable FIXED_SOURCE_DATE_EPOCH is added to support this case.
By default, FIXED_SOURCE_DATE_EPOCH is 0,  and source_date_epoch works
as before. If user build in above case, FIXED_SOURCE_DATE_EPOCH set to 1
in recipe jquery can ensure fixed source date epoch used by this recipe
to support reproducible build.

Signed-off-by: Changqing Li <changqing.li@windriver.com>
---
 meta/conf/bitbake.conf      |  1 +
 meta/lib/oe/reproducible.py | 13 ++++++++-----
 2 files changed, 9 insertions(+), 5 deletions(-)

Comments

Alexander Kanavin Nov. 20, 2025, 11:46 a.m. UTC | #1
On Thu, 20 Nov 2025 at 12:40, Changqing Li via lists.openembedded.org
<changqing.li=windriver.com@lists.openembedded.org> wrote:
>
> From: Changqing Li <changqing.li@windriver.com>
>
> Here is SRC_URI of jquery:
> SRC_URI = "\
>     https://code.jquery.com/${BP}.js;name=js;subdir=${BP} \
>     https://code.jquery.com/${BP}.min.js;name=min;subdir=${BP} \
>     https://code.jquery.com/${BP}.min.map;name=map;subdir=${BP} \
>     "
> When ${BP}.js/${BP}.min.js/${BP}.min.map are downloaded in a git repo,
> and this git repo is cloned locally as a PREMIRRORS. In this case, mtime
> of these files will be current time when checking out.

I don't understand. Is SRC_URI tweaked in a .bbappend to something
else? Can you provide a way to observe the issue?

The bar for adding new variables to bitbake.conf is high, and we
should strive to avoid that.

Alex
Richard Purdie Nov. 20, 2025, 12:17 p.m. UTC | #2
On Thu, 2025-11-20 at 19:40 +0800, Changqing Li via lists.openembedded.org wrote:
> From: Changqing Li <changqing.li@windriver.com>
> 
> Here is SRC_URI of jquery:
> SRC_URI = "\
>     https://code.jquery.com/${BP}.js;name=js;subdir=${BP} \
>     https://code.jquery.com/${BP}.min.js;name=min;subdir=${BP} \
>     https://code.jquery.com/${BP}.min.map;name=map;subdir=${BP} \
>     "
> When ${BP}.js/${BP}.min.js/${BP}.min.map are downloaded in a git repo,
> and this git repo is cloned locally as a PREMIRRORS. In this case, mtime
> of these files will be current time when checking out. For this recipe,
> source_date_epoch will get by function
> get_source_date_epoch_from_youngest_file, mtime of
> ${BP}.js/${BP}.min.js/${BP}.min.map are not stable, so cause the
> generated package not reproducible.
> 
> A new variable FIXED_SOURCE_DATE_EPOCH is added to support this case.
> By default, FIXED_SOURCE_DATE_EPOCH is 0,  and source_date_epoch works
> as before. If user build in above case, FIXED_SOURCE_DATE_EPOCH set to 1
> in recipe jquery can ensure fixed source date epoch used by this recipe
> to support reproducible build.
> 
> Signed-off-by: Changqing Li <changqing.li@windriver.com>
> ---
>  meta/conf/bitbake.conf      |  1 +
>  meta/lib/oe/reproducible.py | 13 ++++++++-----
>  2 files changed, 9 insertions(+), 5 deletions(-)

We need to take a step back here and think about what is going on.

The current design is that mtimes of files are clamped at an upper
value which is determined by the the logic you're changing.

There is an assumption that the mtimes don't affect the build, the
build process will create files and therefore we will always have to
have some kind of ignore threshold as the creation times of built
components will vary.

As you've pointed out, git can under some circumstances mean that files
don't have the correct mtime ordering which causes components to
rebuild, particularly around flex/bison. We need to find those cases
and ensure the right mtime ordering as you've done in some patches.

What I don't think is reasonable is changing the git fetcher to try and
have stable mtimes, or adding new variables without a really strong
explanation of why the existing code can't work.

Cheers,

Richard
diff mbox series

Patch

diff --git a/meta/conf/bitbake.conf b/meta/conf/bitbake.conf
index 5406e542db..2371567da3 100644
--- a/meta/conf/bitbake.conf
+++ b/meta/conf/bitbake.conf
@@ -680,6 +680,7 @@  export SOURCE_DATE_EPOCH ?= "${@get_source_date_epoch_value(d)}"
 # A SOURCE_DATE_EPOCH of '0' might be misinterpreted as no SDE
 SOURCE_DATE_EPOCH_FALLBACK ??= "1302044400"
 REPRODUCIBLE_TIMESTAMP_ROOTFS ??= "1520598896"
+FIXED_SOURCE_DATE_EPOCH ?= "0"
 
 ##################################################################
 # Settings used by bitbake-layers.
diff --git a/meta/lib/oe/reproducible.py b/meta/lib/oe/reproducible.py
index 0270024a83..8ed5e2b458 100644
--- a/meta/lib/oe/reproducible.py
+++ b/meta/lib/oe/reproducible.py
@@ -158,11 +158,14 @@  def fixed_source_date_epoch(d):
     return 0
 
 def get_source_date_epoch(d, sourcedir):
-    return (
-        get_source_date_epoch_from_git(d, sourcedir) or
-        get_source_date_epoch_from_youngest_file(d, sourcedir) or
-        fixed_source_date_epoch(d)       # Last resort
-    )
+    if d.getVar('FIXED_SOURCE_DATE_EPOCH') == '0':
+        return (
+            get_source_date_epoch_from_git(d, sourcedir) or
+            get_source_date_epoch_from_youngest_file(d, sourcedir) or
+            fixed_source_date_epoch(d)       # Last resort
+        )
+    else:
+        return fixed_source_date_epoch(d)
 
 def epochfile_read(epochfile, d):
     cached, efile = d.getVar('__CACHED_SOURCE_DATE_EPOCH') or (None, None)