Undefined symbols for architecture x86_64 - Mavericks (Yosemite, El Capitan...)
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))
Undefined symbols for architecture x86_64: Mac OS 10.8
Its a linker flag called *force_load*. So -force_load filename.a would do it.
Why can templates only be implemented in the header file?
Caveat: It is not necessary to put the implementation in the header file, see the alternative solution at the end of this answer.
Anyway, the reason your code is failing is that, when instantiating a template, the compiler creates a new class with the given template argument. For example:
template<typename T>
struct Foo
{
T bar;
void doSomething(T param) {/* do stuff using T */}
};
// somewhere in a .cpp
Foo<int> f;
When reading this line, the compiler will create a new class (let's call it FooInt
), which is equivalent to the following:
struct FooInt
{
int bar;
void doSomething(int param) {/* do stuff using int */}
}
Consequently, the compiler needs to have access to the implementation of the methods, to instantiate them with the template argument (in this case int
). If these implementations were not in the header, they wouldn't be accessible, and therefore the compiler wouldn't be able to instantiate the template.
A common solution to this is to write the template declaration in a header file, then implement the class in an implementation file (for example .tpp), and include this implementation file at the end of the header.
Foo.h
template <typename T>
struct Foo
{
void doSomething(T param);
};
#include "Foo.tpp"
Foo.tpp
template <typename T>
void Foo<T>::doSomething(T param)
{
//implementation
}
This way, implementation is still separated from declaration, but is accessible to the compiler.
Alternative solution
Another solution is to keep the implementation separated, and explicitly instantiate all the template instances you'll need:
Foo.h
// no implementation
template <typename T> struct Foo { ... };
Foo.cpp
// implementation of Foo's methods
// explicit instantiations
template class Foo<int>;
template class Foo<float>;
// You will only be able to use Foo with int or float
If my explanation isn't clear enough, you can have a look at the C++ Super-FAQ on this subject.
Making .so from .cpp: Undefined symbols for architecture x86_64: Boost.Python MacPorts GCC6 not Clang
Regardless of whether you have GCC/G++ installed correctly, MacPorts always builds its C++ software against libc++ on systems where clang would compile with libc++ as default.
That means that your MacPorts version of Boost is compiled with libc++, which means you cannot use it with GCC/G++ (unless you jump through some extra hoops to use libc++ with GCC).
Despite your guess that your problem is not what you described in the other post you linked, it is exactly that. Your options are:
- Use clang++
- Build your own copy of Boost with g++
Unable to `gem install tiny_tds` OS X Mavericks
I solved this problem by explicitly specifying the 64 bit architecture:
$ brew install freetds
$ sudo ARCHFLAGS="-arch x86_64" gem install tiny_tds
The reason is that during the gem building process, mkmf will try to look for 32 bit version of freetds, which is not available. The error message in mkmf.log
said:
ld: warning: ignoring file /usr/local/lib/libsybdb.dylib, file was built for x86_64 which is not the architecture being linked (i386): /usr/local/lib/libsybdb.dylib
Undefined symbols for architecture i386:
"_tdsdbopen", referenced from:
_t in conftest-a13287.o
ld: symbol(s) not found for architecture i386
Related Topics
How to Use Threads to Speed Up File Reading
How to Pack a Visual Studio C++ Project for Release
What Is a Good Easy to Use Profiler for C++ on Linux
Can Using a Lambda in Header Files Violate the Odr
Check If One String Is a Prefix of Another
In the Standard, What Is "Derived-Declarator-Type"
What Can Make C++ Rtti Undesirable to Use
C++ Linker Error with Class Static Constexpr
Benefits of Using Reserve() in a Vector - C++
How Much Overhead Is There in Calling a Function in C++
Openmp Nested Parallel for Loops VS Inner Parallel For
Exception Running Boost Asio Ssl Example
What Would a Std::Map Extended Initializer List Look Like
C++ Object Created with New, Destroyed with Free(); How Bad Is This
Optimizations for Pow() with Const Non-Integer Exponent
What's the Advantage of Using Std::Allocator Instead of New in C++