Problems with code signing to run locally

Background: I write code with Xcode purely for scientific research purposes, that runs only on my machine, never delivered as an application. I share the project and source code with a few collaborators to run on their machines only. I've done this for years. I keep Xcode up to date because the core functionality is implemented in C++ (with an Objective-C GUI) and I want to stay up-to-date on the C++ features. This is basically a simulation modeling system, which uses separate "plug-in" dylibs from separate Xcode projects for specific models. This has been working great for more than a decade!

The last few versions of Xcode and the change to the new build system have broken my projects in confusing ways. Apparently I now I have code signing problems that I didn't have before.

The software has two pieces: one is a private framework that is built and copied to ~/Library/Frameworks. The main application project uses this framework. The framework is also used by a separate project for the specific models that builds a dylib that is loaded by the main application project using the dlfcn facility.

All this has worked fine until about a year ago when I moved to the new build system. I am currently using Xcode 13.2.1 on macOS 12.2.1 Two problems seem to be involved, but I'll start with the one that is confusing me the most:

When I try to build the main application project, I get a code signing error: /Users/kieras/Documents/Programming/EPIC work/EPIC Archive/Separate EPIC Lib and App projects/EPIC App Only/DerivedData/EPIC/Build/Products/Release/EPICApp.app: code object is not signed at all

In subcomponent: /Users/kieras/Documents/Programming/EPIC work/EPIC Archive/Separate EPIC Lib and App projects/EPIC App Only/DerivedData/EPIC/Build/Products/Release/EPICApp.app/Contents/Frameworks/EPICLib.framework

Does this mean that the signing problem is with my framework project? I checked that and rebuilt it with myself as (Personal Team) and Sign to Run Locally.

However, the build on the application project fails with the same error even though I have the application project also set as (Personal Team) and Sign to Run Locally.

I looked around in the main application project build settings and found in Build Phases/Embed Frameworks an entry for the framework with a check box whose label I could not make completely visible: "Code Sign On Co...". I tried checking this box, cleaned, rebuilt and this time there was no code signing error. However, when I tried to run the project from within Xcode, I got this error appearing in the debugger window:

dyld[3318]: Library not loaded: ~/Library/Frameworks/EPICLib.framework/Versions/A/EPICLib

  Referenced from: /Users/kieras/Documents/Programming/EPIC work/EPIC Archive/Separate EPIC Lib and App projects/EPIC App Only/DerivedData/EPIC/Build/Products/Release/EPICApp.app/Contents/MacOS/EPICApp

  Reason: tried: '/Users/kieras/Documents/Programming/EPIC work/EPIC Archive/Separate EPIC Lib and App projects/EPIC App Only/DerivedData/EPIC/Build/Products/Release/EPICLib.framework/Versions/A/EPICLib' (no such file), '~/Library/Frameworks/EPICLib.framework/Versions/A/EPICLib' (no such file), '/Library/Frameworks/EPICLib.framework/Versions/A/EPICLib' (no such file), '/System/Library/Frameworks/EPICLib.framework/Versions/A/EPICLib' (no such file)

This is the second problem I've encountered in other variations of how I've set up these projects. So there are two problems: One is a code signing problem, the other is a library load problem, both of which are new to recent versions of Xcode.

Another question thread suggests that my framework project run script could be the problem. After building the framework, the script first does rm -R the old framework, and then cp -R the new framework, to the ~/Library/Frameworks directory. This script appears to run correctly.

I could revert to the legacy build system, but I believe that will disappear pretty soon and I would rather solve this problem now rather than later.

Since this will never be distributed as a complete application, I really hope I don't have to get into the whole application/app store code signing drill. Can someone help me sort this out so I can continue just building and running my code successfully on my own machine?

Thanks!

I don’t think this is related to code signing. As you said, you’ve set everything up with Sign to Run Locally, which should be all you need. Also, none of the errors you’re seeing as indicators of code signing issues.

I think your issue is specific to your use of ~/Library/Frameworks. That was on the framework search path back in the day but AFAICT that support was removed in dyld 3. In my tests, on macOS 12.2.1, if I explicitly add /Users/quinn/Library/Frameworks [1] to the framework path, by setting the DYLD_FRAMEWORK_PATH environment variable in the Xcode scheme editor, things work.

Specifically, I have a framework whose install name is a relative path:

% cd ~/Library/Frameworks 
% otool -L QFramework.framework/Versions/A/QFramework 
…
	QFramework.framework/Versions/A/QFramework …
…

And I have an app that references it via that relative path:

% cd /Users/quinn/Library/Developer/Xcode/DerivedData/QFClient-hhrbpxlhhsxazybmifbskbdhlqvq/Build/Products/Debug 
% otool -L QFClient.app/Contents/MacOS/QFClient 
…
	QFramework.framework/Versions/A/QFramework …
…

Running the app fails:

% ./QFClient.app/Contents/MacOS/QFClient 
dyld[32716]: Library not loaded: QFramework.framework/Versions/A/QFramework
  Referenced from: /Users/quinn/Library/Developer/Xcode/DerivedData/QFClient-hhrbpxlhhsxazybmifbskbdhlqvq/Build/Products/Debug/QFClient.app/Contents/MacOS/QFClient
  Reason: tried: 'QFramework.framework/Versions/A/QFramework' (no such file), '/Library/Frameworks/QFramework.framework/Versions/A/QFramework' (no such file), '/System/Library/Frameworks/QFramework.framework/Versions/A/QFramework' (no such file)
zsh: abort      ./QFClient.app/Contents/MacOS/QFClient

But running it with the environment variable works:

% DYLD_FRAMEWORK_PATH=/Users/quinn/Library/Frameworks ./QFClient.app/Contents/MacOS/QFClient

So, what to do about this? Honestly, I don’t think that setting this environment variable is a good long-term solution. Critically, it’ll fail if you run the app from the Finder.

Is there a reason you have to install the framework in ~/Library/Frameworks. My go-to technique fro this sort of thing is to create an Xcode workspace and add both my framework and the client app projects to that workspace. The workspace means that both project share the same derived data directory, so I can build my framework and my app will load it from there.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Note that ~ is expanded by the shell and so does not work in this context.

you said that ~/Library/Frameworks no longer works

Specifically, I said that ~/Library/Frameworks is no longer on the default framework search path.

But would /Users/myusername/Library/Frameworks work instead if I use it everywhere in the Xcode project?

Yes, but that’s not what I recommend. I’m happy to go into the gory details but I think we can head this off at the pass…

I am using a framework because the core of my simulation system, EPICLib, needs to be shared library because both the main app and specific model plugin dylibs, build in multiple separate Xcode project, both need to make use of the EPICLib core.

Right. And my workspace suggestion allows for that. Create a workspace and to that workspace add:

  • Your framework project

  • Your main app project

  • Any module plug-in projects you’re actively working on

This will build the framework from source the first time and then all the clients will use that built copy. No muss, no fuss, no shell scripts to install stuff.

I recommend that you prototype this with a set of test projects beforehand. That’ll give you some confidence that the technique meets your needs before you try adopting it in your main project, whose complexities will inevitably muddy the waters. And if you have problems getting it working with those test projects, their simplicity will make it easier for me to help you debug that.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I appreciate that your suggestion is a simple solution, but the problem is that it would seem that every specific model will require a complete project with its own copy of the entire core EPICLIb and EPICApp code base - a few hundred files. These files will have to be modified occasionally as new features are added, Mac-specific updates are required, or bugs fixed. How would I avoid maintenance problems with multiple copies of that large code base? My current framework structure requires exactly one copy of the EPICLib and EPICApp code base.

Please note that this isn't an ordinary development of a single application product, but rather a research system that has to support multiple specific usage situations with small plugins while maintaining a single core for the bulk of the code. .

So, could you please say more about the gory details? The crash message I provided in my original posting suggests that during application launch the ~/Library/Frameworks path I had specified was being searched. So why didn't it work?

Can my current framework structure be maintained despite these recent changes? Can you tell me which part of the massive Xcode documentation contains the relevant information? My own attempts to search have gotten lost in huge amounts of apparently irrelevant details.

My current framework structure requires exactly one copy of the EPICLib and EPICApp code base.

Understood.

it would seem that every specific model will require a complete project with its own copy of the entire core EPICLIb and EPICApp code base

No. Once you create a workspace you can add your existing projects to it; you don’t need to add each source file. So, at most you’ll need one extra workspace for each project, but in reality you could probably get away with having a single workspace and just adding or removing projects to it as you work on them.

IME workspaces are super cool for solving problems like this. However, you don’t have to take my word for it. Earlier I wrote:

I recommend that you prototype this with a set of test projects beforehand. That’ll give you some confidence that the technique meets your needs before you try adopting it in your main project

and I stand by that advice. Give that a whirl and let us know how you get along.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I decided that rather than construct some dummy projects to try out the workspace concept, I already had projects that involved all the issues to be solved. I did this in two steps:

First, I tried to fix the original approach of using the /Users framework directory. I took my original 3-separate project structure, and changed all references to my EPICLib.framework location from ~/Library/Frameworks to /Users/myusername/Library/Frameworks both in the build settings framework search paths and install directory, and the runscript in the EPICLib project. I also ensured that all projects had identical deployment target OS 12.2 and Xcode Project Document format to Xcode 13 compatible. I cleaned and rebuilt everything. Everything launched and ran correctly both within Xcode and double-clicking on the EPICApp.app.

So, as you suggested, using the full explicit search and install path for the framework looks the key to the fix.

Second, I tried your workspace suggestion. I started a new workspace and added all three of those same projects to it. I deleted the old framework from /Users/myusername/Library/Frameworks after observing that the projects were still referring to it, and for good measure, commented out the run script that copied the framework to that location. After cleaning all this up, I discovered that apparently I had to build the framework project in the workspace first, so that I could set the other two projects to reference the framework product that was now in the workspace Build directory. There appeared to be no "automatic" search of the Build products directory for it when trying to build the other two projects.

I went through all of the project settings in the workspace and cleared all of the framework search paths and framework install directory information. I checked that in the file inspector display, the framework location in the projects were set to the framework in the workspace Build directory. Once I had everything set up, I observed that in the workspace, I could build the EPICApp and it would build the EPICLib framework first, and then I could build the specific model. So apparently the dependencies were correct. I also observed that after all of the builds, all of the build products were in the same workspace Build directory.

However, when I tried to run EPICApp either from within Xcode or by double-clicking on the EPICApp.app, I go the same "can't find it" type of error as before:

dyld[3816]: Library not loaded: /EPICLib.framework/Versions/A/EPICLib Referenced from: /Users/kieras/Documents/Programming/EPIC work/EPIC System/DerivedData/EPIC/Build/Products/Release/EPICApp.app/Contents/MacOS/EPICApp Reason: tried: '/Users/kieras/Documents/Programming/EPIC work/EPIC System/DerivedData/EPIC/Build/Products/Release/EPICLib' (no such file), '/usr/lib/system/introspection/EPICLib' (no such file), '/EPICLib.framework/Versions/A/EPICLib' (no such file), '/usr/local/lib/EPICLib' (no such file), '/usr/lib/EPICLib' (no such file)

Note that the first tried place looks like the workspace Build directory that contains the .app, and the .framework

So at best, it looks like the workspace setup is at least as finicky as the setup using /Users/myusername/Library/Frameworks.
Can you tell me what I missed? Did I need to set the frame install directory to the Build products directory, and likewise the framework search paths?

dyld[3816]: Library not loaded: /EPICLib.framework/Versions/A/EPICLib

Well, that’s not good. For some reason the client of the EPICLib framework has encoded an absolute path to the framework, and the framework does not exist at that path. I’m not sure how that happened. It’s probably related to one of the install name build settings on the framework itself (LD_DYLIB_INSTALL_NAME and DYLIB_INSTALL_NAME_BASE).

I decided that rather than construct some dummy projects to try out the workspace concept, I already had projects that involved all the issues to be solved.

This was a mistake IMO. Constructing a test setup has a bunch of benefits:

  • It speeds up your turnaround time because the resulting projects are tiny.

  • It isolates you from any existing oddities in your current projects.

  • It results in a working example that gives you the confidence to proceed.

  • If you get stuck, you can compare the working example to your test setup.

  • It makes it easier to ask for help, because folks can replicate your test setup without needing your entire project.

With that in mind, here’s what I did today:

  1. Using Xcode 13.2.1 on macOS 12.2.1, I created an app project, Test701261, from the macOS > App template.

  2. I then created a framework project, Framework701261, frame the macOS > Framework template.

  3. I closed both projects.

  4. I created a workspace, Work701261.

  5. I added both projects to the workspace.

  6. I selected the app scheme and ran that. It run successfully, which is not a surprise because I’ve not made any changes yet.

  7. I switched to the framework scheme.

  8. I added an FFTest class to the framework. I then added this code to the implementation:

    + (void)test {
        NSLog(@"+[FFTest test]");
    }
    

    and a matching declaration to the header.

  9. I marked its header as public.

  10. I added an include for that header to Framework701261.h.

  11. I built the framework, just to check that steps 8 through 10 worked (the first time around I was missing a semicolon :-).

  12. I switched back to the app scheme.

  13. In ViewController.m, I added this to the top:

    @import Framework701261;
    

    and this to the -viewDidLoad method:

    [FFTest test];
    
  14. I chose Product > Run. The app ran and printed:

    2022-03-03 10:49:31.873524+0000 Test701261[60437:10208029] +[FFTest test]
    
  15. Breaking into the debugger, I did the following:

    2022-03-03 10:57:31.074497+0000 Test701261[60599:10213265] +[FFTest test]
    (lldb) image list 
    [  0] 69F0276A-3FF7-3795-A4B7-D392F4C0F4FE 0x0000000102ca0000 
        /Users/quinn/Library/Developer/Xcode/DerivedData/
        Work701261-ajnjughmnvhknlfpmjufqukvfxbm/Build/Products/Debug/
        Test701261.app/Contents/MacOS/Test701261 
    …
    [  9] 8938BFEE-FCB0-3A73-86D6-59D9E25AC9FF 0x0000000102dc6000 
        /Users/quinn/Library/Developer/Xcode/DerivedData/
        Work701261-ajnjughmnvhknlfpmjufqukvfxbm/Build/Products/Debug/
        Framework701261.framework/Versions/A/Framework701261 
    …
    

    As you can see, both the app and the framework loaded from the workspace’s build directory.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Problems with code signing to run locally
 
 
Q