Looked around and found a few similar questions but none of them were the same. Most had to do with the constructor or destructor. This issue is, more than likely, a result of my rusty C++ linker memory (picking it back up after a few years).
I'll keep it real simple since this is probably a basic misunderstanding of the linker:
data.h
#pragma once
namespace test {
class Data_V1 {
public:
// some getters/setters
int getData() { return _d; }
void setData( int d ) { _d = d; }
private:
// some data
int _d;
};
}
builder.h
#pragma once
namespace test {
template <class V>
class Builder {
public:
void build();
};
}
builder.cpp
#include <iostream>
#include "builder.h"
namespace test {
template<class V>
void Builder<V>::build() {
std::cout << "Insert building logic" << std::endl;
}
}
main.cpp
#include "builder.h"
#include "data.h"
using namespace test;
int main(int argc, char* argv[]) {
Builder<Data_V1> b;
b.build();
}
compiling:
g++ -Wall -ansi -pedantic -c builder.cpp
g++ -Wall -ansi -pedantic -c main.cpp
g++ -Wall -ansi -pedantic -o main main.o builder.o
Link error:
Undefined symbols for architecture x86_64:
"test::Builder<test::Data_V1>::build()", referenced from:
_main in main.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
Any help would be appreciated!
Template definitions need to be visible to all translation units. Move the definition from the cpp to the header.
Builder.h
#pragma once
namespace test {
template <class V>
class Builder {
public:
void build();
};
template<class V>
void Builder<V>::build() {
std::cout << "Insert building logic" << std::endl;
}
}
Before you ask, no, there's no way to hide the implementation unless you know all possible specializations beforehand.
Templates represent a generalized form for the creation of a new class. If the implementation is not visible, when you attempt to specialize the template, the compiler can't know what code to generate.
Related
Given the following code as test.cpp,
Building using clang++ -c test.cpp -o test.o -g; clang++ test.o -g -all_load, setting breakpoint at return a.getValue(); and attempting to p a.getValue() from lldb:
Running llvm 3.8.0 on unix - works perfectly
Running xcode or llvm 8.1.0 on OSX - I get the following error:
error: Couldn't lookup symbols:
__ZNK4Test7MyClassILi2ELi3EE8getValueEv
Two interesting facts:
If I remove the last template argument - all works well
If I build directly without going through the .o file (clang++ test.cpp) = all goes well
Anyone has a clue what is going on, and how can it be fixed?
namespace Test{
template<class T>
class BLA{
public:
T getBlaValue() const{return 3;}
};
template <int N1, int N2, template<class T>class Impl = BLA>
class MyClass {
private:
public:
__attribute__((used))
int getValue() const
{
return 3;
}
};
}
int main()
{
Test::MyClass<2, 3> a;
return a.getValue();
}
Using g++, when two compilation units "a1.o" and "a2.o" both define and use the same weak symbol, the linker will silently resolve to the first occurrence of the symbol wherever it is used. As a result, the behavior of the application will depend on the order of the object files on the linker command line. What can be done to ensure that these symbols are resolved locally to each compilation unit?
For instance, as a minimalist example, if I have the following source files:
a1.cpp:
#include <iostream>
struct A
{
void foo() {std::cerr << __FILE__ << std::endl;}
};
void bar1() {A a; a.foo();}
a2.cpp:
#include <iostream>
struct A
{
void foo() {std::cerr << __FILE__ << std::endl;}
};
void bar2() {A a; a.foo();}
main.cpp:
void bar1();
void bar2();
int main()
{
bar1();
bar2();
}
and compile them with:
for i in a1 a2 main ; do g++ -c -o $i.o $i.cpp ; done
The output will depend on the relative position of a1.o and a2.o on the linker command line:
g++ -o main main.o a{1,2}.o ; ./main
a1.cpp
a1.cpp
g++ -o main main.o a{2,1}.o ; ./main
a2.cpp
a2.cpp
I'd like to get the same result as if using the '-fno-weak' command line option:
for i in a1 a2 main ; do g++ -fno-weak -c -o $i.o $i.cpp ; done
g++ -o main main.o a{1,2}.o ; ./main
a1.cpp
a2.cpp
but '-fno-weak' seems to lead to other complications. What are the alternatives (besides not inlining and fixing collisions)?
For those wondering what could be a typical use case: when writing mock components it is sometimes convenient to have header-only implementations. Different test fixtures end-up having different mock implementations of the same component type, which becomes an issue when all the fixtures are linked into a single test runner.
You asked:
What are the alternatives (besides not inlining and fixing collisions)?
Use local namespaces or anonymous namespaces.
a1.cpp:
#include <iostream>
namespace A1_namespace
{
struct A
{
void foo() {std::cerr << __FILE__ << std::endl;}
};
}
using namespace A1_namespace;
void bar1() {A a; a.foo();}
or
#include <iostream>
namespace
{
struct A
{
void foo() {std::cerr << __FILE__ << std::endl;}
};
}
void bar1() {A a; a.foo();}
Make similar changes to a2.cpp.
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
"undefined reference" to a template class function
(4 answers)
Closed 9 years ago.
See my demo code below:
b.hpp:
#ifndef B_HPP
#define B_HPP
namespace debug {
class test {
public:
template <class T> void foo(T a);
private:
int a;
};
}
#endif
b.cpp:
#include <iostream>
#include "b.hpp"
namespace debug {
template <class T>
void test::foo(T a) {
std::cout << "debug" << std::endl;
}
}
testb.cpp:
include "b.hpp"
int main(int agrc, char *argv[])
{
debug::test a;
int c = 5;
a.foo(c);
return 0;
}
I compile it with
g++ -std=c++11 testb.cpp b.cpp'
and get a error:
/tmp/ccnjR5S4.o: In function `main':
testb.cpp:(.text+0x1c): undefined reference to `void debug::test::foo<int>(int)'
collect2: error: ld returned 1 exit status
What's the problem?
If I put main function in b.cpp and compile b.cpp, it 's ok. Why?
Thanks!
This is one of the cases where you need explicit instantiation, or to move code back into b.hpp. This arises because the implementation of debug::test::foo isn't visible when you compile testb.cpp, and the compiler has no way of knowing what might be needed when it compiles b.cpp.
To explicitly instantiate debug::test::foo<int>, add the following line to b.cpp:
#include <iostream>
#include "b.hpp"
namespace debug {
template <class T>
void test::foo(T a) {
std::cout << "debug" << std::endl;
}
// Explicitly instantiate test::foo<int>
template void test::foo<int>(int); // <-- add this line
}
Alternately, if you do not know all the ways this template might get instantiated, move its definition back into the class definition in the header. Ugly, but it'll work.
Some compilers do cross-compilation unit template instantiation, but as you've discovered, g++ isn't one of them. (At least, not as it's configured on my system.)
Edit: As #juanchopanza pointed out above, this thread gives a good explanation of what's going on: Why can templates only be implemented in the header file?
I am writing a simple server program using ICE by ZeroC. When I try to link the .o files it gave me the following error message:
$ c++ -o server UserMap.o Server.o -L/Library/Developer/Ice-3.5.0/lib -lIce -lIceUtil
Undefined symbols for architecture x86_64:
"VTT for UserMapI", referenced from:
UserMapI::UserMapI() in Server.o
"vtable for UserMapI", referenced from:
UserMapI::UserMapI() in Server.o
NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
After some googling I understand that the problem is I have an abstract class with 3 virtual methods declared in UserMap.ice (and hence in UserMap.h and UserMap.cpp generated by the command slice2cpp UserMap.ice), and in Server.cpp I have a class called UserMapI:public UserMap which implements the three virtual methods and another private helper function. The error is generated because the compiler thinks I have declared all functions(methods) in UserMap.h and UserMap.cpp.
My understanding to this problem is that I should modify the link command so that the linker will know that there are more functions in UserMapI declared in Server.cpp, but I don't have enough knowledge to do the modification. Can someone help me please?
Thank you all.
Here is the compiler command I am using to get Server.o and UserMap.o:
c++ -I. -I/Library/Developer/Ice-3.5.0/include -c UserMap.cpp Server.cpp
Here's the code of UserMap.ice:
module DR
{
class UserMap
{
void addUserToLocation(int userID, int x, int y);
string getUsersNearLocation(int x, int y, int distance);
void removeFromMap(int userID, int x, int y);
};
};
slice2cpp command slices this .ice file into a .h and a .cpp file that works as an API between server and client.
In Server.cpp I have the following include:
#include <Ice/Ice.h>
#include "UserMap.h"
#include <map>
#include <string>
#include <vector>
#include <iostream>
#include <sstream>
and the following subclass:
class UserMapI : public UserMap
{
public:
virtual void addUserToLocation(int userID, int x, int y, const Ice::Current &);
virtual string getUsersNearLocation(int x, int y, int distance, const Ice::Current &);
virtual void removeFromMap(int userID, int x, int y, const Ice::Current &);
private:
string stringify(int x, int y);
};
And after implementing all methods here's the main function:
int main(int argc, char* argv[])
{
int status = 0;
Ice::CommunicatorPtr ic;
try {
ic = Ice::initialize(argc, argv);
Ice::ObjectAdapterPtr adapter = ic->createObjectAdapterWithEndpoints("SimpleUserMapAdapter", "default -p 10000");
Ice::ObjectPtr object = new UserMapI;
adapter->add(object, ic->stringToIdentity("SimpleUserMap"));
adapter->activate();
ic->waitForShutdown();
} catch (const Ice::Exception & e) {
cerr << e << endl;
status = 1;
} catch (const char * msg) {
cerr << msg << endl;
status = 1;
}
if (ic){
try {
ic->destroy();
} catch (const Ice::Exception & e) {
cerr << e << endl;
status = 1;
}
}
return status;
}
Here's the UserMap.h.
I wrote a class named UserScore:
//header
using namespace std;
class UserScore{
public:
UserScore(const int &user_id, const int &rating);
private:
int _user_id;
int _rating;
};
//cpp
#include "UserScore.h"
UserScore::UserScore (const int &user_id, const int &rating):
_user_id(user_id),
_rating(rating)
{
}
The compile command is:
g++ src/UserScore.cpp -o obj/UserScore.o
But why this simple thing won't compile?
The error is:
Undefined symbols for architecture x86_64:
"_main", referenced from:
start in crt1.10.6.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
You need to include the -c option to the compilation line if you want to generate an object file, otherwise the compiler assumes you are trying to build an executable and will complain if you don't have a main() method (which is happening here).
To make an object file which you will link later to a code file that has a "main()" method in it you need to use
g++ -c src/UserScore.cpp -o obj/UserScore.o
Which is what I think you are trying to do.
Alternatively you just need to add a main function to your code and then you can make an executable.
//header
using namespace std;
class UserScore{
public:
UserScore(const int &user_id, const int &rating);
private:
int _user_id;
int _rating;
};
//cpp
#include "UserScore.h"
UserScore::UserScore (const int &user_id, const int &rating):
_user_id(user_id),
_rating(rating)
{
}
int main()
{
return 0;
}