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

时间:2016-03-14 21:31:01

标签: macos assert

我正在用-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

  

这些调用是从xcodebuild生成的内容中逐渐减少的。

1 个答案:

答案 0 :(得分:1)

感谢您提供的有用回复。

在我的特定情况下,答案结果为/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代码,并且似乎与编译器版本相关联。

我不知道哪个魔术(在调用中没有看到它)链接器决定它需要链接哪个编译器版本。

最简单的解决方案是定义自己的__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);
}