[poky] [PATCH 3/4] package.bbclass: Refactor split and strip function

Mark Hatle mark.hatle at windriver.com
Fri Feb 11 06:56:01 PST 2011


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 at windriver.com>
---
 meta/classes/package.bbclass |  242 +++++++++++++++++++++++++-----------------
 1 files changed, 144 insertions(+), 98 deletions(-)

diff --git a/meta/classes/package.bbclass b/meta/classes/package.bbclass
index 94dbdcc..dd25df1 100644
--- a/meta/classes/package.bbclass
+++ b/meta/classes/package.bbclass
@@ -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...
+				# 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)
-						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
+					except OSError, (err, strerror):
+						if err != errno.ENOENT:
+							raise
+						# 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:
-								bb.mkdirhier(os.path.dirname(fpath))
-								#bb.note("Link %s -> %s" % (fpath, file_links[file_reference]))
-								os.link(file_links[file_reference], fpath)
-								continue
+								ltarget = target
 
-						if elf_file == 2:
-							bb.warn("File '%s' was already stripped, this will prevent future debugging!" % (src))
+							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
 
-						# Split and Strip
-						bb.mkdirhier(os.path.dirname(fpath))
-						#bb.note("Split %s -> %s" % (file, fpath))
-						splitfile(file, fpath, debugsrcdir, d)
+							file_list[file] = "ELF: %d" % elf_file
 
-		# 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):])):
-					try:
-						s = os.stat(file)
-					except OSError, (err, strerror):
-						if err != errno.ENOENT:
-							raise
-						#bb.note("Remove dangling link %s" % file)
-						os.unlink(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
 	#
-- 
1.7.3.4




More information about the poky mailing list