• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Recommendations for strip(1)? Was: gdb: "No line number info...."
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Recommendations for strip(1)? Was: gdb: "No line number info...."


  • Subject: Recommendations for strip(1)? Was: gdb: "No line number info...."
  • From: Jerry Krinock <email@hidden>
  • Date: Sat, 15 Aug 2009 23:31:13 -0700


On 2009 Jul 29, at 06:48, Thierry Faucounau wrote:

This will happen for me if I build Release twice in a row without deleting the application in between. What happens is...

Thierry hit the nail on the head here, although I'm unable to always reproduce the problem on the second build -- sometimes it takes three. With several dependent frameworks and bundles producing a half dozen dSYM files, accounting gets pretty complicated. I filed a bug, 7145893 [1].


So we conclude that the "strip" settings in Xcode 3.1.2 are broken/ dangerous, and we have two proposed workarounds:

Thierry's workaround:

build [only] after a full clean (or at least delete the application binary so Xcode re-links it and puts the symbols back in)


Alastair's workaround:

copy the built product into a separate folder and then strip it there

I like Alastair's better. I presume that I would do this using strip(1), i.e. /Developer/usr/bin/strip. Correct? But reading in man strip I see the following statement which implies that ld(1) can do a better job of stripping than strip(1):


"The link editor ld(1) is the only program that can strip relocation entries and know if it is safe to do so."

I've not read enough to understand that yet. Does this weakness of strip(1) relative to stripping by ld(1) concern anyone?

Also, if someone would like to share which of the half dozen or so "stripping strength" options of strip(1) are recommended for a plain old Cocoa application, and/or for private frameworks and helpers within such a Cocoa application, it would provide some nice data points :)

Jerry Krinock


P.S. Probably I'm fighting the last war, but in testing this I put together and have attached a little Perl script which will check the dSYM files for the constituent executable files in an app bundle:


#!/usr/bin/perl

use strict ;
require File::Util ;

if (@ARGV != 1) {
	die "Usage:\n   checkdSYMS.pl /path/to/MyApp.app\nThis .app's parent directory should also contain the .dSYM files for the app's main executable and any constituent auxiliary executables, frameworks, loadable bundles, etc.  This is of course where they are normally deposited, if the parent directory is your Xcode \"Builds\" directory.  Specifically, this script will find executables in all the \"normal\" places -- the main executable, auxiliary executables in Contents/MacOS, auxiliary executables in Contents/Helpers, frameworks in Contents/Frameworks, and helpers or loadable bundles in Contents/Resources.  If you've got something weird like nested frameworks, it won't find those.\n" ;

}


my @components = split ("/", $ARGV[0]) ;
my $appName = @components[@components - 1] ;
$appName = substr($appName, 0, length($appName) - 4) ;
my $buildsReleasePath  = substr($ARGV[0], 0, length($ARGV[0]) - 4 - length($appName)) ;
printf ("Will check dSYM files for executables in $appName.app\n") ;
printf ("  in directory: $buildsReleasePath\n") ;

# Extract architectures from main executable
my $mainAppExecutable = "$buildsReleasePath$appName.app/Contents/MacOS/$appName" ;
my $otoolOutput = `/Developer/usr/bin/otool -fv "$mainAppExecutable"` ;
my @otoolLines = split("\n", $otoolOutput) ;
my @archLines = grep(/architecture /, @otoolLines) ;
my @architectures ;
foreach my $archLine (@archLines) {
	$archLine =~ s/architecture // ;
	push (@architectures, $archLine) ;
}
print "Main Executable \"$appName\" supports architectures:\n" ;
foreach my $arch (@architectures) {
	printf "   $arch\n" ;
}

my $fileUtil = File::Util->new() ;

my @rawNames ;
my $i ;
my @dSymNames ;

# Next, the executables in Contents/MacOS.  This directory had better exist, so we don't check for it.
my @executableNames ;
push @dSymNames, "$appName.app" ;
my $dirPath = "$buildsReleasePath$appName.app/Contents/MacOS" ;
# Script will fail here if Contents/MacOS does not exist:
my @rawNames = $fileUtil->list_dir($dirPath, qw/--no-fsdots --files-only/) ;
for ($i=0; $i<@rawNames; $i++) {
	# Exclude the application itself, because we've already got it -- with a .app extension
	if ($rawNames[$i] ne $appName) {
		push @dSymNames, $rawNames[$i] ;
	}
}


# Next, any executables in Contents/Helpers
$dirPath = "$buildsReleasePath$appName.app/Contents/Helpers" ;
if ($fileUtil->existent($dirPath)) {
	@rawNames = $fileUtil->list_dir($dirPath, qw/--no-fsdots --files-only/) ;
	for ($i=0; $i<@rawNames; $i++) {
		push @dSymNames, $rawNames[$i] ;
	}
}

# Next, any helper apps or loadable bundles in Contents/Resources
$dirPath = "$buildsReleasePath$appName.app/Contents/Resources" ;
if ($fileUtil->existent($dirPath)) {
	@rawNames = $fileUtil->list_dir($dirPath, qw/--no-fsdots --dirs-only/) ;
	my $dotApp = ".app" ;
	my $dotAppLength = length($dotApp) ;
	my $dotBundle = ".bundle" ;
	my $dotBundleLength = length($dotBundle) ;
	for ($i=0; $i<@rawNames; $i++) {
		# Only process names that have suffix $dotApp or $dotBundle
		if (index($rawNames[$i], $dotApp, length($rawNames[$i]) - $dotAppLength) > 0) {
			push @dSymNames, $rawNames[$i] ;
		}
		elsif (index($rawNames[$i], $dotBundle, length($rawNames[$i]) - $dotBundleLength) > 0) {
			push @dSymNames, $rawNames[$i] ;
		}
	}
}

# Next, any executables in the Contents/Frameworks
$dirPath = "$buildsReleasePath$appName.app/Contents/Frameworks" ;
if ($fileUtil->existent($dirPath)) {
	my @frameworkNames = $fileUtil->list_dir($dirPath, qw/--no-fsdots --dirs-only/) ;
	for ($i=0; $i<@frameworkNames; $i++) {
		my $frameworkDirPath = $dirPath . "/" . $frameworkNames[$i] ;
		@rawNames = $fileUtil->list_dir($frameworkDirPath, qw/--no-fsdots --files-only/) ;
		for (my $j=0; $j<@rawNames; $j++) {
			push @dSymNames, ($rawNames[$j] . ".framework") ;
		}
	}
}

my $n = @dSymNames ;

print "Checking dSYM files...\n" ;
my $trouble = 0 ;
foreach my $dSymName (@dSymNames) {
	printf "   $dSymName\n" ;
	my $dSymPath = $buildsReleasePath . $dSymName . ".dSYM" ;
	if ($fileUtil->existent($dSymPath)) {
		my $firstArch = 1 ;
		my $nSourceFiles ;
		foreach my $arch (@architectures) {
			my $nSourceFilesThis = 0 ;
			my $dwarfDump ;
			$_ = `/Developer/usr/bin/dwarfdump --arch=$arch -r0 "$dSymPath"` ;
			# Count the number of occurrences of the string "Compile Unit: "
			$nSourceFilesThis = s/Compile Unit: //g ;
			if (length($nSourceFilesThis) == 0) {
				$nSourceFilesThis = 0 ;
				$trouble = 1 ;
				printf "      Whoops! 0 source files dSYMed for arch=$arch.\n" ;
			}
			else {
				printf "      $nSourceFilesThis source files dSYMed for arch=$arch.\n" ;
			}

			if ($firstArch) {
				$nSourceFiles = $nSourceFilesThis ;
				$firstArch = 0 ;
			}
			elsif ($nSourceFiles != $nSourceFilesThis) {
				printf "      Whoops!  Different arch has dSYMed different count of source files.\n" ;
				$trouble = 1 ;
			}
		}
	}
	else {
		printf "      Whoops! No dSYM file for $dSymName\n" ;
		$trouble = 1 ;
	}
}

print("\n") ;

if ($trouble) {
	printf "You've got trouble with one or more dSYM files!  (See above.)\n" ;
	exit(1) ;
}

printf "All dSYM files appear to be OK.\n" ;





[1] Apple Bug 7145893

Summary: Xcode can produce empty dSYM files in normal usage. I have shipped products thinking I had dSYM files but then have been unable to symbolize.

Steps to Reproduce:

1. Create an application project containing several private frameworks, loadable code bundles, etc.
2. Set configuration to Release.
3. In the application target's Build Settings, set the Release configuration of the application project to strip the executables, and produce DWARF dSYM files.
4. Clean the target.
5. Build the target. Result: You get a stripped product, and dSYM files populated with symbols.
6. Build the application one or sometimes two more times.


Expected Results:

A stripped product, and dSYM files populated with symbols.

Actual Results: Some of the dSYM files have no symbols in them.

Notes: Sometimes you get a warning of "No debug symbols in executable" in the Build Transcript, and sometimes you don't. But this warning is not good enough anyhow. This should "just work". Here is one of the ways that this can happen: The first command to build will build and link the application, then create dSYM files, and then strip the application. The second or third build command will skip building and linking since it is up to date, but will sometimes still create one or more dSYM files which will be empty since the executables have now been stripped.

 _______________________________________________
Do not post admin requests to the list. They will be ignored.
Xcode-users mailing list      (email@hidden)
Help/Unsubscribe/Update your Subscription:

This email sent to email@hidden

  • Follow-Ups:
    • Re: Recommendations for strip(1)? Was: gdb: "No line number info...."
      • From: Alastair Houghton <email@hidden>
  • Prev by Date: Re: Strange linking problem with Objective-C++
  • Next by Date: Unexpected NSManagedObject isInserted behavior in iPhone.
  • Previous by thread: Re: ld errors when Cocoa app linking C++ via intermediate ObjC++ library
  • Next by thread: Re: Recommendations for strip(1)? Was: gdb: "No line number info...."
  • Index(es):
    • Date
    • Thread