Marc Wäckerlin
Für eine libertäre Gesellschaft

Build for Old Mac OSX Versions

September 5, 2018

Views: 3150

Do you want to support Mac OSX? My recommendation: Don’t! It’s not worth the pain! Really! Apple is the worst shit in the world, especially from a developer’s point of view.

Still here? So you must support Mac, then let’s try to go through these shoals. You will see, there are many little problems to solve.

One typical problem: you cannot cross compile from Linux to MacOSX, Mac builds must be compiled on a native Apple device. So you start by buying a Mac, unless you manage to run it in a virtual machine.

You need an AppleID with developer account to  install Xcode.  Then you install the Linux- / GNU-Tools using Homebrew, so you can finally build using ./configure && make all install based on a GNU gcc, as you are used to do. Creating and signing an app and a dmg-Installer is another pain in the ass, that I won’t describe here. Finally you have a binary that runs on your Mac and you give it away, what happens? Your friend got your program, starts it and only sees an error message, stating that the his OSX version is too old to be supported by your program. So you need explicitly to build for older versions of OSX. I am currently running a build server on OSX 10.13, but the result should run at least on OSX 10.11 too. This blog describes how to do it.

Copy SDK Into Xcode

Your first step will be to install an old SDK into your current Xcode. For this you must download a whole old Xcode image, extract the SDK and manually copy it into your current Xcode app. And since Apple is so smart, you need to repeat this everytime you update Xcode.

What Version of Xcode?

Your first problem is to find out, what version of Xcode you need. Fortunately there is a table in the Wikipedia article. This tells me, that OSX 10.11 is supported by Xcode 7.3.1. So I downloaded 7.3.1 dmg from https://developer.apple.com/download/more. If you trust user phracker, you can get the SDK directly from his github project. There is also a XCodeLegacy script, which did not work for me, it did not finde the SDK.

Install 10.11 SDK in Xcode

Provided you have the Xcode 7.3.1 dmg, open it, then right-click on the Xcode package to oopen the popup-menu and chose «Show Package Contents» instead of simply «Open» it. Then open Contents / Developer / Platforms /MacOSX.platform / Developer / SDKs here you find a folder MacOSX10.11.sdk. In another finder window open Applications, then also here right-click on Xcode to «Show Package Content» and head to Contents / Developer / Platforms /MacOSX.platform / Developer / SDKs. Here you only see MacOSX10.13.sdk. So copy MacOSX10.11.sdk using drag and drop.

Enforce the use of the correct SDK:

sudo rm -rf /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk
sudo ln -s  /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk \
            /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk

Use Mac Ports Instead of Homebrew

Next problem: How to get Homebrew built for the old deployment-target? Answer: You can’t! So forget Homebrew and uninstall it! Use MacPorts, where you can set a target in macports.conf.

Install MacPorts. Run xcode-select --install to install the Xcode commandline tools and sudo xcodebuild -license to accept the license. Then edit /opt/local/etc/macports/macports.conf and append:

universal_target	 10.11
macosx_deployment_target 10.11
macosx_sdk_version       10.11

To be completely sure to build for the right target, also set export MACOSX_DEPLOYMENT_TARGET=10.11 in your .profile and in the .profile of user root.

Important: port often simply copies a binary file. To make sure, everything is correctly rebuilt, you must use the option -s to build from sources. Also make sure you don’t have unwanted caches, port clean --all all is the safest way to get rid of all old files, port uninstall installed removes everything that is already installed.

Then build something, e.g. doxygen and test it:

$ sudo port -s install doxygen
    […]
$ otool -l /opt/local/bin/doxygen \
      | grep -B1 -A3 LC_VERSION_MIN_MACOSX
Load command 9
      cmd LC_VERSION_MIN_MACOSX
  cmdsize 16
  version 10.11
      sdk 10.11

Now you can set export MACOSX_DEPLOYMENT_TARGET=10.11, build your dependencies, then append -mmacosx-version-min=10.11 to your builds.

Check

You should see only success stories when you build your dependencies and check the built binaries:

$ sudo -Hi
$ export MACOSX_DEPLOYMENT_TARGET=10.11
$ port -s -N -v install \
                qt5 boost cppunit subversion doxygen \
                wget emacs autoconf automake libtool \
                pkgconfig pkcs11-helper libproxy
$ for f in /opt/local/bin/*; do \
      if otool -l $f \
         | grep -B1 -A3 LC_VERSION_MIN_MACOSX \
         | grep -q 10.11;
      then \
          echo "success: $f"; \
      else \
          echo "* error: $f"; \
      fi;
  done

comments title