c++ linker error - 'undefined reference' to not inline defined functions - c++

For few days I'm trying to compile one project written in C++ using Code::Blocks IDE (on Linux, Ubuntu 64-bit). Code is valid but there are some linker errors. I noticed that I get errors 'undefined reference' for functions which are not inline defined in classes and are in other files (class is i *.h file and definitions on these functions are in *.cpp). I tried to write my own Makefile but it didn't help.
Makefile:
all: project
project: main.o DList.o Person.o
g++ main.o DList.o Person.o -o project
main.o: main.cpp
g++ -c main.cpp
DList.o: include/DList.cpp
g++ -c include/DList.cpp
Person.o: include/Person.cpp
g++ -c include/Person.cpp
clean:
rm -rf *.o
I don't know what should I do although I read some about these errors on the net.
// EDIT
I changed Object.cpp and Object.h to Person.cpp and Person.h, moved *.cpp files to main directory and changed #include paths in *.cpp files.
Errors:
obj/Debug/main.o||In function `main':|
...main.cpp|19|undefined reference to `DListIterator<Person>::go(int)'|
...main.cpp|20|undefined reference to `std::basic_ostream<char, std::char_traits<char> >& operator<< <Person>(std::basic_ostream<char, std::char_traits<char> >&, DList<Person>&)'|
...main.cpp|21|undefined reference to `DList<Person>::~DList()'|
...main.cpp|21|undefined reference to `DList<Person>::~DList()'|
obj/Debug/main.o||In function `DList<Person>::insert(Person&)':|
...include/DList.h|45|undefined reference to `DList<Person>::insert(Person&, DListIterator<Person>&)'|
||=== Build finished: 5 errors, 0 warnings ===|
It makes no difference if I build starting make in command line or using Build function in Code::Blocks.
When I copied all code from *.cpp files to *.h files, compiler returned no errors, so I think that it's only linker problem.

It looks like you are attempting to separately compile a template. This is not possible in general, as a template will only be instantiated when it is used, and it is never used in the DList.cpp file. Try one of two things:
Move the definitions of the functions in DList into the header file (this is the normal way of doing things).
Put some explicit instantiations of DList in to the DList.cpp file. (Example: template class DList<Person>;)
Full example of the problem: Currently you have:
//DList.h
template<typename T>
class DList {
void insert(T& newPerson);
//etc
};
//DList.cpp
#include "DList.h"
//The when this is being compiled,
//the compiler does not know about Person,
//so it cannot instantiate this function.
template<typename T>
void DList<T>::insert(T& newPerson) {
//implementation
}
//etc
//main.cpp
#include "DList.h"
#include "Person.h"
int main() {
//When this is being compiled, it does not know the
//definition of the out-of-line functions in `DList`,
//so it cannot instantiate them.
DList<Person> people;
people.insert(Person("Joe"));
}
One possible fix is to remove DList.cpp and put the definitions in "DList.hpp":
//DList.hpp
template<typename T>
class DList {
void insert(T& newPerson) {
//implementation
}
~DList();
//etc
};
//the implementations can alternatively be
//placed outside the class, but in the header:
template<typename T>
DList<T>::~DList() {
//implementation
}
The other fix is to explicitly instantiate DList (in a compilation unit where the definitions are available):
//DList.cpp
#include "DList.h"
#include "Person.h"
template<typename T>
void DList<T>::insert(T& newPerson) {
//implementation
}
//Explicit instantiation:
template class DList<Person>;

Related

undefined reference to; class public function not accessible at link time

I'm trying to build a simple program where I defined a class and included it's header in Main. While linking, Linker complains about accessing any of the member function from class:
: undefined reference to voxel::anyFunction
even though functions are public and headers are included.
Originally I discovered the problem when creating an object of voxel - I had overloaded the default constructor, but I figure out the problem is present for any function from voxel class.
Here are some code excerpts:
voxel.hpp
class voxel
{
public:
//here defined some member variables
//ommited the constructor
void fillMemberValuesWithDummy();//sets all members to some dummy value
};
voxel.cpp
#include "voxel.hpp"
void voxel::fillMemberValuesWithDummy()
{
//does the assignment to member variables
}
Main.cpp
#include <iostream>
#include <fstream>
using namespace std;
#include "voxel.hpp"
{
voxel someVoxel;
somevoxel.fillMemberValuesWithDummy();
}
I figure it is something very stupid I am (not) doing here, but can you tell me what?
You need to link all object files to get the executable. When you have just your two source files you can compile them directly:
g++ -o myprog.exe Main.cpp voxel.cpp
When you want to divide compile and link and do it this way:
g++ -c -o Main.o Main.cpp
g++ -c -o voxel.o voxel.cpp
g++ -o myprog.exe Main.o voxel.o
Feel free to create an appropriate Makefile that generates such commands.
Remove the .exe if you OS doesn't need it.

Error with multiple definitions of function

I am trying to relearn C++ after taking an intro course a few years ago and I’m having some basic problems. My current problem occurs when trying to use a friend function. Here is my code in 2 files.
First:
// fun.cpp
#include <iostream>
using namespace std;
class classA {
friend void funct();
public:
classA(int a=1,int b=2):propa(a),propb(b){cout<<"constructor\n";}
private:
int propa;
int propb;
void outfun(){
cout<<"propa="<<propa<<endl<<"propb="<<propb<<endl;
}
};
void funct(){ // ERROR HERE
cout<<"enter funct"<<endl;
classA tmp(1,2);
tmp.outfun();
cout<<"exit funct"<<endl;
}
Second:
// mainfile.cpp
#include <iostream>
#include "fun.cpp"
using namespace std;
int main(int nargin,char* varargin[]) {
cout<<"call funct"<<endl;
funct();
cout<<"exit main"<<endl;
return 0;
}
The error I am getting is "multiple definition of `funct()'". Am I using the wrong syntax when declaring it as a friend function?
Here is a highly simplified but hopefully relevant view of what happens when you build your code in C++.
C++ splits the load of generating machine executable code in following different phases -
Preprocessing - This is where any macros - #defines etc you might be using get expanded.
Compiling - Each cpp file along with all the #included files in that file directly or indirectly (together called a compilation unit) is converted into machine readable object code.
This is where C++ also checks that all functions defined (i.e. containing a body in { } e.g.
void Foo( int x){ return Boo(x); }) are referring to other functions in a valid manner.
The way it does that is by insisting that you provide at least a declaration of these other functions (e.g. void Boo(int); ) before you call it so it can check that you are calling it properly among other things. This can be done either directly in the cpp file where it is called or usually in an included header file.
Note that only the machine code that corresponds to functions defined in this cpp and included files gets built as the object (binary) version of this compilation unit (e.g. Foo) and not the ones that are merely declared (e.g. Boo).
Linking - This is the stage where C++ goes hunting for stuff declared and called in each compilation unit and links it to the places where it is getting called. Now if there was no definition found of this function the linker gives up and errors out. Similarly if it finds multiple definitions of the same function signature (essentially the name and parameter types it takes) it also errors out as it considers it ambiguous and doesn't want to pick one arbitrarily.
The latter is what is happening in your case. By doing a #include of the fun.cpp file, both fun.cpp and mainfile.cpp have a definition of funct() and the linker doesn't know which one to use in your program and is complaining about it.
The fix as Vaughn mentioned above is to not include the cpp file with the definition of funct() in mainfile.cpp and instead move the declaration of funct() in a separate header file and include that in mainline.cpp. This way the compiler will get the declaration of funct() to work with and the linker would get just one definition of funct() from fun.cpp and will use it with confidence.
The problem is that if you include fun.cpp in two places in your program, you will end up defining it twice, which isn't valid.
You don't want to include cpp files. You want to include header files.
The header file should just have the class definition. The corresponding cpp file, which you will compile separately, will have the function definition.
fun.hpp:
#include <iostream>
class classA {
friend void funct();
public:
classA(int a=1,int b=2):propa(a),propb(b){std::cout<<"constructor\n";}
private:
int propa;
int propb;
void outfun(){
std::cout<<"propa="<<propa<<endl<<"propb="<<propb<< std::endl;
}
};
fun.cpp:
#include "fun.hpp"
using namespace std;
void funct(){
cout<<"enter funct"<<endl;
classA tmp(1,2);
tmp.outfun();
cout<<"exit funct"<<endl;
}
mainfile.cpp:
#include <iostream>
#include "fun.hpp"
using namespace std;
int main(int nargin,char* varargin[]) {
cout<<"call funct"<<endl;
funct();
cout<<"exit main"<<endl;
return 0;
}
Note that it is generally recommended to avoid using namespace std in header files.
This problem happens because you are calling fun.cpp instead of fun.hpp. So c++ compiler finds func.cpp definition twice and throws this error.
Change line 3 of your main.cpp file, from #include "fun.cpp" to #include "fun.hpp" .
You have #include "fun.cpp" in mainfile.cpp so compiling with:
g++ -o hw1 mainfile.cpp
will work, however if you compile by linking these together like
g++ -g -std=c++11 -Wall -pedantic -c -o fun.o fun.cpp
g++ -g -std=c++11 -Wall -pedantic -c -o mainfile.o mainfile.cpp
As they mention above, adding #include "fun.hpp" will need to be done or it won't work. However, your case with the funct() function is slightly different than my problem.
I had this issue when doing a HW assignment and the autograder compiled by the lower bash recipe, yet locally it worked using the upper bash.

Separate compiling with MinGW

Using this tutorial Makefile I want to build a simple program with a separate compiling, The main problem is that the IDE Eclpse Indigo C\C++ (prespective) or MinGW I cannot compile the files. The error which I get is :
undefined reference to double getAverage<int, 85u>(int (&) [85u])'
undefined reference to int getMax<int, 85u>(int (&) [85u])'
undefined reference to int getMin<int, 85u>(int (&) [85u])'
undefined reference to void print<int, 85u>(int (&) [85u])'
undefined reference to void sort<int, 85u>(int (&) [85u])'
undefined reference to void print<int, 85u>(int (&) [85u])'
The main.cpp file is this :
#include "Tools.h"
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
int numbers[] = {1,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8};
cout <<"Average = "<< getAverage(numbers) << endl;
cout <<"Max element = "<< getMax(numbers) << endl;
cout <<"Minimal element = "<< getMin(numbers) << endl;
print(numbers);
sort(numbers);
print(numbers);
return 0;
}
and I have a Tools.h file :
#ifndef TOOLS_H_
#define TOOLS_H_
#include <iostream>
int getBigger(int numberOne,int numberTwo);
template <typename T,size_t N> double getAverage(T (&numbers)[N]);
template <typename T,size_t N> T getMax(T (&numbers)[N]);
template <typename T,size_t N> T getMin(T (&numbers)[N]);
/**
* Implementing a simple sort method of big arrays
*/
template <typename T,size_t N> void sort(T (&numbers)[N]);
/**
* Implementing a method for printing arrays
*/
template <typename T,size_t N> void print(T (&numbers)[N]);
#endif
When you compile Tools.cpp your compiler has no idea about the template parameters that you have used in main.cpp. Therefore it compiles nothing related to this templates.
You need to include theses template definitions from the compilation unit that uses them. The file Tools.cpp is often renamed to something like Tools.inl to indicate that it's neither a header file nor a separate compilation unit.
The compilation unit "main.cpp" could look like this:
#include "tools.h"
#include "tools.inl"
main()
{
int number[] = {1,2,3};
getaverage(numbers);
}
Since the compiler identifies the required specialization it can generate the code from the implementation file.
For most cases, harper's answer is appropriate. But for completeness' sake, explicit template instantiation should also be mentioned.
When you include the implementation in every compilation unit, your template classes and functions will be instantiated and compiled in all of them. Sometimes, this is not desirable. It is mostly due to compile-time memory restrictions and compilation time, if your template classes and functions are very complicated. This becomes a very real issue when you, or the libraries you use rely heavily on template metaprogramming. Another situation could be that your template function implementations might be used in many compilation units, and when you change the implementation, you will be forced to re-compile all those compilation units.
So, the solution in these situations is to include a header file like your tools.h, and have a tools.cpp, implementing the templates. The catch is that, you should explicitly instantiate your templates for all the template arguments that will be used throughout your program. This is accomplished via adding the following to tools.cpp:
template double getAverage<int,85>(int (&numbers)[85]);
Note: You obviously have to do something about that "85", such as defining it in a header file and using it across tools.cpp and main.cpp
I've found this article which is useful : templates and header files
I declared the function in the Tools.h file and include there the file Tool.hpp and after this I defined them in the Tools.hpp file.
I haven't tried to compile .cpp and .c files together but maybe my example will help.
I had similar problem compiling two separate assembly files .s on mingw with standard gcc
compiler and i achieved it as follows:
gcc -m32 -o test test.s hello.s
-m32 means i'm compiling 32bit code
-o is the output file ( which in my example is the "test" file )
test.s and hello.s are my source files. test.s is the main file and hello.s has the helper function. (Oh, to mention is the fact that both files are in the same directory)

C++ Template Class Problem

Hi everybody I just wanted to practice some c++ template but i get linker errors. Can anybody help me please?
Here is my code:
// File: MyClass.h
#ifndef _MYCLASS_H
#define _MYCLASS_H
template<class T> class MyClass {
T value;
public:
MyClass(T v);
~MyClass();
};
#endif // _MYCLASS_H
// File: MyClass.cpp
#include "MyClass.h"
template<class T> MyClass<T>::MyClass(T v) {
value = v;
}
template<class T> MyClass<T>::~MyClass() {
}
// File: main.cpp
#include "MyClass.h"
int main() {
MyClass<int> test(10);
return 0;
}
Here is command line output:
g++ main.cpp -c
g++ MyClass.cpp -c
g++ main.o MyClass.o -o Out
main.o: In function `main':
main.cpp:(.text+0x1a): undefined reference to `MyClass<int>::MyClass(int)'
main.cpp:(.text+0x2b): undefined reference to `MyClass<int>::~MyClass()'
collect2: ld returned 1 exit status
make: *** [all] Error 1
As you can see I'm using Ubuntu 10.04 and GNU C++ Compiler.
Am I missing something in this code?
Thanks for replies. It works but isn't there a better way to protect the code?
For example what if I want to create a non-opensource library?!
I want to export the code to a static library. and link the library to other projects ...
You have to put full template into the header. Compiler needs to see the body of the template methods at the site of template instantiation - main.cpp in your case. See, for example, C++ FAQ.
You should put template classes and inline methods into header files. You can't seperate definition and implementation in their case.
#Nikolai N Fetissov has the right solution. I would add to this that a nice way to do this, if you want to keep the implementation and templated function definitions separate is that you can put the implementations into MyClass.hxx and include it at the end of your MyClass.h
// File: MyClass.h
#ifndef _MYCLASS_H
#define _MYCLASS_H
template<class T> class MyClass
{
T value;
public:
MyClass(T v);
~MyClass();
};
#include "MyClass.hxx" /// <--- like this
#endif // _MYCLASS_H
It's important to remember what a template is. It is a template for generating code if needed; it is not code itself.
So declaring a template class and writing implementations for those methods does not generate any object code for that class; it simply provides a template for doing so if necessary.
When a template class is instantiated with an actual argument, the compiler will generate the code from the template class. In order to do that, it needs to be able to see the the templates. But since you've only #includeed the .h file, and the implementation of the methods in in the .cpp file, the compiler won't be able to generate the object code for the function implementations. Then, when the linker looks for those definitions it won't find it.
All of this is a long-winded way of getting to the same result the other answers did -- you need to put the implementation in the header file with the class declaration. But it may help to know why that is.

C++ Shared Library with Templates: Undefined symbols error

I'm trying to link to a shared library with a template class, but it is giving me "undefined symbols" errors. I've condensed the problem to about 20 lines of code.
shared.h
template <class Type> class myclass {
Type x;
public:
myclass() { x=0; }
void setx(Type y);
Type getx();
};
shared.cpp
#include "shared.h"
template <class Type> void myclass<Type>::setx(Type y) { x = y; }
template <class Type> Type myclass<Type>::getx() { return x; }
main.cpp
#include <iostream>
#include "shared.h"
using namespace std;
int main(int argc, char *argv[]) {
myclass<int> m;
cout << m.getx() << endl;
m.setx(10);
cout << m.getx() << endl;
return 0;
}
This is how I compile the library:
g++ -fPIC -c shared.cpp -o shared.o
g++ -dynamiclib -Wl,-dylib_install_name -Wl,libshared.dylib -o libshared.dylib shared.o
And the main program:
g++ -c main.cpp
g++ -o main main.o -L. -lshared
Only to get the following errors:
Undefined symbols:
"myclass<int>::getx()", referenced from:
_main in main.o
_main in main.o
"myclass<int>::setx(int)", referenced from:
_main in main.o
If I remove the 'template' stuff in shared.h/cpp, and replace them with just 'int', everything works fine. Also, if I just copy&paste the template class code right into main.cpp, and don't link to the shared library, everything works as well.
How can I get a template class like this to work through a shared library?
I'm using MacOS 10.5 with GCC 4.0.1.
In addition to the other answers, you can explicitly instantiate template classes. This is only useful if you know beforehand what types the template parameters may assume. You instantiate the template with all these types in the library.
For your example to compile, just add the following to the end of shared.cpp:
// Instantiate myclass for the supported template type parameters
template class myclass<int>;
template class myclass<long>;
This instantiates the template with Type=int and places the instantiated code in the shared library. Add as many explicit instantiations as you need, for all the types you need.
Again, if you want to be able to instantiate the template with any arbitrary Type parameter, then you must add the definitions to the header file, so that the compiler knows the source code of the template when instantiating it in other compilation units.
Template function definitions must reside in header files. Move the definitions from shared.cpp to shared.h.
So, you can't compile this to a shared library and then link to it. It just doesn't work like that.
You need to include the implementation of the template classes in the header files as well. This is a constraint of templates in C++. So either include shared.cpp from main (#include ) or just move the code from shared.cpp in shared.h
The compiler has to see all the code for a template, so it can generate the appropriate code for the actual type you want to use.
So you should place all the code in your .h. file.