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:
>
> https://github.com/macports/macports-ports/pull/8259
>
> 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.