Reputation:
Edit: I have updated my question with changes I've made, upon answers.
I'm trying to link to a little library that I've wrote to learn ho this is done with C++ with no luck. G++ is complaining with undefined reference
.
The root directory of library I want to link is in directory ~/code/gklib/cxx/
. The structure of this directory is as follows:
~/code/gklib/cxx/
|
|`-> gk.{hh,cc}
|`-> libgk.o
|
`-> lib/
|
`-> libgk.a
I have compiled gk.cc
with -c
flag, then transformed the resulting object file to a .a file with ar rvsc lib/libgk.a libgk.o
.
The client to this library is at folder ~/code/cpp
. In this directory I compiled some_stuff.cc
to an object file again, then I tried to link to it with this command:
$ cxx some_stuff.o -L../gklib/cxx/lib -lgk -o some_stuff
I get this error:
some_stuff.o: In function `main':
some_stuff.cc:(.text+0x49): undefined reference to `void GK::algorithms::insertionSort<int, 5ul>(int*)'
collect2: error: ld returned 1 exit status
These are contents of these files:
~/code/cpp/some_stuff.cc
#include <cstdlib>
#include <iostream>
#include <gk.hh>
using namespace std;
int main(int argc, char **argv) {
int i = -1;
int arr[5] = { 3, 4, 2, 1, 5 };
const size_t len = sizeof(arr)/sizeof(int);
GK::algorithms::insertionSort<int, len>(arr);
while(++i < 5)
cout << arr[i] << " ";
cout << endl;
exit(EXIT_SUCCESS);
}
~/code/gklib/cxx/gk.cc
#include "gk.hh"
template<class T, size_t len>
void GK::algorithms::insertionSort(T arr[len]){
// insertion sort
}
~/code/gklib/cxx/gk.hh
#pragma once
#include <cstdlib>
#define NAMESPACE(ns) namespace ns {
#define END_NAMESPACE(ns) }
NAMESPACE(GK)
NAMESPACE(algorithms)
template<class T, size_t len>
extern void insertionSort(T arr[len]);
END_NAMESPACE(algorithms)
END_NAMESPACE(GK)
I've tried many variations on my commands with no result. Internet is full of tutorials and forums with instructions those did not work for me. This code ran perfectly when all the stuff was in one file. How can I resolve this problem? Thanks in advance.
Upvotes: 0
Views: 270
Reputation: 153889
I see several problems: in order:
If this is your exact command line, the -L
option doesn't
point to the structure you've shown above (where there is no
cxx
in the path).
I don't know why you're using -B
. This tells the compiler
where to look for its libraries, etc. Normally, this is only
necessary when you want to test parts of the compiler you've
modified.
I don't see where you've specified to link against the
library. Since the library doesn't respect the usual naming
conventions (libname.a
), you'll have to
specify it directly (in the same way you'd specify an object
file), and the -L
option isn't used. Alternatively, you name
it libgk.a
, or something like that, and add a -lgk
to the
command line, after your object files.
Finally, the error messages refer to an instantiation of a template. This typically occurs because the implementation of the template is in a source file, not in the header. The standard requires that the implementation be visible when it triggers the instantiation of a template. The way g++ (and almost every other compiler) works is that if the implementation isn't visible, they suppose that the template will be instantiated in another translation unit, and output external references to it. But if the implementation is in a source, there will be no instantiation, and you'll get a linker error. (You'll also not find the assembler for the instantiation anywhere, either, because the template hasn't been instantiated.) You should include the source code at the bottom of your header, and not compile it separately.
Upvotes: 0
Reputation:
I have solved this problem, with the help of this and this questions. The problem lies in the fact that void insertionSort(T *)
is a template function, and template functions can only be implemented in header files. The reason for this is, the compiler needs to reach the definition of the to create a new function for each call to it with a different type as the argument to template. I have moved the definition of this function to gk.h
, which resulted in a successfull compilation and linkage.
Upvotes: 0
Reputation: 444
I think it's more something like:
cxx some_stuff.o -L$HOME/gklib/cxx/lib -B../gklib/cxx/lib -lgklib -o some_stuff
-lgklib
, not -Igklib
(-I
option specify an include folder)
but you'll have to rename your gklib.a
by libgklib.a
Maybe you can even remove -B../gklib/cxx/lib
, just try it out :)
Upvotes: 1