OS X 10.11 中定义的 __eprintf 符号在哪里?

Where is the __eprintf symbol defined in OS X 10.11?

我正在用 -arch i386 -isysroot /Applications/Xcode-7.2.1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk -mmacosx-version-min=10.4 编译一些断言。因此,断言代码不使用 __assert_rtn,而是使用 __eprintf

来自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

到目前为止一切顺利,除了链接时间到了,它没有找到 __eprintf。这是在哪个库中定义的?


一种将 __eprintf 重现为 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


利用上面的方法,制作一个dylib并观察问题:

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.

感谢您提供有用的回复。

在我的具体情况下,答案是 /Applications/Xcode-7.2.1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/7.0.2/lib/darwin/libclang_rt.10.4.a

这是一个由 clang 自己在幕后添加的库 (DarwinClang::AddLinkRuntimeLibArgs)。请注意,此库仅适用于 10.4 代码,并且似乎与编译器版本相关。

我不知道 linker 是通过什么魔法(在调用中看不到)来决定它需要 link 的编译器版本的。


最简单的解决方案是定义自己的 __eprintf,而不是乱用工具链:

#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);
}