17

EDIT :

If you fall on this post, you may want to jump directly to the answer


I sent a post about my confusion earlier this morning

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

But I guess I did a mistake by being not precise. So I decided to give an example of situations I face and that I can not understand.

STEP 1

I build a library on machine A, a 2 years old mac with OS x 10.7.5 (that I guess is 64 bits; my guess being based on the commands you will see below in Additional Info) using the following files.

A header SimpleClass.hpp:

#ifndef SIMPLECLASS_HPP
#define SIMPLECLASS_HPP

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

} ;

#endif  /* SIMPLECLASS_HPP */

A source file 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()
{
}

I create the library using

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

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

Additional info on machine 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

STEP 2

I copy SimpleClass.hpp as well as the library to another machine B that is a 5 years old mac with osx 10.6.7 that I believe is 32 bits. And I write the following hello file to test the library

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

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

Surprisingly, no problems at linking with the library and I get.

[~/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

Additional info on Machine 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.

STEP 3

I copy the same library again with the same header and hello file on Machine C that is a new mac with 10.9.2 that I believe is 64 bits.

Surprisingly I have linking problems

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)

Additional Info on 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

I would have expected the linking problem with machine B that is 32bits and not with machine C that is 64bits but I got the opposite. Can anyone please explain what I am missing here?

EDIT (STEP 4)

On machine C, when I add to the g++ command the option -stdlib=libstdc++, the "undefined symbols" error disappear and the executable is running correctly. Running g++ with the option -v allowed me to notice the default stdlib was libc++and not libstdc++. So it seems that although the machine A and machine C are both 64 bits they don't use the same stdlib by default which caused the error Undefined symbols for architecture x86_64.

Community
  • 1
  • 1
Issam T.
  • 1,677
  • 1
  • 14
  • 32
  • 1
    Run `file` on your object files. You'll see what's up in short order. – Carl Norum Jul 29 '14 at 17:14
  • 1
    Try `g++ -o hello hello.cpp -L. -ltest_sc` (different order of arguments). Also try running `file` and/or `lipo -info` on files right before you use them, not before you copy them to some place. – n. m. could be an AI Jul 29 '14 at 17:16
  • @CarlNorum thanks for your time. `file libtest_sc.a libtest_sc.a: current ar archive random library` `file file SC.o SC.o: Mach-O 64-bit object x86_64` I am not sure how I am supposed to use this information. I can understand that my object file is 64 bits. nothing new though... – Issam T. Jul 30 '14 at 12:25
  • @n.m. thanks for your time. I tried this order as well as others, and I still got the same result. Alos using `lipo -info` on the library returns the same thing on the 3 machines. – Issam T. Jul 30 '14 at 12:27

2 Answers2

21

All the issues I had, that were giving

Undefined symbols for architecture x86_64

were due to the fact that some libraries were compiled with libstdc++ and could not be used for code that is compiled/linked with libc++

libc++ is in fact the default new library used by clang since Mavericks, however it is possible to compile with the same clang (no need to install an old gcc) with the classical libstdc++ by using the option

-stdlib=libstdc++


For those who use Boost it is also possible to have boost libraries on mavericks that are compiled/linked with libstdc++ by downloading the source and using (when compiling it) instead of the classical

./b2

the following

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


For those using Cmake, you may want to add in the adequate cmake file something similar to:

find_library (LIBSTDCXX NAMES stdc++)

and

add_compile_options(-stdlib=libstdc++)

and

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

Issam T.
  • 1,677
  • 1
  • 14
  • 32
  • 2
    I'm running into a similar problem, I'm using an open source library. I used the library on linux and i have no problems. Now I'm trying to use this library on mac but I get `Undefined symbols for architecture x86_64:` that is pointing to call to one of the classes functions. Any tips? Where should I include the -stdlib=libstdc++? – Lily Jan 16 '16 at 03:49
  • Specifically, it is at the "make" step. The command "make -stdlib=libstdc++" works for me. – Châu Hồng Lĩnh Nov 18 '16 at 09:19
0

I am sort of lazy and not going to read this, so feel free to vote down...

I think you are trying build a fat 32/64 bit library...

you have a couple of ways to do this, one if to build explicitly with 32-bit and explicitly with 64-bit... then use lipo to combine them.

consider nominal C++ code is stored in main.cpp

then:

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

or you can generally use some shortcuts with apple tools:

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
Grady Player
  • 14,399
  • 2
  • 48
  • 76
  • I am pretty sure I should not but I will upvote this just because you are one of the few who tried for now to answer my question (although you were not able to read the question lol). I learned something from your answer that I didn't know. However it has nothing to do with my question. Thanks anyway – Issam T. Jul 30 '14 at 14:36
  • Nah, you shouldn't. I understand that not all people have enough time to read my "salade Niçoise" :P – Issam T. Jul 30 '14 at 15:15
  • I think the simplest explanation is that the first compilation and the second compilation are both 32-bit only – Grady Player Jul 30 '14 at 15:26
  • actually that doesn't fit – Grady Player Jul 30 '14 at 15:26
  • 1
    maybe libstdC++ vs libC++ issue? – Grady Player Jul 30 '14 at 15:28
  • 1
    I don't know if you read my last edit, but yes, that seems to be the explanation for what is happening on machine C – Issam T. Jul 30 '14 at 15:29