MacOS doesn’t support static binaries

clang -static -g -o dump1090 dump1090.o anet.o -L/tmp/rtl-sdr/build/src/ -L/usr/homebrew/Cellar/libusb/1.0.9/lib/ -lrtlsdr -lpthread -lm
ld: library not found for -lcrt0.o
clang: error: linker command failed with exit code 1 (use -v to see invocation)

/sadtrombone. Or what’s the emotion for “Apple’s kernel team is laughing at you”?

Apple has a reasonable explanation:

A statically linked binary assumes binary compatibility at the kernel system call interface, and we do not make any guarantees on that front. Rather, we strive to ensure binary compatibility in each dynamically linked system library and framework.

So basically they moved the guarantee of compatibility from the kernel interface down into the library interfaces. I guess that sort of makes sense, only it’s different from every other Unix ever and makes simple things hard. Too bad. I have some 10 year old Linux binaries I can still run because I thought to statically link them at the time.

Next best thing is to statically link everything but the system library.

$ otool -L dump1090
dump1090:
	/tmp/rtl-sdr/build/src/librtlsdr.0.dylib (compatibility version 0.0.0, current version 0.0.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)

OK, so librtlsdr was dynamically linked. I’m not sure how to tell clang to statically link just this library. I bashed around listing .a files on the linker command line and ended up here:

$ clang -g -o dump1090 dump1090.o anet.o /tmp/rtl-sdr/build/src/librtlsdr.a /usr/homebrew/Cellar/libusb/1.0.9/lib/libusb-1.0.a
Undefined symbols for architecture x86_64:
  "_CFDictionaryCreateMutable", referenced from:
      _usb_setup_device_iterator in libusb-1.0.a(libusb_1_0_la-darwin_usb.o)
  "_CFDictionarySetValue", referenced from:
      _usb_setup_device_iterator in libusb-1.0.a(libusb_1_0_la-darwin_usb.o)
...
  "_objc_registerThreadWithCollector", referenced from:
      _event_thread_main in libusb-1.0.a(libusb_1_0_la-darwin_usb.o)

Apparently linking by naming the .a suppresses the linker’s walking of library dependencies, so now I’m not getting some of the basic system stuff expected by libusb. I tried exploring what libraries were needed with otool -l and failed. I’m doing this wrong.