vendredi 2 août 2019

Can "undefined reference to vtable" error be linker-specific?

I am trying to compile my C++ code on a cluster using a different version of gcc; I run into this "undefined reference to vtable" linker error, which doesn't show up when I compile on my local machine.

What I am trying to do is to create a static library for Romberg integration, to be used in my main code. I successfully create the library, and when I compile on my local machine no linker error is reported and the code works just fine. However, when trying to compile on a cluster machine, the following error is displayed, at linking stage:

undefined reference to `vtable for Poly_interp'

I tried to check whether there where some virtual functions left undefined in derived classes, or if a virtual destructor was define, but I couldn't spot any mistake.

These are the part of my code I reckon may be 'indicted':

Makefile

CXX = g++

STANDARD = -std=c++11

[...]

RESULT = ../libraries/libromberg.a

SRC = poly_interp.cpp base_interp.cpp
OBJS := $(SRC:%.cpp=%.o)
HEADERS = $(wildcard *.hpp)

poly_interp.o: recipe_types.hpp base_interp.hpp poly_interp.hpp
base_interp.o: recipe_types.hpp base_interp.hpp

[...]

all: $(RESULT)

$(RESULT): $(OBJS) $(HEADERS)
    ar rs $@ $^

[...]

base_interp.hpp

struct Base_interp
{
  Int n, mm, jsav, cor, dj;
  const Doub *xx, *yy;
  Base_interp(VecDoub_I &x, const Doub *y, Int m)
  : n(x.size()), mm(m), jsav(0), cor(0), xx(&x[0]), yy(y)
  {
    dj = MIN(1,(int)pow((Doub)n,0.25));
  }
  Doub interp(Doub x)
  {
    Int jlo = cor ? hunt(x) : locate(x);
    return rawinterp(jlo,x);
  }
  Int locate(const Doub x);
  Int hunt(const Doub x);
  Doub virtual rawinterp(Int jlo, Doub x) = 0;
};

poly_interp.hpp

#include "base_interp.hpp"
struct Poly_interp : Base_interp
{
  Doub dy;
  Poly_interp(VecDoub_I &xv, VecDoub_I &yv, Int m)
    : Base_interp(xv,&yv[0],m), dy(0.) {}
  Doub rawinterp(Int jl, Doub x) override;
};

poly_interp.cpp

#include "poly_interp.hpp"
Doub Poly_interp::rawinterp(Int jl, Doub x)
{
  Int i,m,ns=0;
  Doub y,den,dif,dift,ho,hp,w;
  const Doub *xa = &xx[jl], *ya = &yy[jl];
  VecDoub c(mm),d(mm);
  dif=abs(x-xa[0]);
  for (i=0;i<mm;i++)
  {
  if ((dift=abs(x-xa[i])) < dif)
  {
    ns=i;
    dif=dift;
  }
  c[i]=ya[i];
  d[i]=ya[i];
  }
  y=ya[ns--];
  for (m=1;m<mm;m++)
  {
    for (i=0;i<mm-m;i++)
    {
      ho=xa[i]-x;
      hp=xa[i+m]-x;
      w=c[i+1]-d[i];
      if ((den=ho-hp) == 0.0) throw("Poly_interp error");
      den=w/den;
      d[i]=hp*den;
      c[i]=ho*den;
    }
    y += (dy=(2*(ns+1) < (mm-m) ? c[ns+1] : d[ns--]));
  }
  return y;
}

Compiler version on my machine:

MacBook-Pro-4:~ macbookpro$ gcc -v
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 10.0.0 (clang-1000.11.45.2)
Target: x86_64-apple-darwin17.7.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
Found CUDA installation: /usr/local/cuda, version unknown


Compiler version on the cluster machine:

mpellegrino@node-5-1 enskog_vlasov_serial $ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/software/matematica/sw/pkgs/toolchains/gcc-glibc/5/prefix/bin/../libexec/gcc/x86_64-mk-linux/5.3.0/lto-wrapper
Target: x86_64-mk-linux
Configured with: ../gcc-5.3.0/configure --build=x86_64-mk-linux --prefix=/u/sw/pkgs/toolchains/gcc-glibc/5/prefix --with-local-prefix=/u/sw/pkgs/toolchains/gcc-glibc/5/base --with-native-system-header-dir=/u/sw/pkgs/toolchains/gcc-glibc/5/prefix/include --with-pkgversion=mk --with-bugurl=https://bitbucket.org/mattiapenati/mk/issues --disable-nls --disable-multilib --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-lto --enable-libgomp --disable-libstdcxx-pch --enable-bootstrap --enable-languages=c,c++,fortran
Thread model: posix
gcc version 5.3.0 (mk)

I solved... no, actually I didn't solve the problem: I by-passed it by putting everything in a header file (so, no poly_interp.o and base_interp.o are created, as well as the static library), but I believe this to be a quite inelegant solution. The full Linker error is the following

/tmp/ccj8ToBh.o: In function `Poly_interp::Poly_interp(std::vector<double, std::allocator<double> > const&, std::vector<double, std::allocator<double> > const&, int)':
/home/matematica/mpellegrino/enskog_vlasov/enskog_vlasov_serial/./romberg/poly_interp.hpp:16: undefined reference to `vtable for Poly_interp'
/tmp/ccj8ToBh.o: In function `double qromb<std::function<double (double)> >(std::function<double (double)>&, double, double, double)':
/home/matematica/mpellegrino/enskog_vlasov/enskog_vlasov_serial/./romberg/romberg.hpp:34: undefined reference to `Poly_interp::rawinterp(int, double)'
collect2: error: ld returned 1 exit status
Makefile:32: recipe for target 'main' failed
make: *** [main] Error 1

Aucun commentaire:

Enregistrer un commentaire