11

In brief: does LLVM/Clang support the 'weak' attribute?

I'm learning some Arduino library sources (HardwareSerial.cpp to be more detailed) and I've found some interesting attribute weak that I've never used before:

#if defined(HAVE_HWSERIAL0)
  void serialEvent() __attribute__((weak));
  bool Serial0_available() __attribute__((weak));
#endif

I've found it interesting and I've read that the linker should set it to NULL if it's not defined.

However, in my tests with Clang I'm unable to use it.

File lib.cpp:

#include "lib.h"
#include <stdio.h>

void my_weak_func() __attribute__((weak));

void lib_func() {
    printf("lib_func()\n");

    if (my_weak_func)
        my_weak_func();
}

File lib.h:

#ifndef LIB_FUNC
#define LIB_FUNC

void lib_func();

#endif

File main.cpp:

#include "lib.h"
#include <stdio.h>

#ifdef DEFINE_WEAK
void my_weak_func() {
    printf("my_weak_func()\n");
}
#endif

int main() {

    lib_func();

    printf("finished\n");
    return 0;
}

If I use g++ lib.cpp main.cpp -o main -DDEFINE_WEAK I'm able to use it:

MBA-Anton:Weak_issue asmirnov$ ./main
lib_func()
my_weak_func()
finished

But if I use g++ lib.cpp main.cpp -o main I'm unable to link the application:

Undefined symbols for architecture x86_64:
  "my_weak_func()", referenced from:
      lib_func() in lib-ceb555.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

To be more detailed about Clang:

MBA-Anton:Weak_issue asmirnov$ g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/c++/4.2.1
Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin14.3.0
Thread model: posix

What should I do? Is the weak attribute supported by LLVM/Clang?

PS. I've already tried to rewrite lib.cpp in the way Apple describes and still get the same linker error:

#include "lib.h"
#include <stdio.h>

extern void my_weak_func() __attribute__((weak_import));

void lib_func() {
    printf("lib_func()\n");

    if (my_weak_func != NULL)
        my_weak_func();
}
4

2 に答える 2

9

どうやら (私の知る限りでは)、弱いリンクに関する Apple の説明は誤解を招くようです。リンク時に定義が実際に利用可能である場合にのみ、関数をweak/weak_importとしてマークすることに成功しました。これは、リンク時に弱くリンクされたシンボルを定義する必要がない通常の Linux の動作とは逆です。

たとえば、次のコードは GCC 4.8.2 を使用する Ubuntu 14.04 でコンパイルされますが、Clang を使用するMac OS X v10.9.5 (Mavericks)ではコンパイルされません。

/* test.c */
int weakfunc() __attribute__((weak));

int main()
{
    if (weakfunc) return weakfunc();
    else        return -1;
}

私が見つけた最も簡単な回避策は、問題のシンボルを未定義のままにするようにリンカに明示的に指示することです。たとえば、clang test.c -Wl,-U,_myfunc. C と C++ ではシンボルの名前が異なることに注意してください。C では (少なくとも私にとっては、これは一貫していると思います)、ここに示すように、シンボル名の先頭にアンダースコアが追加されています。C ++では、名前が壊れているため、次のような結果になります__Z8weakfuncv(必ずしも一貫しているわけではありません-Ubuntuボックスの壊れた名前には、先頭のアンダースコアが1つしかありません)。

このアプローチに従って、関数が実行時に定義されている場合 (たとえば、DYLD_INSERT_LIBRARIES環境変数を設定してプリロードされたライブラリを介して、または共有ライブラリの依存関係のバージョンがビルド時と実行時に異なる場合)、シンボルは解決され、必要に応じて呼び出される関数。シンボルが実行時に定義されていない場合、関数のチェックは失敗し、必要に応じて -1 を返します。

もう少し複雑な解決策は、問題の関数の実装を提供するダミー ライブラリにリンクすることです。たとえば、同じディレクトリで libdummy.dylib として次をコンパイルするとします。

int weakfunc()
{
    return 1;
}

あなたはそれに対して弱くリンクすることができます

clang test.c -weak_library ./libdummy.dylib -flat_namespace

シンボルはリンク時に定義されるため、リンカーは問題なく、結果のバイナリで弱いリンクとしてマークされます。libdummy.dylib を-weak_library標準のリンクではなくリンクすることにより-l/-L、ライブラリの依存関係自体が弱くなるため、実行時に libdummy.dylib が使用できない場合でも実行可能ファイルは実行されます。

この-flat_namespace引数は、OS X のデフォルトである「2 レベル」名前空間ではなく、「フラット」名前空間を使用するようにリンカーに指示します。 、したがって、これがないと、リンカは libdummy.dylib と呼ばれるライブラリからの weakfunc のバージョンのみを受け入れます。シンボルを未定義としてマークする最初のケースでは、そのシンボルはフラットな名前空間からのものとして扱われることに注意してください.

于 2016-01-25T00:11:24.170 に答える