"undefined reference" link error in Makefile
Oct 4, 2014 at 2:18am UTC
This was running before I changed Row to a template class.
Now it gets this error:
>make
g++ -ggdb -Wall -std=c++11 -c ../../lib/ScanCode/Sa.cpp -o obj/Sa.o
g++ -ggdb -Wall -std=c++11 -c ../../lib/ScanCode/Sb.cpp -o obj/Sb.o
g++ -ggdb -Wall -std=c++11 -c ../../lib/Key/Ke.cpp -o obj/Ke.o
g++ -ggdb -Wall -std=c++11 -c ../../lib/Row/RowBase.cpp -o obj/RowBase.o
g++ -ggdb -Wall -std=c++11 -c ../../lib/Row/Row.cpp -o obj/Row.o
g++ -ggdb -Wall -std=c++11 -c ../../lib/Matrix/MatrixA.cpp -o obj/MatrixA.o
g++ -ggdb -Wall -std=c++11 -c ../../lib/Keyboard/Keyboard.cpp -o obj/Keyboard.o
g++ -ggdb -Wall -std=c++11 -c keyboard1.cpp -o obj/keyboard1.o
g++ obj/Sa.o obj/Sb.o obj/Ke.o obj/RowBase.o obj/Row.o obj/MatrixA.o obj/Keyboar
d.o obj/keyboard1.o -o a.exe
obj/keyboard1.o:keyboard1.cpp:(.rdata$_ZTV3RowILi4EE[__ZTV3RowILi4EE]+0x8): unde
fined reference to `Row<4>::scan()'
collect2.exe: error: ld returned 1 exit status
make: *** [a.exe] Error 1
Makefile:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
# Macros ****************************************************
COMPILER = g++ -ggdb -Wall -std=c++11 -c
OBJ = obj/Sa.o obj/Sb.o obj/Ke.o obj/RowBase.o obj/Row.o obj/MatrixA.o obj/Keyboard.o obj/keyboard1.o
KEYBOARD_PATH = ../../lib/Keyboard/
MATRIX_PATH = ../../lib/Matrix/
MAT_PARENT = $(MATRIX_PATH)Matrix.cpp $(MATRIX_PATH)Matrix.h
ROW_PATH = ../../lib/Row/
KEY_PATH = ../../lib/Key/
KEY_PARENT = $(KEY_PATH)Key.cpp $(KEY_PATH)Key.h
SC_PATH = ../../lib/ScanCode/
SC_PARENT = $(SC_PATH)ScanCode.cpp $(SC_PATH)ScanCode.h
# Targets ****************************************************
all: a.exe
# link object files
a.exe: $(OBJ)
g++ $^ -o $@
# (obj file from previouse rule is needed, linker did not detect ScanCode change)
# keyboard1
obj/keyboard1.o: keyboard1.cpp obj/Keyboard.o
$(COMPILER) keyboard1.cpp -o $@
# lib
obj/Keyboard.o: $(KEYBOARD_PATH)Keyboard.cpp $(KEYBOARD_PATH)Keyboard.h obj/MatrixA.o
$(COMPILER) $(KEYBOARD_PATH)Keyboard.cpp -o $@
obj/MatrixA.o: $(MATRIX_PATH)MatrixA.cpp $(MATRIX_PATH)MatrixA.h $(MATRIX_PARTENT) obj/Row.o
$(COMPILER) $(MATRIX_PATH)MatrixA.cpp -o $@
obj/Row.o: $(ROW_PATH)Row.cpp $(ROW_PATH)Row.h obj/RowBase.o obj/Ke.o
$(COMPILER) $(ROW_PATH)Row.cpp -o $@
obj/RowBase.o: $(ROW_PATH)RowBase.cpp $(ROW_PATH)RowBase.h
$(COMPILER) $(ROW_PATH)RowBase.cpp -o $@
obj/Ke.o: $(KEY_PATH)Ke.cpp $(KEY_PATH)Ke.h $(KEY_PARTENT)obj/Sa.o obj/Sb.o
$(COMPILER) $(KEY_PATH)Ke.cpp -o $@
obj/Sb.o: $(SC_PATH)Sb.cpp $(SC_PATH)Sb.h $(SC_PARENT)
$(COMPILER) $(SC_PATH)Sb.cpp -o $@
obj/Sa.o: $(SC_PATH)Sa.cpp $(SC_PATH)Sa.h $(SC_PARENT)
$(COMPILER) $(SC_PATH)Sa.cpp -o $@
#clean
clean:
rm $(OBJ)
Row.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
#ifndef Row_h
#define Row_h
#include <iostream>
#include "RowBase.h"
#include "../Key/Key.h"
template < int sampleSize >
class Row : public RowBase
{
private :
Key*const *const ptrsKeys; // row is composed of an array of Keys
const int numCols;
int samples[sampleSize]; // array size not specified
public :
//Row(Key*const pk[], const int nc): ptrsKeys(pk), numCols(nc) { }
Row< sampleSize >(Key*const pk[], const int nc): ptrsKeys(pk), numCols(nc) { }
void scan();
};
#endif
Row.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#include "Row.h"
template < int sampleSize >
void Row< sampleSize >::scan()
{
for (int i=0; i<numCols; i++)
{
ptrsKeys[i]->press();
}
for (int j = 0; j < sampleSize; j++) // traverse ring buffer
{
samples[j] = j;
std::cout << samples[j];
}
std::cout << std::endl;
}
RowBase.h:
1 2 3 4 5 6 7 8
#ifndef RowBase_h
#define RowBase_h
class RowBase
{
public :
virtual void scan() = 0;
};
#endif
RowBase.cpp:
1 2
#include "RowBase.h"
//empty file
What is the source of the error?
Thank you.
Oct 4, 2014 at 2:35am UTC
you can't create an object ( Row.o ) out of a template. All of the code in Row.cpp needs to be moved to Row.h and then delete Row.cpp. Remove the compilation of Row.o from your makefile.
Oct 4, 2014 at 3:36am UTC
Lowest0ne,
That worked! C++ syntax/linker blows my mind again.
you can't create an object ( Row.o ) out of a template.
Thanks for your help.
Oct 4, 2014 at 3:44am UTC
I don't know much about it, but it does make sense to me. The template is just a template, the actual typed code only gets created when you call the function. How can the compiler make an object out of something if it doesn't know the type?
I have seen strategies such as this:
1 2 3 4 5 6 7 8 9
// file.h
#ifndef FILE_H
#define FILE_H
template <typename T>
void func( const T& value );
#include <file.cpp>
#endif
1 2 3 4 5 6
// file.cpp
template < typename T>
void func( const T& value )
{
// do it
}
Which will technically work. However, you must be sure not to try to compile file.cpp into an object. As you get better at writing makefiles, you will see that having certain cpp files that should not be compiled only complicates things.
Oct 4, 2014 at 4:40am UTC
I like your strategy of not having .cpp file if it should not be compiled.
So I guess Row.h does not need a compile command because it is included by other files as needed. For those files I added Row.h to Makefile dependencies.
Thank you for sharing your insights; I learned something today.
Topic archived. No new replies allowed.