0

I have a couple of plain C-programs (actually plugins that are dlopen()ed by some host) to compile, and I would like to support as many OSX/macOS versions as possible. The actual number supported versions of OSX/macOS are not so important, but i strive for a maximum coverage ("whatever is possible"). The C-programs virtually don't use any libraries apart from libc, and are cross-platform (linux/windows/macOS).

To achieve maximum compatibility, I use the -mmacosx-version-min flag when compiling on macOS.

In the past, I've build my binaries on macOS Sierra using -mmacosx-version-min=10.5, which used to work nicely. This flag is now hardcoded in my Makefile.

However, since I've upgraded my build machine to macOS Mojave the builds fail with:

ld: library not found for -lgcc_s.10.5

So it seems that recent versions of XCode have a minimum deployment target of OSX-10.6. Obviously I could just go and update all my Makefile's to use -mmacosx-version-min=10.6, but I guess I will have the same problem soon enough when Apple decides to ditch 10.6 support.

So my question is: is there any way to determine programmatically the minimum supported value for -mmacosx-version-min on my build host?

My build system is a very simple pure GNU make (no autotools, CMake and the like), and I'd like to keep it that way. So any check should be simple enough to be done at the beginning of the make invocation.

Ideally something like:

CFLAGS+=-mmacosx-version-min=$(shell xcodebuild --minimum-supported-version)

Ideas?

NOTE: my target build hosts are headless CI-machines, that usually will only have the "cmdline" version of the build-tools installed. Any proposed solution should run on a system that doesn't have the full XCode suite installed.

on older systems

Funnily enough, specifying a very low deployment target on Sierra was handled much more gracefully:

E.g. adding -mmacosx-version-min=10.1 would compile without a problem, creating a x86_64 binary (which iirc was only supported starting with OSX-10.4), and which - according to otool -l is only compatible with OSX-10.4.

Given that older versions of clang/Xcode/... handled out-of-bound values for -mmacosx-version-min gracefully, I wonder whether this is an actual regression bug on Apple's side.

further information

This is what the compiler on Mojave tells me about it's own version:

$ cc --version
Apple LLVM version 10.0.1 (clang-1001.0.46.4)
Target: x86_64-apple-darwin18.0.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

On Sierra (where everything works), I get:

$ cc --version
Apple LLVM version 9.0.0 (clang-900.0.38)
Target: x86_64-apple-darwin16.7.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
umläute
  • 28,885
  • 9
  • 68
  • 122
  • Is your question *So my question is: is there any way to determine programmatically the minimum supported value for -mmacosx-version-min* still open in the sense that you don't know how to determine which version supports which? Or is there only the *programmatical* way unknown? – Vroomfondel Nov 12 '19 at 12:43
  • i'm only interested in a way to **automatically** detect the *minimum supported value for -mmacosx-version-min*. – umläute Nov 12 '19 at 14:57
  • Umm, sorry to sound thick, but is the question: "I want to know the rule set that decides which version X is compatible with version Y" or is it "I want to program the rule set which I knew how formulate as program code, were it not for the clumsy syntax and restricted functionality that make offers"? – Vroomfondel Nov 12 '19 at 15:37
  • i want my makefile to automatically pass the correct flag to the compiler to produce binaries that are compatible with the largest possible range of macOS/OSX versions. i'm not sure i can fully parse your "thick question". but i usually don't have trouble with `make` syntax, but currently have no idea which runes i should run in order to calculate such a working flag for past, present and future versions of macOS/Xcode. – umläute Nov 12 '19 at 16:34
  • Maybe you want to take a look at [gmtt](https://github.com/markpiffer/gmtt) which has a working version of tabular data selection and glob patterns (the less potent cousins of regular expressions) – Vroomfondel Nov 12 '19 at 17:34
  • a well, that would require me to know which versions of XCode support which minimum deployment target beforehand. whenever a new version comes out, the table would need to be updated manually. since XCode is supposed to know which deployment targets it supports, i was hoping to be able to ask it directly. – umläute Nov 13 '19 at 08:50
  • Ok, sorry, wrote the answer before I read your comment. That would be _I want to know the rule set.._ version where gmtt will not be any help of course. – Vroomfondel Nov 13 '19 at 09:50
  • I suppose you already stumbled over this? [https://smallhacks.wordpress.com/2018/11/11/how-to-support-old-osx-version-with-a-recent-xcode/] – Vroomfondel Nov 13 '19 at 10:34

1 Answers1

0

To give you an idea what it would look like with pure make programming and gmtt as helper library:

include gmtt/gmtt.mk

#CC_VERSION_OUTPUT := Apple LLVM version 10.0.1 (clang-1001.0.46.4) \
#Target: x86_64-apple-darwin18.0.0 \
#Thread model: posix \
#InstalledDir: /Library/Developer/CommandLineTools/usr/bin

CC_VERSION_OUTPUT := Apple LLVM version 9.0.0 (clang-900.0.38) \
Target: x86_64-apple-darwin16.7.0 \
Thread model: posix \
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

CC_VERSION := $(call glob-match,$(CC_VERSION_OUTPUT),Apple LLVM version * (clang-*)*Target: *-apple-* *)

LLVM_VERSION := $(subst ., ,$(word 2,$(CC_VERSION)))
LLVM_MAJOR := $(word 1,$(LLVM_VERSION))
LLVM_MINOR := $(word 2,$(LLVM_VERSION))
CLANG_VERSION := $(word 4,$(CC_VERSION))
PLATFORM := $(word 8,$(CC_VERSION))
OS := $(word 10,$(CC_VERSION))

# Table for OSX version minimum (last column)
# platform | OS | LVM-major | LLVM-minor | OSX-version
define COMPATIBILITY_TABLE :=
5
x86_64 darwin16.7.0   9   0   10.5
x86_64 darwin18.0.0  10   0   10.6
endef

#$(info $(LLVM_MAJOR) $(LLVM_MINOR) $(OS) $(PLATFORM))

MACOSX_VERSION_MIN := $(call select,5,$(COMPATIBILITY_TABLE),$$(and $$(call str-eq,$$1,$(PLATFORM)),\
                                                                    $$(call str-eq,$$2,$(OS)),\
                                                                    $$(or $$(call int-ge,$$3,$(LLVM_MAJOR)),\
                                                                          $$(and $$(call int-eq,$$3,$$(LLVM_MAJOR)),\
                                                                                 $$(call int-ge,$$4,$(LLVM_MINOR))))))

$(info -mmacosx_version_min=$(MACOSX_VERSION_MIN))

The where-clause for the select statement is admittedly quite noisy. Depending on your assumptions you could also use $(call glob-match...).

Vroomfondel
  • 2,704
  • 1
  • 15
  • 29
  • thanks for the answer. i don't mind the noisiness of the where-clause; however this solutions requires me to collect the compatibility matrix manually (so i can hardcode it into the Makefile) *and* it parses the output of `--version` which seems to be a very brittle operation (how stable is the interface of the `--version` output? e.g. Debian's `clang` will fill most values with nonsense - just telling that the output-format of `--version` might change more than the macos-min-version...) – umläute Nov 13 '19 at 09:59
  • You can make the `glob-match` pattern quite immune to trash with extra programming. What would be the compatibility matrix (or rather part of it) that will come out of ... well which tool knows the compatibility? – Vroomfondel Nov 13 '19 at 10:03
  • well, yes...that was the question in the first place (or at least: that was, what i was attempting to ask in the first place) – umläute Nov 13 '19 at 10:09