Jaanus
Jaanus

Reputation: 17856

Why does Xcode behavior of copying embedded framework headers differ across targets?

I am working on a Mac project that has two build targets. One of my users reported being unable to install one of the targets.

Installation problem

Okay, let’s check it with RB App Checker Lite.

Validation result

Interesting. There’s some resources missing from this target, let’s call it Example 2. Just to be sure, I checked the other target, Example 1 and that one didn’t have any validation problems.

So the targets are different as it relates to copying the headers embedded in HockeySDK/CrashReporter framework. The code signature expects these headers to be there, but they’re not, and the signature validation fails.

I also checked the bundles on disk. Sure enough, the headers are there in Example 1 but not Example 2.

My next question was, why are the targets built differently? Why does Example 1 include the headers and Example 2 doesn’t? I looked into the build logs of the targets, and sure enough, there’s a difference in the “Copy frameworks” phase.

Example 1 log:

PBXCp Libraries/HockeySDK-Mac/HockeySDK.framework /Users/jaanus/Library/Developer/Xcode/DerivedData/Example-chptxdrwwlafgodccbiqclccqjkl/Build/Intermediates/ArchiveIntermediates/Example\ 1/InstallationBuildProductsLocation/Applications/Example\ 1.app/Contents/Frameworks/HockeySDK.framework
    cd /Users/jaanus/dev/Example/tool
    builtin-copy -exclude .DS_Store -exclude CVS -exclude .svn -exclude .git\
    -exclude .hg -resolve-src-symlinks /Users/jaanus/dev/Example/tool/Libraries/HockeySDK-Mac/HockeySDK.framework /Users/jaanus/Library/Developer/Xcode/DerivedData/Example-chptxdrwwlafgodccbiqclccqjkl/Build/Intermediates/ArchiveIntermediates/Example\ 1/InstallationBuildProductsLocation/Applications/Example\ 1.app/Contents/Frameworks

Example 2 log:

PBXCp Libraries/HockeySDK-Mac/HockeySDK.framework /Users/jaanus/Library/Developer/Xcode/DerivedData/Example-chptxdrwwlafgodccbiqclccqjkl/Build/Intermediates/ArchiveIntermediates/Example\ 2/InstallationBuildProductsLocation/Applications/Example\ 2.app/Contents/Frameworks/HockeySDK.framework
    cd /Users/jaanus/dev/Example/tool
    builtin-copy -exclude .DS_Store -exclude CVS -exclude .svn -exclude .git\
    -exclude .hg -exclude Headers -exclude PrivateHeaders -resolve-src-symlinks /Users/jaanus/dev/Example/tool/Libraries/HockeySDK-Mac/HockeySDK.framework /Users/jaanus/Library/Developer/Xcode/DerivedData/Example-chptxdrwwlafgodccbiqclccqjkl/Build/Intermediates/ArchiveIntermediates/Example\ 2/InstallationBuildProductsLocation/Applications/Example\ 2.app/Contents/Frameworks

Sure enough, the example 2 builtin-copy command contains the extra arguments -exclude Headers -exclude PrivateHeaders which are causing the headers to not be included.

Now, the question is, why does building one target exclude the headers and the other doesn’t?

I’ve reviewed the build settings of the targets over and over and the look as identical as can be to me. There doesn’t seem to be a way for me to influence the behavior of builtin-copy. But obviously, something is influencing it.

I fixed it for now using an ugly workaround that I don’t like. I’d really like to understand what’s going on here and how to fix this.

My Xcode version is 6.1.1 (6A2008a), the one that’s currently available from App Store.

Upvotes: 4

Views: 1448

Answers (1)

sunil
sunil

Reputation: 601

Xcode is very selective about what it decides to show you, so when it comes to investigating a problem like this the first step is to look at the project.pbxproj file by hand.

Opening up Example 1.xcodeproj/project.pbxproj and navigating to the instruction to copy the framework (I search for "Copy Framework Files"), you'll see something like:

BCAC434BC9F0E2F78087CA01 /* HockeySDK.framework in Copy Framework Files */ = {isa = PBXBuildFile; fileRef = BCAC434BC9F0E2F78087CA01 /* HockeySDK.framework */; };

And the analogue in Example 2.xcodeproj/project.pbxproj:

F19543FC17EC99FB62CA62C8 /* HockeySDK.framework in Copy Framework Files */ = {isa = PBXBuildFile; fileRef = F19543FC17EC99FB62CA62C8 /* HockeySDK.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };

From there, it's clear. Example 2's copy instruction has some additional settings after it:

settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); };

So to "fix" the problem you can just add or remove the RemoveHeadersOnCopy setting as required.

Unfortunately, this is not reflected in the UI. It seems some versions of Xcode will just add it in (and I suspect it's related to the Code Sign checkbox, but I couldn't reproduce anything worthy of mentioning).

Upvotes: 4

Related Questions