Symbol not found: _getentropy with Xcode 8 on macOS 10.11 El Capitan
Tested with gnutls 3.4.15 and 3.4.16 but affects all versions that use getentropy.
The gnutls build succeeds with Xcode 8 on macOS 10.11 El Capitan, but the resulting binary fails at run-time on the same system. Note that it's perfectly fine with Xcode 8 on macOS 10.12 Sierra.
Full build log here: https://gist.githubusercontent.com/ilovezfs/17c599f7e147384b55b0d8a8fff77440/raw/8e85dd6acc9e60496770c4ccfa90247b93b0ab31/gistfile1.txt
The error is
"dyld: lazy symbol binding failed: Symbol not found: _getentropy"
==> /usr/local/Cellar/gnutls/3.4.15/bin/gnutls-cli --version
dyld: lazy symbol binding failed: Symbol not found: _getentropy
Referenced from: /usr/local/Cellar/gnutls/3.4.15/lib/libgnutls.30.dylib
Expected in: /usr/lib/libSystem.B.dylib
dyld: Symbol not found: _getentropy
Referenced from: /usr/local/Cellar/gnutls/3.4.15/lib/libgnutls.30.dylib
Expected in: /usr/lib/libSystem.B.dylib
Error: gnutls: failed
Apple moved to a unitary SDK model a year ago with Xcode 7. Xcode 8 runs on 10.11 and 10.12. It has only a single SDK. You set the MACOSX_DEPLOYMENT_TARGET in order to specify which version of macOS you're building for.
The underlying cause of the bug reported in this issue is the SDK's weak symbols:
iMac-TMP:~ joe$ cd /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs
iMac-TMP:SDKs joe$ grep 'weak$os10.11' MacOSX.sdk/usr/lib/system/libsystem_c.tbd
symbols: [ '$ld$weak$os10.11$_basename_r', '$ld$weak$os10.11$_clock_getres',
'$ld$weak$os10.11$_clock_gettime', '$ld$weak$os10.11$_clock_settime',
'$ld$weak$os10.11$_dirname_r', '$ld$weak$os10.11$_getentropy',
'$ld$weak$os10.11$_mkostemp', '$ld$weak$os10.11$_mkostemps',
iMac-TMP:SDKs joe$
So it's defined but not actually available on 10.11, and you won't find that out at build time unless you pass -no_weak_imports
in LDFLAGS. (Note that you can't easily do that because that flag is not supported on earlier versions of Xcode, including the CLT 7.3.1 which is the latest available for 10.11. So even if Xcode 8 is installed, using -no_weak_imports
can still fail, which is a case you have to be prepared to handle if you use that flag.)
But assuming you don't pass -no_weak_imports
it will find getentropy is defined in /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/random.h
and compile, but then crash at run time. So a somewhat more robust approach is to check that it both builds and executes, since simply successfully compiling does not mean you actually have the symbol available at run-time anymore.
I can work around the issue with this ridiculous hack:
# dyld: lazy symbol binding failed: Symbol not found: _getentropy
if MacOS.version == "10.11" && MacOS::Xcode.installed? && MacOS::Xcode.version >= "8.0"
inreplace "configure", "getentropy(0, 0);", "undefinedgibberish(0, 0);"
end
or deleting D["HAVE_GETENTROPY"]=" 1" from config.status after configure runs, and then re-running ./config.status.