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
.
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))