2

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?

charles
  • 11,212
  • 3
  • 31
  • 46

2 Answers2

4

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.

charles
  • 11,212
  • 3
  • 31
  • 46
  • 2
    With Xcode 9 there is a simpler solution that does not involve scripts. See my original answer here: https://stackoverflow.com/a/46982763/2272561 – Stefan Vasiljevic Oct 27 '17 at 22:04
  • That sounds great! Could you post an answer here to my specific question? I am not sure how the 'exclude source' would work with frameworks, and prevent the 'Copy' phase of the build. Thanks! – charles Apr 12 '18 at 08:48
0

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

Tulleb
  • 8,919
  • 8
  • 27
  • 55