package.py: Fix static library processing

When PACKAGE_STRIP_STATIC is enabled the system did not pay attention to
hardlinks.  This could trigger a race condition during stripping of static
libraries where multiple strips (through hardlinks) could run at the same
time triggering a truncated or modified file error.

The hardlink breaking code is based on the existing code for elf files, but
due to the nature of the symlinks needed to be done in a separate block of
code.

Add support for static-library debugfs hardlinking through the existing
inode processing code.

Print a note to the logs if the link target can't be found.  This isn't
strictly an error, but may be useful for debugging an issue where a file
isn't present.

(From OE-Core rev: c2809691992dab48a360c9516d205ec031378cda)

Signed-off-by: Mark Hatle <mark.hatle@amd.com>
Signed-off-by: Mark Hatle <mark.hatle@kernel.crashing.org>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
(cherry picked from commit ff371d69f60a1529ed456acb7d8e9305242e74bd)
Signed-off-by: Mark Hatle <mark.hatle@kernel.crashing.org>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
This commit is contained in:
Mark Hatle 2024-07-26 11:22:32 -05:00 committed by Steve Sakoman
parent 648d2617ba
commit 0d017528d4

View File

@ -1065,6 +1065,7 @@ def process_split_and_strip_files(d):
d.getVar('INHIBIT_PACKAGE_DEBUG_SPLIT') != '1'):
checkelf = {}
checkelflinks = {}
checkstatic = {}
for root, dirs, files in cpath.walk(dvar):
for f in files:
file = os.path.join(root, f)
@ -1078,10 +1079,6 @@ def process_split_and_strip_files(d):
if file in skipfiles:
continue
if oe.package.is_static_lib(file):
staticlibs.append(file)
continue
try:
ltarget = cpath.realpath(file, dvar, False)
s = cpath.lstat(ltarget)
@ -1093,6 +1090,13 @@ def process_split_and_strip_files(d):
continue
if not s:
continue
if oe.package.is_static_lib(file):
# Use a reference of device ID and inode number to identify files
file_reference = "%d_%d" % (s.st_dev, s.st_ino)
checkstatic[file] = (file, file_reference)
continue
# Check its an executable
if (s[stat.ST_MODE] & stat.S_IXUSR) or (s[stat.ST_MODE] & stat.S_IXGRP) \
or (s[stat.ST_MODE] & stat.S_IXOTH) \
@ -1157,6 +1161,27 @@ def process_split_and_strip_files(d):
# Modified the file so clear the cache
cpath.updatecache(file)
# Do the same hardlink processing as above, but for static libraries
results = list(checkstatic.keys())
# As above, sort the results.
results.sort(key=lambda x: x[0])
for file in results:
# Use a reference of device ID and inode number to identify files
file_reference = checkstatic[file][1]
if file_reference in inodes:
os.unlink(file)
os.link(inodes[file_reference][0], file)
inodes[file_reference].append(file)
else:
inodes[file_reference] = [file]
# break hardlink
bb.utils.break_hardlinks(file)
staticlibs.append(file)
# Modified the file so clear the cache
cpath.updatecache(file)
def strip_pkgd_prefix(f):
nonlocal dvar
@ -1195,11 +1220,24 @@ def process_split_and_strip_files(d):
dest = dv["libdir"] + os.path.dirname(src) + dv["dir"] + "/" + os.path.basename(target) + dv["append"]
fpath = dvar + dest
ftarget = dvar + dv["libdir"] + os.path.dirname(target) + dv["dir"] + "/" + os.path.basename(target) + dv["append"]
bb.utils.mkdirhier(os.path.dirname(fpath))
# Only one hardlink of separated debug info file in each directory
if not os.access(fpath, os.R_OK):
#bb.note("Link %s -> %s" % (fpath, ftarget))
os.link(ftarget, fpath)
if os.access(ftarget, os.R_OK):
bb.utils.mkdirhier(os.path.dirname(fpath))
# Only one hardlink of separated debug info file in each directory
if not os.access(fpath, os.R_OK):
#bb.note("Link %s -> %s" % (fpath, ftarget))
os.link(ftarget, fpath)
elif (d.getVar('PACKAGE_DEBUG_STATIC_SPLIT') == '1'):
deststatic = dv["staticlibdir"] + os.path.dirname(src) + dv["staticdir"] + "/" + os.path.basename(file) + dv["staticappend"]
fpath = dvar + deststatic
ftarget = dvar + dv["staticlibdir"] + os.path.dirname(target) + dv["staticdir"] + "/" + os.path.basename(target) + dv["staticappend"]
if os.access(ftarget, os.R_OK):
bb.utils.mkdirhier(os.path.dirname(fpath))
# Only one hardlink of separated debug info file in each directory
if not os.access(fpath, os.R_OK):
#bb.note("Link %s -> %s" % (fpath, ftarget))
os.link(ftarget, fpath)
else:
bb.note("Unable to find inode link target %s" % (target))
# Create symlinks for all cases we were able to split symbols
for file in symlinks: