在macos sierra上使用gcc和clang的链接器错误

时间:2017-10-31 20:27:03

标签: macos gcc clang

我必须将带有 g ++ 6.4.0 (Homebrew g ++ - 6)的c ++代码编译成静态库,然后将其封装到C静态库(Homebrew gcc-6)中并链接到 macos sierra 上的 clang ++ (clang 8.1.0)应用程序。所以图片是:

c++ (gcc) wrapped in c (gcc) linked to clang app.

作为测试用例,我使用 shared-lib.cpp

#include <iostream>
using namespace std;
void foo()
{
  cerr << "Hi from the shared lib" << endl;
} 

shared-lib.h

一起使用
extern void foo(); 

wrapper-lib.c

#include "shared-lib.h"
int wrapper()  
{
  foo();
  return 123;
} 

以及 wrapper-lib.h

#ifdef __cplusplus
extern "C"
{
#endif

extern int wrapper();

#ifdef __cplusplus
}
#endif 

使用所有库的 main.cpp 看起来像

#include <iostream>
#include <string>

#include "shared-lib.h"
#include "wrapper-lib.h"
using namespace std;

int main()
{
    auto s = "Hello world from main";
    cout << s << endl;
    foo(); // from c++ lib

    int result = wrapper();  // from c wrapper lib
    cout << "wrapper returned " << result << endl;

    return 0;
} 

我的测试构建脚本是

g++-6 --version
echo -----------------------

echo build shared-lib .o with g++
g++-6 -c -Wall -fpic -std=c++11 shared-lib.cpp

echo build a wrapper library in C with gcc
gcc-6 -c -Wall -fpic  wrapper-lib.c

echo build static libshared-lib.a
ar rcs libshared-lib.a  shared-lib.o

echo build static libwrapper-lib.a
ar rcs libwrapper-lib.a  wrapper-lib.o

echo build main with clang
clang++ --version
echo ----------------------
clang++ -v -L/Users/worker -Wall -std=c++11 -stdlib=libstdc++ -lwrapper-lib  -lshared-lib main.cpp -o main

echo start the app
./main 

如果我只调用gcc c ++函数 foo()那么一切正常。 如果我调用C包装函数 wrapper(),则clang会出现:

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

也许有人可以简单地发现我的工作流程出了什么问题?

注意,为了完整性,整个构建脚本输出

Note2 ,因为gcc @ 6工具链中的 ar 不起作用(liblto_plugin.so缺失)我使用了clang的#em> ar 工具......

mac-mini:~ worker$ ./build-test.sh
g++-6 (Homebrew GCC 6.4.0) 6.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

-----------------------
build shared-lib .o with g++
build a wrapper library in C with gcc
build static libshared-lib.a
build static libwrapper-lib.a
build main with clang
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 8.1.0 (clang-802.0.41)
Target: x86_64-apple-darwin16.7.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
----------------------
Apple LLVM version 8.1.0 (clang-802.0.41)
Target: x86_64-apple-darwin16.7.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
clang: warning: libstdc++ is deprecated; move to libc++ [-Wdeprecated]
 "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" -cc1 -triple x86_64-apple-macosx10.12.0 -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -emit-obj -mrelax-all -disable-free -disable-llvm-verifier -discard-value-names -main-file-name main.cpp -mrelocation-model pic -pic-level 2 -mthread-model posix -mdisable-fp-elim -masm-verbose -munwind-tables -target-cpu penryn -target-linker-version 278.4 -v -dwarf-column-info -debugger-tuning=lldb -resource-dir /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/8.1.0 -stdlib=libstdc++ -Wall -std=c++11 -fdeprecated-macro -fdebug-compilation-dir /Users/worker -ferror-limit 19 -fmessage-length 166 -stack-protector 1 -fblocks -fobjc-runtime=macosx-10.12.0 -fencode-extended-block-signature -fcxx-exceptions -fexceptions -fmax-type-align=16 -fdiagnostics-show-option -fcolor-diagnostics -o /var/folders/18/m18t0kxx03d7__31kg3wrsr40000gq/T/main-337db7.o -x c++ main.cpp
clang -cc1 version 8.1.0 (clang-802.0.41) default target x86_64-apple-darwin16.7.0
ignoring nonexistent directory "/usr/include/c++/4.2.1/i686-apple-darwin10/x86_64"
ignoring nonexistent directory "/usr/include/c++/4.0.0"
ignoring nonexistent directory "/usr/include/c++/4.0.0/i686-apple-darwin8/"
ignoring nonexistent directory "/usr/include/c++/4.0.0/backward"
#include "..." search starts here:
#include <...> search starts here:
 /usr/include/c++/4.2.1
 /usr/include/c++/4.2.1/backward
 /usr/local/include
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/8.1.0/include
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include
 /usr/include
 /System/Library/Frameworks (framework directory)
 /Library/Frameworks (framework directory)
End of search list.
 "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld" -demangle -lto_library /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/libLTO.dylib -no_deduplicate -dynamic -arch x86_64 -macosx_version_min 10.12.0 -o main -L/Users/worker -lwrapper-lib -lshared-lib /var/folders/18/m18t0kxx03d7__31kg3wrsr40000gq/T/main-337db7.o -lstdc++ -lSystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/8.1.0/lib/darwin/libclang_rt.osx.a
Undefined symbols for architecture x86_64:
  "_foo", referenced from:
      _wrapper in libwrapper-lib.a(wrapper-lib.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

1 个答案:

答案 0 :(得分:1)

您使用以下代码编译shared-lib.cpp

g++-6 -c -Wall -fpic -std=c++11 shared-lib.cpp

您使用以下代码编译wrapper-lib.c

gcc-6 -c -Wall -fpic  wrapper-lib.c

查看shared-lib.o的符号表。它类似于:

$ readelf -s shared-lib.o

Symbol table '.symtab' contains 24 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS shared-lib.cpp
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    4 
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 
     6: 0000000000000000     1 OBJECT  LOCAL  DEFAULT    5 _ZStL19piecewise_construc
     7: 0000000000000000     1 OBJECT  LOCAL  DEFAULT    4 _ZStL8__ioinit
     8: 0000000000000032    73 FUNC    LOCAL  DEFAULT    1 _Z41__static_initializati
     9: 000000000000007b    21 FUNC    LOCAL  DEFAULT    1 _GLOBAL__sub_I_shared_lib
    10: 0000000000000000     0 SECTION LOCAL  DEFAULT    6 
    11: 0000000000000000     0 SECTION LOCAL  DEFAULT    9 
    12: 0000000000000000     0 SECTION LOCAL  DEFAULT   10 
    13: 0000000000000000     0 SECTION LOCAL  DEFAULT    8 
    14: 0000000000000000    50 FUNC    GLOBAL DEFAULT    1 _Z3foov
    15: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _GLOBAL_OFFSET_TABLE_
    16: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _ZSt4cerr
    17: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _ZStlsISt11char_traitsIcE
    18: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _ZSt4endlIcSt11char_trait
    19: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _ZNSolsEPFRSoS_E
    20: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _ZNSt8ios_base4InitC1Ev
    21: 0000000000000000     0 NOTYPE  GLOBAL HIDDEN   UND __dso_handle
    22: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _ZNSt8ios_base4InitD1Ev
    23: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND __cxa_atexit

(我正在研究Ubuntu,而不是OS X.)

请注意,此对象文件中只定义了一个全局函数 它的名字是_Z3foov

这是foo中名为shared-lib.cpp的C ++函数的mangled name。那是 链接器看到的名称。

现在是wrapper-lib.o的符号表:

Symbol table '.symtab' contains 11 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS wrapper-lib.c
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    4 
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    6 
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    7 
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 
     8: 0000000000000000    21 FUNC    GLOBAL DEFAULT    1 wrapper
     9: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _GLOBAL_OFFSET_TABLE_
    10: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND foo

此目标文件对foo进行了未定义的引用,因为wrapper-lib.c 是一个C源文件,你这样编译它。 C不会破坏名称。没有定义 foo的{​​{1}}由链接中的任何目标文件提供,因此它失败了 符号尚未解决。

要避免这种情况并完成链接,可以指导C ++编译器 在编译foo时,不会破坏名称 shared-lib.cpp。你这样做:

<强>共享lib.cpp

#include <iostream>
using namespace std;

extern "C" {

void foo()
{
  cerr << "Hi from the shared lib" << endl;
}

} //extern "C"

foo中加上extern "C" {...}的定义对此没有影响 C ++编译除了你想要的那个:将发出符号foo 作为C符号;没有被破坏。

完成后,您当然必须在shared-lib.h

中效仿

<强>共享lib.h

#ifndef SHARED_LIB_H
#define SHARED_LIB_H

#ifdef __cplusplus
extern "C" {
#endif

void foo();

#ifdef __cplusplus
}
#endif

#endif  

通过这些更正,让我们再试一次:

$ g++-6 -c -Wall -fpic -std=c++11 shared-lib.cpp

并检查符号表:

$ readelf -s shared-lib.o | grep foo
    14: 0000000000000000    50 FUNC    GLOBAL DEFAULT    1 foo

现在定义的一个全局函数是foo,而不是_Z3foov,而你的 联系将会成功。

如果要编写导出C ++ API而不是C API 的C ++库 链接器,然后你不能通过发现它从C调用它的API 错误的API名称(包含readelfnmobjdump)并明确说明 从C调用那些 mangled 名称。因此没有那些extern "C"修复, 你的联系也会成功:

<强>包装-lib.c

extern void _Z3foov(void); 
int wrapper()  
{
  _Z3foov();
  return 123;
}