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.xcodeprojs 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 (Productmenu -> 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, - https://stackoverflow.com/q/16692923 here, - https://stackoverflow.com/q/11531560 and here). - https://stackoverflow.com/q/12501960 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:
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 unchanged
Strip Linked Product (STRIP_INSTALLED_PRODUCT): Made no difference, the sequence is unchanged
Strip Style (STRIP_STYLE): Changes the argument that is passed to the strip 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.
Post
Replies
Boosts
Views
Activity
I have a simple Xcode project that contains a single C++ class. However, when I attempt to build that project in Xcode I'm getting the following error message:
error: unable to spawn process
'/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang'
(No such file or directory) (in target 'iOSStaticLibrary' from project
'iOSStaticLibrary')
In addition, the following warning is emitted:
warning: Could not read serialized diagnostics file: error("Failed to
open diagnostics file") (in target 'iOSStaticLibrary' from project
'iOSStaticLibrary')
I couldn't figure out how to attach the actual project to my post. It only consists of 3 files, so, I'm posting the relative filenames and contents below.
In order to recreate the problem, create the 3 files in the specified folder and add the corresponding content.
File "ARM64/Debug/iOSStaticLibrary.xcodeproj/project.pbxproj":
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
3b051b2877334f3891e05fbf /* iOSStaticLibrary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 810f8ddb516f4fd9aae95391 /* iOSStaticLibrary.cpp */; settings = {COMPILER_FLAGS = "-c -Wall -Wswitch -W\"no-deprecated-declarations\" -W\"empty-body\" -W\"bool-conversion\" -W\"constant-conversion\" -W\"shorten-64-to-32\" -W\"enum-conversion\" -W\"int-conversion\" -W\"return-type\" -Wparentheses -W\"no-pointer-sign\" -W\"no-format\" -Wuninitialized -W\"unreachable-code\" -W\"unused-function\" -W\"unused-value\" -W\"unused-variable\" -O0 -fno-strict-aliasing -fwritable-strings -fno-threadsafe-statics -fno-exceptions -std=gnu11 -x c"; }; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
0e5228c6fe3a40ef9446f1d3 /* libiOSStaticLibrary.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libiOSStaticLibrary.a; sourceTree = BUILT_PRODUCTS_DIR; };
810f8ddb516f4fd9aae95391 /* iOSStaticLibrary.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = iOSStaticLibrary.cpp; path = ../../../iOSStaticLibrary.cpp; sourceTree = SOURCE_ROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
c8f1fdfa1a1a4cf2af0a7098 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
20adea7cddb14f79ab5df50b /* Products */ = {
isa = PBXGroup;
children = (
0e5228c6fe3a40ef9446f1d3 /* libiOSStaticLibrary.a */,
);
name = Products;
sourceTree = SOURCE_ROOT;
};
cb87a76375d04d85a8368aa7 = {
isa = PBXGroup;
children = (
810f8ddb516f4fd9aae95391 /* iOSStaticLibrary.cpp */,
20adea7cddb14f79ab5df50b /* Products */,
);
sourceTree = "\"<group>\"";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
3488e49fcf514802b7be61b6 /* iOSStaticLibrary */ = {
isa = PBXNativeTarget;
buildConfigurationList = 67256f7dc92b42baa13ec8d3 /* Build configuration list for PBXNativeTarget "iOSStaticLibrary" */;
buildPhases = (
7baf7bfde3004dd493908ddd /* Sources */,
c8f1fdfa1a1a4cf2af0a7098 /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = iOSStaticLibrary;
productName = iOSStaticLibrary;
productReference = 0e5228c6fe3a40ef9446f1d3 /* libiOSStaticLibrary.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
ee73158d3505468a8fdc43b9 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0610;
ORGANIZATIONNAME = MyOrganizationName;
TargetAttributes = {
3488e49fcf514802b7be61b6 = {
CreatedOnToolsVersion = 6.1;
};
};
};
buildConfigurationList = 33fd7959eb644d189bbaa7f7 /* Build configuration list for PBXProject "iOSStaticLibrary" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
English,
en,
);
mainGroup = cb87a76375d04d85a8368aa7;
productRefGroup = 20adea7cddb14f79ab5df50b /* Products */;
projectDirPath = "\n\n				";
projectRoot = "\n\n				";
targets = (
3488e49fcf514802b7be61b6 /* iOSStaticLibrary */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
7baf7bfde3004dd493908ddd /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
3b051b2877334f3891e05fbf /* iOSStaticLibrary.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
1cbb1a8c7cbf4c2699369b65 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
};
name = Debug;
};
fda96981947c4c2cb659f3e3 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_CXX_LIBRARY = "libc++";
IPHONEOS_DEPLOYMENT_TARGET = 8.1;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
};
name = Debug;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
33fd7959eb644d189bbaa7f7 /* Build configuration list for PBXProject "iOSStaticLibrary" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1cbb1a8c7cbf4c2699369b65 /* Debug */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Debug;
};
67256f7dc92b42baa13ec8d3 /* Build configuration list for PBXNativeTarget "iOSStaticLibrary" */ = {
isa = XCConfigurationList;
buildConfigurations = (
fda96981947c4c2cb659f3e3 /* Debug */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Debug;
};
/* End XCConfigurationList section */
};
rootObject = ee73158d3505468a8fdc43b9 /* Project object */;
}
File "iOSStaticLibrary.h"
class iOSStaticLibrary
{
public:
		iOSStaticLibrary();
		~iOSStaticLibrary();
};
File "iOSStaticLibrary.cpp":
#include "iOSStaticLibrary.h"
iOSStaticLibrary::iOSStaticLibrary()
{
}
iOSStaticLibrary::~iOSStaticLibrary()
{
}
My assumption is that something in the project.pbxproj is not as it should be. This file is generated by a code generator, not by Xcode itself so that might well be the case.
However, for the life of me I cannot figure out what's wrong.