mirror of
https://git.yoctoproject.org/poky
synced 2026-06-30 11:13:39 +02:00
Change the search regime for find_git_folder():
1. WORKDIR/git: This is the default git fetcher unpack path
2. ${S}
3. Go looking for .git/ under the WORKDIR as a last resort.
linux-yocto:
We had an existing (silent) defect. The linux-yocto recipes all specify
two git SRC_URIs, one for the kernel source itself, the other for the
kmeta data (config fragments and friends). find_git_folder() was finding
the git checkout for the kmeta data, but due to a typo in the git log -1
--pretty=%ct line, we were (silently) reading the source_date_epoch from
the ${S} directory = STAGING_KERNEL_DIR, which is empty. If your
build/ happened to be inside a git checkout, git would walk up the
directory tree, and silently read the commit timestamp from this other
git checkout. The correct path to read the git commit timestamp from is
the "gitpath", being that found by find_git_folder(), though this
function was incorrectly finding the kmeta data checkout, not the kernel
source tree.
Non-kernel git recipes:
The default git fetcher clones and checks out the sources at
WORKDIR/git/ regardless of the setting of S (unless subpath or
destsuffix is set). find_git_folder() now looks for the
WORKDIR/git/.git/ directory first.
Non-yocto linux kernels:
Kernel recipes that don't inherit kernel-yocto should always set
S = ${WORKDIR}/git, so that when base_do_unpack_append() in
kernel.bbclass moves the checkout down to the STAGING_KERNEL_DIR and
symlinks it as WORKDIR/git, the build can still work by following the
symlink. We were previously failing to follow the symlink in the
os.walk(), but we now look first for WORKDIR/git/.git/, and find it due
to the symlink.
If none of the above mechanisms work for finding the git checkout,
perhaps there was a subpath or destsuffix specified in the SRC_URI.
We go looking for the git checkout under the WORKDIR as a last resort.
(From OE-Core rev: b0ddb141d36853447f85ecaac07dbc9c5779627f)
Signed-off-by: Douglas Royds <douglas.royds@taitradio.com>
Signed-off-by: Ross Burton <ross.burton@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
165 lines
6.5 KiB
Plaintext
165 lines
6.5 KiB
Plaintext
# reproducible_build.bbclass
|
|
#
|
|
# Sets SOURCE_DATE_EPOCH in each component's build environment.
|
|
# Upstream components (generally) respect this environment variable,
|
|
# using it in place of the "current" date and time.
|
|
# See https://reproducible-builds.org/specs/source-date-epoch/
|
|
#
|
|
# After sources are unpacked but before they are patched, we set a reproducible value for SOURCE_DATE_EPOCH.
|
|
# This value should be reproducible for anyone who builds the same revision from the same sources.
|
|
#
|
|
# There are 4 ways we determine SOURCE_DATE_EPOCH:
|
|
#
|
|
# 1. Use the value from __source_date_epoch.txt file if this file exists.
|
|
# This file was most likely created in the previous build by one of the following methods 2,3,4.
|
|
# Alternatively, it can be provided by a recipe via SRC_URI.
|
|
#
|
|
# If the file does not exist:
|
|
#
|
|
# 2. If there is a git checkout, use the last git commit timestamp.
|
|
# Git does not preserve file timestamps on checkout.
|
|
#
|
|
# 3. Use the mtime of "known" files such as NEWS, CHANGLELOG, ...
|
|
# This works for well-kept repositories distributed via tarball.
|
|
#
|
|
# 4. If the above steps fail, use the modification time of the youngest file in the source tree.
|
|
#
|
|
# Once the value of SOURCE_DATE_EPOCH is determined, it is stored in the recipe's ${SDE_FILE}.
|
|
# If this file is found by other tasks, the value is exported in the SOURCE_DATE_EPOCH variable.
|
|
# SOURCE_DATE_EPOCH is set for all tasks that might use it (do_configure, do_compile, do_package, ...)
|
|
|
|
BUILD_REPRODUCIBLE_BINARIES ??= '1'
|
|
inherit ${@oe.utils.ifelse(d.getVar('BUILD_REPRODUCIBLE_BINARIES') == '1', 'reproducible_build_simple', '')}
|
|
|
|
SDE_DIR ="${WORKDIR}/source-date-epoch"
|
|
SDE_FILE = "${SDE_DIR}/__source_date_epoch.txt"
|
|
|
|
SSTATETASKS += "do_deploy_source_date_epoch"
|
|
|
|
do_deploy_source_date_epoch () {
|
|
echo "Deploying SDE to ${SDE_DIR}."
|
|
}
|
|
|
|
python do_deploy_source_date_epoch_setscene () {
|
|
sstate_setscene(d)
|
|
}
|
|
|
|
do_deploy_source_date_epoch[dirs] = "${SDE_DIR}"
|
|
do_deploy_source_date_epoch[sstate-plaindirs] = "${SDE_DIR}"
|
|
addtask do_deploy_source_date_epoch_setscene
|
|
addtask do_deploy_source_date_epoch before do_configure after do_patch
|
|
|
|
def get_source_date_epoch_from_known_files(d, sourcedir):
|
|
source_date_epoch = None
|
|
known_files = set(["NEWS", "ChangeLog", "Changelog", "CHANGES"])
|
|
for file in known_files:
|
|
filepath = os.path.join(sourcedir, file)
|
|
if os.path.isfile(filepath):
|
|
mtime = int(os.lstat(filepath).st_mtime)
|
|
# There may be more than one "known_file" present, if so, use the youngest one
|
|
if not source_date_epoch or mtime > source_date_epoch:
|
|
source_date_epoch = mtime
|
|
return source_date_epoch
|
|
|
|
def find_git_folder(d, sourcedir):
|
|
# First guess: WORKDIR/git
|
|
# This is the default git fetcher unpack path
|
|
workdir = d.getVar('WORKDIR')
|
|
gitpath = os.path.join(workdir, "git/.git")
|
|
if os.path.isdir(gitpath):
|
|
return gitpath
|
|
|
|
# Second guess: ${S}
|
|
gitpath = os.path.join(sourcedir, ".git")
|
|
if os.path.isdir(gitpath):
|
|
return gitpath
|
|
|
|
# Perhaps there was a subpath or destsuffix specified.
|
|
# Go looking in the WORKDIR
|
|
exclude = set(["build", "image", "license-destdir", "patches", "pseudo",
|
|
"recipe-sysroot", "recipe-sysroot-native", "sysroot-destdir", "temp"])
|
|
for root, dirs, files in os.walk(workdir, topdown=True):
|
|
dirs[:] = [d for d in dirs if d not in exclude]
|
|
if '.git' in dirs:
|
|
return root
|
|
|
|
bb.warn("Failed to find a git repository in WORKDIR: %s" % workdir)
|
|
return None
|
|
|
|
def get_source_date_epoch_from_git(d, sourcedir):
|
|
source_date_epoch = None
|
|
if "git://" in d.getVar('SRC_URI'):
|
|
gitpath = find_git_folder(d, sourcedir)
|
|
if gitpath:
|
|
import subprocess
|
|
source_date_epoch = int(subprocess.check_output(['git','log','-1','--pretty=%ct'], cwd=gitpath))
|
|
bb.debug(1, "git repo path: %s sde: %d" % (gitpath, source_date_epoch))
|
|
return source_date_epoch
|
|
|
|
def get_source_date_epoch_from_youngest_file(d, sourcedir):
|
|
# Do it the hard way: check all files and find the youngest one...
|
|
source_date_epoch = None
|
|
newest_file = None
|
|
# Just in case S = WORKDIR
|
|
exclude = set(["build", "image", "license-destdir", "patches", "pseudo",
|
|
"recipe-sysroot", "recipe-sysroot-native", "sysroot-destdir", "temp"])
|
|
for root, dirs, files in os.walk(sourcedir, topdown=True):
|
|
files = [f for f in files if not f[0] == '.']
|
|
dirs[:] = [d for d in dirs if d not in exclude]
|
|
|
|
for fname in files:
|
|
filename = os.path.join(root, fname)
|
|
try:
|
|
mtime = int(os.lstat(filename).st_mtime)
|
|
except ValueError:
|
|
mtime = 0
|
|
if not source_date_epoch or mtime > source_date_epoch:
|
|
source_date_epoch = mtime
|
|
newest_file = filename
|
|
|
|
if newest_file != None:
|
|
bb.debug(1," SOURCE_DATE_EPOCH %d derived from: %s" % (source_date_epoch, newest_file))
|
|
return source_date_epoch
|
|
|
|
python do_create_source_date_epoch_stamp() {
|
|
sourcedir = d.getVar('S')
|
|
if not os.path.isdir(sourcedir):
|
|
bb.warn("Unable to determine source_date_epoch! path:%s" % sourcedir)
|
|
return
|
|
|
|
epochfile = d.getVar('SDE_FILE')
|
|
if os.path.isfile(epochfile):
|
|
bb.debug(1, " path: %s reusing __source_date_epoch.txt" % epochfile)
|
|
return
|
|
|
|
source_date_epoch = (
|
|
get_source_date_epoch_from_git(d, sourcedir) or
|
|
get_source_date_epoch_from_known_files(d, sourcedir) or
|
|
get_source_date_epoch_from_youngest_file(d, sourcedir) or
|
|
0 # Last resort
|
|
)
|
|
if source_date_epoch == 0:
|
|
# empty folder, not a single file ...
|
|
# kernel source do_unpack is special cased
|
|
if not bb.data.inherits_class('kernel', d):
|
|
bb.debug(1, "Unable to determine source_date_epoch! path:%s" % sourcedir)
|
|
|
|
bb.utils.mkdirhier(d.getVar('SDE_DIR'))
|
|
with open(epochfile, 'w') as f:
|
|
f.write(str(source_date_epoch))
|
|
}
|
|
|
|
BB_HASHBASE_WHITELIST += "SOURCE_DATE_EPOCH"
|
|
|
|
python () {
|
|
if d.getVar('BUILD_REPRODUCIBLE_BINARIES') == '1':
|
|
d.appendVarFlag("do_unpack", "postfuncs", " do_create_source_date_epoch_stamp")
|
|
epochfile = d.getVar('SDE_FILE')
|
|
source_date_epoch = "0"
|
|
if os.path.isfile(epochfile):
|
|
with open(epochfile, 'r') as f:
|
|
source_date_epoch = f.read()
|
|
bb.debug(1, "source_date_epoch stamp found ---> stamp %s" % source_date_epoch)
|
|
d.setVar('SOURCE_DATE_EPOCH', source_date_epoch)
|
|
}
|