package.bbclass: Refactor split and strip function

Refactor the function to eliminate additional interations/walks of the
filesystem..

Elimiate multiple runs of the external 'file' command as well.

Signed-off-by: Mark Hatle <mark.hatle@windriver.com>
This commit is contained in:
Mark Hatle 2011-02-09 21:22:42 -06:00 committed by Richard Purdie
parent 16102e1890
commit 40ea19d6e1
1 changed files with 146 additions and 100 deletions

View File

@ -184,7 +184,7 @@ def splitfile(file, debugfile, debugsrcdir, d):
# We ignore kernel modules, we don't generate debug info files.
if file.find("/lib/modules/") != -1 and file.endswith(".ko"):
return 0
return 1
newmode = None
if not os.access(file, os.W_OK) or os.access(file, os.R_OK):
@ -239,9 +239,14 @@ def splitfile2(debugsrcdir, d):
#bb.note("rmdir -p %s" % dir)
os.system("rmdir -p %s 2>/dev/null" % dir)
def runstrip(file, d):
def runstrip(file, elftype, d):
# Function to strip a single file, called from split_and_strip_files below
# A working 'file' (one which works on the target architecture)
#
# The elftype is a bit pattern (explained in split_and_strip_files) to tell
# us what type of file we're processing...
# 4 - executable
# 8 - shared library
import commands, stat
@ -258,16 +263,12 @@ def runstrip(file, d):
newmode = origmode | stat.S_IWRITE | stat.S_IREAD
os.chmod(file, newmode)
ret, result = commands.getstatusoutput("%sfile '%s'" % (pathprefix, file))
if ret:
bb.error("runstrip: 'file %s' failed" % file)
return 0
extraflags = ""
if ".so" in file and "shared" in result:
# .so and shared library
if ".so" in file and elftype & 8:
extraflags = "--remove-section=.comment --remove-section=.note --strip-unneeded"
elif "shared" in result or "executable" in result:
# shared or executable:
elif elftype & 8 or elftype & 4:
extraflags = "--remove-section=.comment --remove-section=.note"
stripcmd = "'%s' %s '%s'" % (strip, extraflags, file)
@ -410,109 +411,158 @@ python split_and_strip_files () {
os.chdir(dvar)
def isexec(path):
try:
s = os.stat(path)
except (os.error, AttributeError):
return 0
return ((s[stat.ST_MODE] & stat.S_IXUSR) or (s[stat.ST_MODE] & stat.S_IXGRP) or (s[stat.ST_MODE] & stat.S_IXOTH))
# Return 0 - not elf, 1 - ELF & not stripped, 2 - ELF & stripped
# Return type (bits):
# 0 - not elf
# 1 - ELF
# 2 - stripped
# 4 - executable
# 8 - shared library
def isELF(path):
type = 0
pathprefix = "export PATH=%s; " % bb.data.getVar('PATH', d, True)
ret, result = commands.getstatusoutput("%sfile '%s'" % (pathprefix, path))
if ret:
bb.error("split_and_strip_files: 'file %s' failed" % path)
return 0
return type
# Not stripped
if "ELF" in result and "not stripped" in result:
return 1
# Stripped
if "ELF" in result:
return 2
type |= 1
if "not stripped" not in result:
type |= 2
if "executable" in result:
type |= 4
if "shared" in result:
type |= 8
return type
return 0;
#
# First lets process debug splitting
# First lets figure out all of the files we may have to process ... do this only once!
#
if (bb.data.getVar('INHIBIT_PACKAGE_DEBUG_SPLIT', d, True) != '1'):
file_links = {}
file_list = {}
file_links = {}
if (bb.data.getVar('INHIBIT_PACKAGE_DEBUG_SPLIT', d, True) != '1') and \
(bb.data.getVar('INHIBIT_PACKAGE_STRIP', d, True) != '1'):
for root, dirs, files in os.walk(dvar):
for f in files:
file = os.path.join(root, f)
# Skip debug files, it must be executable, and must be a file (or link)
if not (debugappend != "" and file.endswith(debugappend)) and not (debugdir != "" and debugdir in os.path.dirname(file[len(dvar):])) and isexec(file) and os.path.isfile(file):
src = file[len(dvar):]
dest = debuglibdir + os.path.dirname(src) + debugdir + "/" + os.path.basename(src) + debugappend
fpath = dvar + dest
# Preserve symlinks in debug area...
if os.path.islink(file):
target = os.readlink(file)
if not os.path.isabs(target):
target = os.path.join(os.path.dirname(file), target)
if isELF(target):
ltarget = os.readlink(file)
lpath = os.path.dirname(ltarget)
lbase = os.path.basename(ltarget)
ftarget = ""
if lpath and lpath != ".":
ftarget += lpath + debugdir + "/"
ftarget += lbase + debugappend
bb.mkdirhier(os.path.dirname(fpath))
#bb.note("Symlink %s -> %s" % (fpath, ftarget))
os.symlink(ftarget, fpath)
continue
# If the file is elf we need to check it for hard links
elf_file = isELF(file)
if elf_file:
# Preserve hard links in debug area...
s = os.stat(file)
if s.st_nlink > 1:
file_reference = "%d_%d" % (s.st_dev, s.st_ino)
if file_reference not in file_links:
# If this is new, and already stripped we avoid recording it
# as we'll be unable to set the hard link later, because it
# won't be split/stripped...
if elf_file != 2:
file_links[file_reference] = fpath
else:
bb.mkdirhier(os.path.dirname(fpath))
#bb.note("Link %s -> %s" % (fpath, file_links[file_reference]))
os.link(file_links[file_reference], fpath)
continue
if elf_file == 2:
bb.warn("File '%s' was already stripped, this will prevent future debugging!" % (src))
continue
# Split and Strip
bb.mkdirhier(os.path.dirname(fpath))
#bb.note("Split %s -> %s" % (file, fpath))
splitfile(file, fpath, debugsrcdir, d)
# Process the debugsrcdir if requested...
splitfile2(debugsrcdir, d)
# The above may have generated dangling symlinks
for root, dirs, files in os.walk(dvar):
for f in files:
file = os.path.join(root, f)
# We ONLY strip dangling links if they're debug generated!
if (debugappend != "" and file.endswith(debugappend)) or (debugdir != "" and debugdir in os.path.dirname(file[len(dvar):])):
# Only process files (and symlinks)... Skip files that are obviously debug files
if not (debugappend != "" and file.endswith(debugappend)) and \
not (debugdir != "" and debugdir in os.path.dirname(file[len(dvar):])) and \
os.path.isfile(file):
try:
s = os.stat(file)
except OSError, (err, strerror):
if err != errno.ENOENT:
raise
#bb.note("Remove dangling link %s" % file)
os.unlink(file)
# Skip broken symlinks
continue
# Is the item excutable? Then we need to process it.
if (s[stat.ST_MODE] & stat.S_IXUSR) or \
(s[stat.ST_MODE] & stat.S_IXGRP) or \
(s[stat.ST_MODE] & stat.S_IXOTH):
# If it's a symlink, and points to an ELF file, we capture the readlink target
if os.path.islink(file):
target = os.readlink(file)
if not os.path.isabs(target):
ltarget = os.path.join(os.path.dirname(file), target)
else:
ltarget = target
if isELF(ltarget):
#bb.note("Sym: %s (%d)" % (ltarget, isELF(ltarget)))
file_list[file] = "sym: " + target
continue
# It's a file (or hardlink), not a link
# ...but is it ELF, and is it already stripped?
elf_file = isELF(file)
if elf_file & 1:
# Check if it's a hard link to something else
if s.st_nlink > 1:
file_reference = "%d_%d" % (s.st_dev, s.st_ino)
# Hard link to something else
file_list[file] = "hard: " + file_reference
continue
file_list[file] = "ELF: %d" % elf_file
#
# First lets process debug splitting
#
if (bb.data.getVar('INHIBIT_PACKAGE_DEBUG_SPLIT', d, True) != '1'):
for file in file_list:
src = file[len(dvar):]
dest = debuglibdir + os.path.dirname(src) + debugdir + "/" + os.path.basename(src) + debugappend
fpath = dvar + dest
# Preserve symlinks in debug area...
if file_list[file].startswith("sym: "):
ltarget = file_list[file][5:]
lpath = os.path.dirname(ltarget)
lbase = os.path.basename(ltarget)
ftarget = ""
if lpath and lpath != ".":
ftarget += lpath + debugdir + "/"
ftarget += lbase + debugappend
bb.mkdirhier(os.path.dirname(fpath))
#bb.note("Symlink %s -> %s" % (fpath, ftarget))
os.symlink(ftarget, fpath)
continue
# Preserve hard links in debug area...
file_reference = ""
if file_list[file].startswith("hard: "):
file_reference = file_list[file][6:]
if file_reference not in file_links:
# If this is a new file, add it as a reference, and
# update it's type, so we can fall through and split
file_list[file] = "ELF: %d" % (isELF(file))
else:
target = file_links[file_reference][len(dvar):]
ftarget = dvar + debuglibdir + os.path.dirname(target) + debugdir + "/" + os.path.basename(target) + debugappend
bb.mkdirhier(os.path.dirname(fpath))
#bb.note("Link %s -> %s" % (fpath, ftarget))
os.link(ftarget, fpath)
continue
# It's ELF...
if file_list[file].startswith("ELF: "):
elf_file = int(file_list[file][5:])
if elf_file & 2:
bb.warn("File '%s' was already stripped, this will prevent future debugging!" % (src))
continue
# Split the file...
bb.mkdirhier(os.path.dirname(fpath))
#bb.note("Split %s -> %s" % (file, fpath))
# Only store off the hard link reference if we successfully split!
if splitfile(file, fpath, debugsrcdir, d) == 0 and file_reference != "":
file_links[file_reference] = file
# The above may have generated dangling symlinks, remove them!
# Dangling symlinks are a result of something NOT being split, such as a stripped binary.
# This should be a rare occurance, but we want to clean up anyway.
for file in file_list:
if file_list[file].startswith("sym: "):
src = file[len(dvar):]
dest = debuglibdir + os.path.dirname(src) + debugdir + "/" + os.path.basename(src) + debugappend
fpath = dvar + dest
try:
s = os.stat(fpath)
except OSError, (err, strerror):
if err != errno.ENOENT:
raise
#bb.note("Remove dangling link %s -> %s" % (fpath, os.readlink(fpath)))
os.unlink(fpath)
# This could leave an empty debug directory laying around
# take care of the obvious case...
os.system("rmdir %s 2>/dev/null" % os.path.dirname(fpath))
# Process the debugsrcdir if requested...
# This copies and places the referenced sources for later debugging...
splitfile2(debugsrcdir, d)
#
# End of debug splitting
#
@ -521,15 +571,11 @@ python split_and_strip_files () {
# Now lets go back over things and strip them
#
if (bb.data.getVar('INHIBIT_PACKAGE_STRIP', d, True) != '1'):
for root, dirs, files in os.walk(dvar):
for f in files:
file = os.path.join(root, f)
# if not a debugfile, is executable, is a file, and not a symlink
if not (debugappend != "" and file.endswith(debugappend)) and not (debugdir != "" and debugdir in os.path.dirname(file[len(dvar):])) and isexec(file) and os.path.isfile(file) and not os.path.islink(file):
elf_file = isELF(file)
if elf_file and elf_file != 2:
#bb.note("Strip %s" % file)
runstrip(file, d)
for file in file_list:
if file_list[file].startswith("ELF: "):
elf_file = int(file_list[file][5:])
#bb.note("Strip %s" % file)
runstrip(file, elf_file, d)
#
# End of strip
#