建筑的未定义符号x86_64 - Mavericks(Yosemite,El Capitan ...)

时间:2014-07-29 16:19:15

标签: c++ macos linker static-libraries 32bit-64bit

编辑:

如果你落在这篇文章上,你可能想直接跳到答案


今天早上我发了一篇关于我的困惑的帖子

machine type (C++ librairies) : i386 vs x86_64

但我猜我做错了不准确。所以我决定举一个我面对的情况的例子,我无法理解。

第1步

我在机器A上构建了一个库,一个2岁的mac,OS x 10.7.5(我猜是64位;我的猜测基于你将在下面的附加信息中看到的命令)使用以下文件。

标题SimpleClass.hpp:

#ifndef SIMPLECLASS_HPP
#define SIMPLECLASS_HPP

class SimpleClass
{
public:
  SimpleClass();
  SimpleClass(const SimpleClass& orig);
  virtual ~SimpleClass();
private:

} ;

#endif  /* SIMPLECLASS_HPP */

源文件SimpleClass.cpp:

#include "SimpleClass.h"
#include <iostream>

SimpleClass::SimpleClass()
{
  std::cout << "A new instance of Simple Class was created" << std::endl;
}

SimpleClass::SimpleClass(const SimpleClass& orig)
{
}

SimpleClass::~SimpleClass()
{
}

我使用

创建库
~/cpp_test$ clang++ -c -o SC.o -I SimpleClass.hpp SimpleClass.cpp

~/cpp_test$ ar rcs libtest_sc.a SC.o

机器A的其他信息:

~/cpp_test$ clang++ --version
Apple LLVM version 4.2 (clang-425.0.28) (based on LLVM 3.2svn)
Target: x86_64-apple-darwin11.4.2
~/cpp_test$ uname -m
x86_64
~/cpp_test$ uname -p
i386
~/cpp_test$ lipo -info libtest_sc.a 
input file libtest_sc.a is not a fat file
Non-fat file: libtest_sc.a is architecture: x86_64

第2步

我将SimpleClass.hpp以及该库复制到另一台机器B,这是一台5年前使用osx 10.6.7的Mac机器,我相信它是32位。我编写以下hello文件来测试库

#include <iostream>
#include "SimpleClass.hpp"

int main()
{
  std::cout << "Hello World!" << std::endl;
  SimpleClass testObj;
  return 0;
} 

令人惊讶的是,我没有遇到与图书馆联系的问题。

[~/Downloads/Gmail-9]$ g++ -o hello -L. -ltest_sc hello.cpp
[~/Downloads/Gmail-9]$ ./hello
Hello World!
A new instance of Simple Class was created

机器B的其他信息:

[~/Downloads/Gmail-9]$ uname -m
i386
[~/Downloads/Gmail-9]$ uname -p
i386
[~/Downloads/Gmail-9]$ g++ --version
i686-apple-darwin10-g++-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5666) (dot 3)
Copyright (C) 2007 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.

第3步

我再次使用相同的头文件和hello文件在机器C上复制相同的库,这是一个10.9.2的新mac,我相信是64位。

令人惊讶的是我有链接问题

MacBook-Pro:testcpp$ g++ -o hello -L. -ltest_sc hello.cpp

Undefined symbols for architecture x86_64:
  "std::ostream::operator<<(std::ostream& (*)(std::ostream&))", referenced from:
      SimpleClass::SimpleClass() in libtest_sc.a(SC.o)
  "std::ios_base::Init::Init()", referenced from:
      ___cxx_global_var_init in libtest_sc.a(SC.o)
  "std::ios_base::Init::~Init()", referenced from:
      ___cxx_global_var_init in libtest_sc.a(SC.o)
  "std::cout", referenced from:
      SimpleClass::SimpleClass() in libtest_sc.a(SC.o)
  "std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)", referenced from:  
      SimpleClass::SimpleClass() in libtest_sc.a(SC.o)
  "std::basic_ostream<char, std::char_traits<char> >& std::operator<<<std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)", referenced from:
      SimpleClass::SimpleClass() in libtest_sc.a(SC.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

有关Machine C的其他信息

g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin13.1.0
Thread model: posix

MacBook-Pro:testcpp$ uname -m
x86_64
MacBook-Pro:testcpp$ uname -p
i386

我原本预计机器B的链接问题是32位而不是机器C的64位,但我得到了相反的结果。谁能解释一下我在这里缺少什么?

编辑(第4步)

在机器C上,当我向g++命令添加选项-stdlib=libstdc++时,“未定义符号”错误消失,可执行文件正常运行。使用选项-v运行g ++允许我注意到默认stdliblibc++而不是libstdc++。所以看起来虽然机器A和机器C都是64位,但默认情况下它们不会使用相同的stdlib导致错误Undefined symbols for architecture x86_64

2 个答案:

答案 0 :(得分:20)

我所有的问题,即给予

Undefined symbols for architecture x86_64

是因为某些库是使用 libstdc ++ 编译的,并且无法用于使用 libc ++

编译/链接的代码

libc ++实际上是clang自 Mavericks 以来使用的默认新库,但是使用经典的libstdc ++可以使用相同的clang(不需要安装旧的gcc)进行编译。选项

-stdlib=libstdc++


对于那些使用Boost的人来说,通过下载源代码并使用(编译时)代替经典

,也可以在libverdc ++编译/链接的小牛上拥有增强库

./b2

以下

./b2 cxxflags="-stdlib=libstdc++" linkflags="-stdlib=libstdc++"


对于那些使用Cmake的人,您可能希望在适当的cmake文件中添加类似于:

的文件

find_library (LIBSTDCXX NAMES stdc++)

add_compile_options(-stdlib=libstdc++)

target_link_libraries(${PROJECT_NAME} ${LIBSTDCXX} ${YOUR_OTHER_LIBRARIES))

答案 1 :(得分:0)

我有点懒,不会读这个,所以随时投票......

我认为你正在尝试构建一个胖胖的32/64位库......

你有两种方法可以做到这一点,一种方法是使用32位明确构建并使用64位显式构建...然后使用lipo组合它们。

考虑名义C ++代码存储在main.cpp

然后:

grady$ clang++ main.cpp -m64 -o64.out
grady$ file 64.out 
64.out: Mach-O 64-bit executable x86_64
grady$ clang++ main.cpp -m32 -o32.out
grady$ file 32.out 
32.out: Mach-O executable i386
grady$ lipo -arch i386 32.out -arch x86_64 64.out -create -output fat.out
grady$ file fat.out
fat.out: Mach-O universal binary with 2 architectures
fat.out (for architecture i386):    Mach-O executable i386
fat.out (for architecture x86_64):  Mach-O 64-bit executable x86_64

或者您通常可以使用苹果工具的一些快捷方式:

grady$ clang++ main.cpp -arch i386 -arch x86_64  -ofat2.out
grady$ file fat2.out 
fat2.out: Mach-O universal binary with 2 architectures
fat2.out (for architecture i386):   Mach-O executable i386
fat2.out (for architecture x86_64): Mach-O 64-bit executable x86_64