charles
charles

Reputation: 11812

Remove a framework and the link to the framework after the app binary is created by Xcode

I would like to build 2 versions of the same app in Xcode, one with, and one without the Sparkle framework. I don't want to maintain a separate target. Instead, I would like to use 2 separate schemes that rely on 2 separate build configurations (well, 4 in total, as I'll use one for the debug build and one for the release build).

The problem is the 'Copy Bundle Resources' and the 'Link Binary' steps in the 'Build Phases' are the same for all the schemes on a given target, as far as I can tell.

So my only option as I see it is to run a script after the build (and before signing) that would:

  1. Remove the framework from the app bundle.
  2. Unlink the framework from the executable (as listed with ottol -L).

Any suggestions?

Upvotes: 2

Views: 2832

Answers (2)

Tulleb
Tulleb

Reputation: 9206

You can remove files / frameworks from specific builds through the EXCLUDED_SOURCE_FILE_NAMES key (also accessible from the Build Settings tab).

Prefer this to the script as it could lead to some startup crash and/or Apple warnings regarding missing libraries.

Exclude framework from build settings

Warning received from Apple

Upvotes: 0

charles
charles

Reputation: 11812

After quite a bit of work, I have come up with a solution.

  1. First, make sure the framework linking is "weak", which Xcode calls "Optional" in the 'Link Binary' phase. Also make sure that any use of Sparkle in your code handles a missing Sparkle framework.

Optional linking of framework

  1. Create separate build configurations for Debug and Release, e.g. called 'Debug-no_sparkle' and 'Release-no_sparkle', by going to the Project settings, under 'Info' in the 'Configurations' tab. Also create a corresponding scheme by going to the 'Schemes' popup menu, duplicating your normal scheme, and then using the 'no_sparkle' configurations in the various actions for the scheme.

  2. Add a 'Run Script' step to the Build phases in the target settings.

Run script phase to remove Sparkle framework

Here is the Ruby script I use:

config = ENV['CONFIGURATION']
if (config =~ /no_sparkle/)

    $stderr.puts "Removing Sparkle Framework"
    sparkle_path = "#{ENV['BUILT_PRODUCTS_DIR']}/#{ENV['FRAMEWORKS_FOLDER_PATH']}/Sparkle.framework"
    `rm -Rf "#{sparkle_path}"`

    $stderr.puts "Removing Sparkle Framework linking"
    binary_path = "#{ENV['BUILT_PRODUCTS_DIR']}/#{ENV['EXECUTABLE_PATH']}"
    `install_name_tool -change @rpath/Sparkle.framework/Versions/A/Sparkle @rpath/ "#{binary_path}"`
end

One thing I could not do is remove completely the line corresponding to the framework link with install_name_tool. I could only change it to '/' to remove any trace of it, so it would not even accidentally load if the framework was somehow accessible. It would be nice to be able to fully remove it.

Upvotes: 4

Related Questions