Search code examples
macosassert

Where is the __eprintf symbol defined in OS X 10.11?


I am compiling some asserts with -arch i386 -isysroot /Applications/Xcode-7.2.1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk -mmacosx-version-min=10.4. Therefore, the assert code doesn't use __assert_rtn but __eprintf instead.

Relevant snippet from assert.h:

#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && ((__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__-0) < 1070)
#define __assert(e, file, line) \
    __eprintf ("%s:%u: failed assertion `%s'\n", file, line, e)
#else
/* 8462256: modified __assert_rtn() replaces deprecated __eprintf() */
#define __assert(e, file, line) \
    __assert_rtn ((const char *)-1L, file, line, e)
#endif

So far so good, except when linking time arrives, it doesn't find __eprintf. In which library is this defined ?


A way to reproduce getting __eprintf into the assert:

cat <<EOF >/tmp/x.c
#include <assert.h>


#ifdef __clang__
# if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && ((__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__-0) <= 1040)
#  if ! __DARWIN_UNIX03
#   warning "compiling for 10.4 (not __DARWIN_UNIX03), with __eprintf"
#  endif
# endif
#endif

int  xxx( int a)
{
   assert( a);
   return( a);
}
EOF

clang -E -arch i386 -mmacosx-version-min=10.4 -isysroot /Applications/Xcode-7.2.1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk -o /tmp/x.txt /tmp/x.c


Using above, make a dylib and observe the problem:

clang -c -arch i386 -mmacosx-version-min=10.4 -isysroot /Applications/Xcode-7.2.1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk -O0 -o /tmp/x.o /tmp/x.c

ld -arch i386 -macosx_version_min 10.4.0 -syslibroot /Applications/Xcode-7.2.1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk -t -o /tmp/x.dylib -ldylib1.o /tmp/x.o -lSystem -lgcc_s.10.4

These calls are destilled down from what xcodebuild produces.


Solution

  • Thanks for the helpful responses.

    The answer turns out to be /Applications/Xcode-7.2.1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/7.0.2/lib/darwin/libclang_rt.10.4.a in my particular case.

    This is a library that gets added by clang itself behind the scenes (DarwinClang::AddLinkRuntimeLibArgs). Note that this library is only for 10.4 code and seems to be tied to the compiler version.

    I don't know by which magic (don't see it in the invocation) the linker decides which compiler version it needs to link for.


    The easiest solution is to define ones own __eprintf, instead of messing around with the toolchain:

    #include <assert.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    
    #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && ((__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__-0) <= 1040)
    # if ! __DARWIN_UNIX03
    
    __attribute__((visibility("hidden")))
    void __eprintf( const char* format, const char* file, 
               unsigned line, const char *expr)
    {
       fprintf( stderr, format, file, line, expr);
       abort();
    }
    
    # endif
    #endif
    
    
    int  main( int argc, char *argv[])
    {
       assert( argc == 2);
       return( 0);
    }