1

While creating a static library using c++11, it fails during linking I think.

I can create a static library and link to it using the information in How to create a static library with g++? with ordinary c++, but if I try to follow the steps using c++11 features, it fails during the linking.

test.cpp:

#include <iostream>
#include <vector>
#include "libtestlib.h"
using namespace std;

int  main() {
  itest n1={{1,2,3,4},
            {5,6,7,8},
            {9,0,1,2}};

  cout << "testing...\n";
  test_print(n1);

  return 0;
}

libtestlib.h:

#ifndef testlib
#define testlib

#include <vector>
using namespace std;

typedef vector<vector<double>> dtest;
typedef vector<vector<int>>    itest;

template <typename testtype>
void test_print(testtype);

#endif

libtestlib.cpp:

#include <iostream>
#include "libtestlib.h"
using namespace std;

template <typename testtype>
void test_print(testtype &t)
{
  int m=t.size();
  int n=t[0].size();
  for(int i=0; i<m; i++) {
    for(int j=0; j<n; j++)
      cout << t[i][j] << " ";
    cout << endl;
  }
  cout << endl;
}

this is the output I'm getting:

$ g++ -std=c++11 -c libtestlib.cpp

$ ar rvs libtestlib.a libtestlib.o
r - libtestlib.o

$ g++ -std=c++11 test.cpp libtestlib.a
/tmp/cccJ7SXZ.o:test.cpp:(.text+0x1af): undefined reference to `void test_print<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > >(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >)'
/tmp/cccJ7SXZ.o:test.cpp:(.text+0x1af): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `void test_print<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > >(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >)'
collect2: error: ld returned 1 exit status
Third
  • 21
  • 6
  • Your library is essentially empty since that is a templated function it won't have any instantiations. It should be in the libtestlib.h header or included into it. Once you do that you can statically compile it. – estabroo Apr 12 '19 at 21:56
  • Thanks for your response @estabroo. Can you give an example of what you mean? – Third Apr 12 '19 at 22:36
  • https://isocpp.org/wiki/faq/templates#templates-defn-vs-decl gives a good explanation. And for an example take your code above, move what's in libtestlib.cpp into libtestlib.h and compile it. `g++ --std=c++11 -static -o test_it test.cpp` – estabroo Apr 12 '19 at 22:48

2 Answers2

3

Since it seems you are supporting operations on a limited number of types, the classic "Just do it in a header" answer to this problem is not necessarily the best one.

You can get the best of both worlds by explicitely exporting a symbol for each implementation, but delegate the implementation to a template within the library:

libtestlib.h:

#ifndef testlib
#define testlib

#include <vector>
using namespace std;

typedef vector<vector<double>> dtest;
typedef vector<vector<int>>    itest;

void test_print(dtest&);
void test_print(itest&);

libtestlib.cpp:

#include <iostream>
#include "libtestlib.h"
using namespace std;

namespace {
  template <typename testtype>
  void test_print_impl(testtype &t)
  {
    int m=t.size();
    int n=t[0].size();
    for(int i=0; i<m; i++) {
      for(int j=0; j<n; j++)
        cout << t[i][j] << " ";
      cout << endl;
    }
    cout << endl;
  }
}

void test_print(dtest& val) {
  test_print_impl(val);
}

void test_print(itest& val) {
  test_print_impl(val);
}

Mind you, for a small function like this, it's probably not worth the effort, and just inlining the template code in the header is just fine. At what point does the complexity of a function and the scope of its dependencies warrant this is a bit of a judgement call.

  • Thanks @Frank! Your solution works for me, but of course my real situation is not as simple/small as this example. :) – Third Apr 12 '19 at 22:32
  • @Frank nice and actually gives you the option to build a static library, whereas in the header doesn't really lend itself to doing that. – estabroo Apr 12 '19 at 22:54
1

Putting example requested from comment on the question here as code looked really ugly in a comment. Combined libtestlib.h and libtestlib.cpp

#ifndef testlib
#define testlib

#include <vector>
#include <iostream>
using namespace std;

typedef vector<vector<double>> dtest;
typedef vector<vector<int>>    itest;

template <typename testtype>
void test_print(testtype &t)
{
  int m=t.size();
  int n=t[0].size();
  for(int i=0; i<m; i++) {
    for(int j=0; j<n; j++)
      cout << t[i][j] << " ";
    cout << endl;
  }
  cout << endl;
}
#endif
estabroo
  • 189
  • 5