【问题标题】:Linker error using gcc and clang together on macos sierra在 macos sierra 上使用 gcc 和 clang 的链接器错误
【发布时间】:2017-10-31 20:27:03
【问题描述】:

我必须使用 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 的 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)

【问题讨论】:

  • 糟糕。看起来,这不是 GCC - Clang 问题,因为如果我纯粹使用 clang++ / clang 尝试所有操作,也会发生链接器错误。所以现在的问题是**如何摆脱仍然存在的讨厌的链接器错误,如果我尝试将静态 c++ 库包装在普通 c 库中..

标签: macos gcc clang


【解决方案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

这是shared-lib.cpp 中名为foo 的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 由链接中的任何目标文件提供,因此它失败了 符号未解析。

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

shared-lib.cpp

#include <iostream>
using namespace std;

extern "C" {

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

} //extern "C"

extern "C" {...} 中包含foo 的定义对 C++编译除了你想要的那个:符号foo会被发射 作为 C 符号;没有损坏。

完成之后,你当然必须在shared-lib.h 中效仿:

shared-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" 修复, 您的链接也将成功:

wrapper-lib.c

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

【讨论】:

  • 啊,就是这样!非常感谢您的解决方案。现在唯一的问题是,在我的情况下,我需要包装到 C 库 中的 c++ 库Qtcore 的静态版本。那么这是否意味着,我必须将 extern "C" 放在数以亿计的 Qt 源代码行中?听起来很有趣;-)
  • @xy @xy 恐怕这不是首发。 extern "C" {...}` 将为您提供 C API,前提是 ... 在语法上是 C API,但 C++ 类定义 显然不是。除了POD structs,您不能将 classes 公开为 C。
猜你喜欢
  • 2023-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-12
  • 1970-01-01
  • 2012-04-11
  • 2018-11-18
  • 2016-03-31
相关资源
最近更新 更多