Code signing errors when exporting from archive in Xcode

Ah, code signing. Bane of modern software development!

I’m really struggling to figure out how to distribute a VST3 using Xcode. In this case, the software is a DAW/looper which works standalone and as a VST3, and I’m intending to distribute the app with the VST3 contained within the app bundle, linked to a shared framework that also resides within the app’s bundle, and symlinked from the user’s Library/Audio/Plug-Ins/VST3 folder on first run of the standalone version.

This is all working just peachy in a development environment, with code signing in place, but I’m hitting a wall trying to export the damn thing, from Xcode’s Organiser.

“Archive” is working just fine, and drops the built product in Archives. But trying to use “Distribute App” to export using “Developer ID” is throwing up an error: The operation couldn’t be completed. (DVTFoundation.DVTCodeSignerError error 0.). Looking in the logs reveals the culprit:

codesign output: .../TestApp.app/Contents/PlugIns/helloworld.vst3: replacing existing signature .../TestApp.app/Contents/PlugIns/helloworld.vst3: code object is not signed at all In subcomponent: /private.../TestApp.app/Contents/PlugIns/helloworld.vst3/Contents/moduleinfo.json

I’ve created this test build environment using the VST3 examples:

  1. I created an Xcode build setup using the provided VST3 Project Generator
  2. I opened the “vstsdk.xcodeproj” project in Xcode, then created a new target, an app called “TestApp” (FYI I had to modify the “Code Signing Entitlements” build setting as the project root was set to the VST SDK folder).
  3. I added the “helloworld” sample as a build dependency in “Build Phases”
  4. I added a new Copy Files phase, targeted at the “PlugIns” folder, and added “helloworld.vst3”

Then, I built using “Archive”, which completed and opened the Archives window. Clicked “Distribute App”, then selected “Developer ID”, and “Export”, and that’s where the error appears.

It seems that the re-signing which Xcode does on export is totally oblivious to the moduleinfo.json file that lives in the top directory of the VST, and it just doesn’t know what to do with it, even if it is already code-signed. I think files in the “Resources” folder of a bundle are automatically signed as expected, but anything that lies outside that (and perhaps a few other specific folders) cause the whole process to fall in a heap.

Unfortunately, it seems that one must jump through this hoop if one wants to make use of Apple’s notarisation service (and I’m pretty sure I’m going to need that).

So: Any hints, here? Anyone else come up against this? Is that moduleinfo.json strictly necessary? Can it be moved to the Resources folder instead? Any other solutions I’ve missed?

Many thanks.

I think I’ve got it. I found an Apple tech note on code signing, with the following at the bottom:

I can’t change where my data files are stored without significantly changing my code.

  • You can work around this by moving the files to the correct locations and leave behind symlinks so your code can still find the files.
  • Then fix your code, and remove the symlinks as soon as possible.

By generating moduleinfo.json in the Contents/Resources folder rather than the top-level Contents folder, and then creating a symbolic link from the Contents folder, the code signing system seems to be now behaving as expected, and the resulting VST seems to load correctly in hosts.

I’m using the following in a Run Script build phase:

MODULEINFOTOOL="${BUILT_PRODUCTS_DIR}/moduleinfotool"

"${MODULEINFOTOOL}" -create -version "${MARKETING_VERSION} (${CURRENT_PROJECT_VERSION})" -path "${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}" -output "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/moduleinfo.json"
cd "${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}"
[ -e moduleinfo.json ] && rm moduleinfo.json
ln -s Resources/moduleinfo.json .

If this seems like an acceptable solution, it may be worth revising the SDK’s Xcode project generator to adopt this technique to avoid future shenanigans for others.