0

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.

3 Answers3

1

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 :)

SeedmanJ
  • 444
  • 2
  • 8
  • Please surround code bits with backticks, as there is no difference between __capital i__ and __lowercase l__ in many Sans-Serif fonts. –  Feb 07 '13 at 16:36
0

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.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • I've pasted the wrong cxx command. I updated it with the true one I used. And, I applied all of your suggestions, still having a reference error. –  Feb 07 '13 at 17:05
  • Additionally, I observed that, when compiled with `-S` flag, this function is not included in the resulting `gk.s` assembly file. –  Feb 07 '13 at 17:31
  • @G.Kayaalp I still see a `-L` with a path with `cxx`, and no `cxx` in the diagram. As for the function... It's an instantiation of a function template, so you won't find it in the library. You did include the source code for it in your header, didn't you? – James Kanze Feb 07 '13 at 18:55
  • The diagram itself starts under the `~/code/gklib/cxx/` directory. It does not containt the client code. And the function was the part that I shot myself in my foot; putting the implemetation apart from the header. I naively thought that I would just do it in the C way :) –  Feb 07 '13 at 21:07
  • @G.Kayaalp Yes. Templates are nice, but they're sort of broken in this respect. (Having to put the implementation in the header increases coupling enormously.) – James Kanze Feb 08 '13 at 09:15
  • Templates are why I like C++. I personally think that they are way better than void pointers etc. BTW if you move the related comment to your answer, I'll accept it as it has been helpful for other things. –  Feb 08 '13 at 10:14
  • @G.Kayaalp They're way better than void*, that's for sure. Before templates were added to C++, we simulated them with macros (`generic.h`); once you've done that, you really understand why they were added to the language. But the fact that they require the implementation code in the header definitely increased coupling, and is a real downer. Especially since the earliest implementations didn't require it. – James Kanze Feb 08 '13 at 10:39
0

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.

Community
  • 1
  • 1