Problem description:
I have an Xcode workspace that references two Xcode projects. The first Xcode project (lib.xcodeproj
) builds an iOS static library while the second project (app.xcodeproj
) builds an iOS app that consumes the static library. app.xcodeproj
references lib.xcodeproj
, i.e. lib.xcodeproj
is listed in app.xcodeproj
s Link Binary With Libraries build phase.
So, the setup is as follows:
MyApp.xcworkspace
|
+-app.xcodeproj---+
| | Referenced via build phase
+-lib.xcodeproj <-+
If I open this workspace in Xcode and build an archive out of it (Product
menu ->
Archive
) everything compiles as expected and I end up with an .xcarchive
. The same applies if I build via command line (xcodebuild archive -workspace MyApp.xcworkspace ...
).
However, dumping the content of the dSYM file that is generated as part of the archive reveals that it does not contain the debugging symbols of the static library (lib.xcodeproj
). To be more specific, executing the command
dwarfdump MyApp.xcarchive\dSYMs\MyApp.app.dSYM\Contents\Resources\DWARF\MyApp > dwarfdump.txt
generates a text file that confirms that all debugging symbols of the app itself are there but the debugging symbols of the static library are not.
This only happens when creating archives. Producing a build via Product
menu ->
Build
produces a dSYM file containing all debugging symbols of the app AND the static library.
Now, this isn't exactly new. That behavior was already observed ages ago and I found three different SO posts describing the same behavior (here, here and here). However, these posts are more than 7 years ago!
What I would like to know:
How do other people create archives of apps that are using static libraries created in the same workspace?
Seems that without scripting and just with Xcode itself this is an unsolvable problem.
Analysis (for the curious reader):
I've analyzed this issue and strongly suspect it is a long lasting Xcode issue. Here's what I found:
Building the workspace via xcodebuild build -workspace MyApp.xcworkspace ...
produces the following sequence of log entries:
CompileC <static library file 1>
CompileC <static library file 2>
...
Libtool <instructions to create the static library>
...
CompileC <app file 1>
CompileC <app file 2>
...
GenerateDSYMFile <instructions to create the dSYM file>
...
CodeSign <instructions to sign the app>
Building the workspace via xcodebuild archive -workspace MyApp.xcworkspace ...
produces the following sequence of log entries:
CompileC <static library file 1>
CompileC <static library file 2>
...
Libtool <instructions to create the static library>
Strip <instructions to strip the debugging symbols from the static library>
...
CompileC <app file 1>
CompileC <app file 2>
...
GenerateDSYMFile <instructions to create the dSYM file>
Strip <instructions to strip the debugging symbols from the app>
...
CodeSign <instructions to sign the app>
From these two sequences we see that when an archive is created we get calls to the strip
tool. This tool strips out the debugging symbols from a binary. So, when the dSYM file gets created the static library simply does not contain any debugging symbols anymore.
When GenerateDSYMFile
is executed, all that is left are the debugging symbols within the app. These symbols are then also stripped. BUT they are stripped after the dSYM file already exists and not before as is the case with the static library.
Now, there are build settings designed to influence that behavior. I found the following and tested whether they have an effect:
Strip Debug Symbols During Copy
(COPY_PHASE_STRIP
): Made no difference, the sequence is unchangedStrip Linked Product
(STRIP_INSTALLED_PRODUCT
): Made no difference, the sequence is unchangedStrip Style
(STRIP_STYLE
): Changes the argument that is passed to thestrip
tool. But I cannot prevent the information from being stripped nonetheless.
So, with that information I dare to make the statement that the build process used by Xcode for this constellation is simply incorrect. The correct way would be to run GenerateDSYMFile
and only after that run strip
for the static library and the app.