Backport library that supplies missing-on-old-macOS symbols and ObjC selectors, so applications built against modern SDKs can still load and run on legacy systems (Mavericks 10.9 onward).
Pairs well with macports-legacy-support which handles a different layer (POSIX/libc/Darwin headers and helpers). RCS specifically covers:
- Modern ObjC ABI fast-paths (
objc_alloc_init,objc_opt_new, etc.) - Compiler-emitted runtime helpers (
__availability_version_check) - libc++ low-level ulock primitives (
__ulock_wait2,__ulock_wake) - Tracing/logging APIs (
os_log_create,os_signpost_*) - Quality-of-Service APIs (
pthread_get_qos_class_np, etc.) - C++17 typeinfo/vtable for
std::bad_variant_access,std::bad_optional_access - ObjC selector backports via
+loadcategories
make # x86_64, deployment 10.9
make ARCHS="x86_64 arm64" # universal
make DEPLOYMENT_TARGET=10.7 # bump back further
make CC=/opt/local/bin/clang-mp-19 # MacPorts clang
make SHARED=no # only static archive
make print-config # show resolved variables
make test # run smoke testsOutputs land in build/: libRedlanceCompatShims.a and
libRedlanceCompatShims.dylib.
make install PREFIX=/opt/local
make install PREFIX=/opt/local DESTDIR=/tmp/staging # for packagersEvery shim is gated by an #if RL_RCS_DEPLOYMENT < <version> guard.
The RL_RCS_DEPLOYMENT macro is defined by the Makefile from the
DEPLOYMENT_TARGET variable in standard form (e.g. 10.9 → 100900,
10.14.4 → 101404). On systems where the symbol exists natively,
no code is emitted.
Sources:
src/objc-abi-shims.m — objc_alloc, objc_alloc_init, objc_opt_new, ...
src/availability-check.c — __availability_version_check via sysctl
src/ulock.c — __ulock_wait2, __ulock_wake (no-op fallback)
src/filesystem-shims.c — renameatx_np
src/os-log.c — os_log_create, os_signpost_* (no-op)
src/qos.c — pthread_*_qos_*_np (no-op, return DEFAULT)
src/cxx17-polyfill.cpp — std::bad_variant_access, std::bad_optional_access
src/NSToolbarItemGroup+Compat.m — example +load category backport
| Symbol | Native since | Source |
|---|---|---|
objc_alloc |
10.10 | objc-abi-shims.m |
objc_allocWithZone |
10.10 | objc-abi-shims.m |
objc_opt_new |
10.10 | objc-abi-shims.m |
objc_unsafeClaimAutoreleasedReturnValue |
10.11 | objc-abi-shims.m |
objc_alloc_init |
10.14.4 | objc-abi-shims.m |
qos_class_self |
10.10 | qos.c |
pthread_get_qos_class_np |
10.10 | qos.c |
pthread_override_qos_class_*_np |
10.10 | qos.c |
os_log_create |
10.12 | os-log.c |
__ulock_wake |
10.12 | ulock.c |
renameatx_np |
10.12 | filesystem-shims.c |
os_signpost_* |
10.14 | os-log.c |
std::bad_variant_access |
10.14 libc++ | cxx17-polyfill.cpp |
std::bad_optional_access |
10.14 libc++ | cxx17-polyfill.cpp |
__availability_version_check |
10.15 | availability-check.c |
__ulock_wait2 |
11.0 | ulock.c |
For the ObjC ABI / C / C++ shims (anything with C-callable symbols), normal static linkage is enough. The linker picks them up through unresolved references just like any other library.
For ObjC +load categories (currently NSToolbarItemGroup+Compat.m),
you MUST use -force_load because there are no C symbol references that
could pull the .o in:
clang myapp.m -framework AppKit -framework Foundation \
-Wl,-force_load,/opt/local/lib/libRedlanceCompatShims.a \
-o myappIn Kotlin/Native (Gradle):
binaries.all {
linkerOpts(
"-Wl,-force_load,/opt/local/lib/libRedlanceCompatShims.a",
)
}For a missing C function: add to an existing .c file (or create one),
wrap in #if RL_RCS_DEPLOYMENT < <version> based on when it appeared
natively, mark exported via __attribute__((visibility("default"))).
For a missing ObjC selector on an existing class: add a category file
under src/. Inside +load, do class_respondsToSelector check,
then class_addMethod with the right type encoding.
For a missing class entirely: harder — see project docs.
MIT.