macosx_deployment_target - building for previous versions from MacOS 10.13

Ryan Schmidt ryandesign at
Thu Sep 3 15:58:42 UTC 2020

On Sep 2, 2020, at 10:48, Friedrich Beckmann wrote:

> i use macports to build a MacOS application bundle for the pspp statistics software. I build on my Macbook with MacOS 10.13 and XCode 10.1. The idea is that the bundle can run also on previous MacOS versions. I do this by setting the macosx_deployment_target to 10.8 in macports.conf. As this usually gives problems with some ports, e.g. now rust:
> I switched to the plan to only compile the library dependencies of pspp with a different deployment target. So I install everything with no deployment target, then I force uninstall some ports, enable deployment target and install those ports again. So I try to avoid to compile build time dependencies like gimp and rust with a different deployment target. This seems to work.
> Now I wanted to go further down and set the deployment target to 10.5. It seems that the XCode 10.1 compiler then does not compile C++ anymore, e.g. when compiling ncurses. Does anybody know some description or a strategy how to compile for previous MacOS versions with macports? 
> Can I for example compile with a GNU gcc compiler and the deployment target is still honoured?

You're right that MacPorts supports setting macosx_deployment_target in macports.conf, but we don't advertise that in the documentation, very few people try to use that, and there are probably many ports that don't honor that setting. (Many ports' build system set the deployment target themselves. When we notice this we try to fix it, but there are many such instances that we probably haven't noticed yet.)

Even assuming all of the ports you care about do support propagating the deployment target properly, if the software in question includes C++ software then you have the problem of the C++ standard library. Apple started providing a new C++ standard library -- LLVM's libc++ -- in OS X 10.7 and made it the default in OS X 10.9. Prior to that, the C++ library was GCC 4.2.1's libstdc++, and it didn't support C++11. Many ports now require C++11 or newer, so to make it easier to build those on older systems, MacPorts switched to using libc++ on 10.6-10.8 last year. 10.6 didn't ship with libc++, so we provide a copy in the libcxx port.

If you want to distribute an installer containing MacPorts-compiled software targeting 10.7 or later, no problem. Any C++-using software will use the system's libc++.

If you're targeting 10.6 or earlier, slight problem: you have to bundle libc++ and install it into /usr/lib. If there's already one there with the same major version (maybe installed by the user's MacPorts installation) it might be best not to replace it if the one that's already there has a newer minor version. You could possibly determine library versions by looking at line 2 of the output of "otool -L /usr/lib/libc++.dylib": The number in the filename is the major library version (e.g. libc++.1.dylib is major version 1) and the "current version" is the minor library version.

If you're targeting 10.5 or earlier, and you're only targeting Intel, that may work. I believe we have some success getting libc++ installed on 10.5 Intel. 10.5 PowerPC is probably not possible; I don't think we have libc++ installable for PowerPC yet, and clang doesn't generate PowerPC code.

Trying to use older gcc, like gcc 4.2.1 available on 10.5 or in the apple-gcc42 port, to compile for 10.5 is probably not going to work. Since it uses libstdc++, it's not C++11 compatible, which would be a problem in case any of the dependencies of the software you want to package use C++11 or newer. Using a newer gcc from MacPorts that has a libstdc++ that understands C++11 could conceivably work, but ports are not generally written to accommodate the user picking a random compiler and may make incorrect decisions if you do this. I believe newer gcc can be told to use libc++ instead of libstdc++ but MacPorts has not been designed with any support for this.

There is also the problem of the SDK. If you build using a newer SDK, software (especially software not written specifically for macOS) that is not aware of how Apple's SDKs work may inadvertently find and use symbols in the SDK that are not available on older systems, so the executable won't actually work on older systems. Ideally the software would be fixed to become aware of SDKs, by weak-linking to symbols available in the SDK but not on the target system and checking for their existence at runtime. If that's not possible, you can build using an older SDK, but that may not work on newer systems; you may have to build on an older system to do that.

I've given a little thought recently to how best to package software so it's available to the widest userbase possible (though my thoughts here do not include consideration of the C++ problem). What I came up with is that I would provide two packages: one for 32-bit 10.6 and older (built for ppc and i386 probably on a machine running 10.6 or older, with as old a deployment target as you need or can build for, e.g. 10.5, or 10.4, or 10.4 on i386 and 10.3 on ppc), and another for 64-bit 10.6 and newer (built for x86_64 and arm64 on a machine running 10.15 or newer, with as old a deployment target as you need or can build for, e.g. 10.6 on x86_64 and 11.0 on arm64).

You might think you could build a smart installer pkg that contains both of the aforementioned components and picks the right one when the installer is run. The problem is that pkg formats changed, with the flat pkg format that we now prefer having been introduced in 10.5, but missing some key features until 10.6, such that MacPorts for example distributes its own installers as a flat pkg from 10.6 onward but uses a non-flat pkg on a dmg for 10.5 and 10.4.

If you only care about 64-bit or building 32-bit doesn't work, you could do a single package that works down to 10.5. Can't go down to 10.4 because although 10.4 ran on 64-bit processors, some of the OS wasn't 64-bit yet, so trying to run a universal i386/x86_64 executable on 10.4 will pick the x86_64 slice and it will fail to launch.

More information about the macports-users mailing list