Call to global fcn in template class static helper fcn result in linker errors, but not calls in member fcns?

Hello,

I'm a newbie to class templates, and a moderate C++ programmer in general. I have a project which uses the autotools build system to create a static library. I wish to test this library by making a small test program which links to it, but am getting undefined references in the linking step I do not understand.

The test program is being created in the code::blocks IDE. The paths containing the headers have been added to the search directories, and the included library added.

When I compile my test program I get the following error:

obj/Debug/main.o: In function 'givens':
<snip> undefined reference to `xhypot(double, double)


However, xhypot is a global function declared, in an included header in real.h as:

nr_double_t xhypot (const nr_double_t, const nr_double_t);

and defined in a companion file real.cpp.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
nr_double_t xhypot (const nr_double_t a, const nr_double_t b) {
    nr_double_t c = fabs (a);
    nr_double_t d = fabs (b);
    if (c > d) {
      nr_double_t e = d / c;
      return c * sqrt (1 + e * e);
    }
    else if (d == 0)
      return 0;
    else {
      nr_double_t e = c / d;
    return d * sqrt (1 + e * e);
  }
}


The type nr_double_t is defined in config.h as:

1
2
/* The global type of double representation. */
#define nr_double_t double 


Where the offending call to xhypot occurs is in a static helper function for a template class like so:

1
2
3
4
5
6
7
static nr_double_t
givens (nr_double_t a, nr_double_t b, nr_double_t& c, nr_double_t& s) {
  nr_double_t z = xhypot (a, b);
  c = a / z;
  s = b / z;
  return z;
}


However, xhypot is also called in other non-static member functions of the class with the exact same syntax (i.e. xhypot(double,double) and if I replace the line nr_double_t z = xhypot (a, b); in this static method with the line nr_double_t z = 0.0; the error disappears.

Here is the entirety of my test program:

1
2
3
4
5
6
7
8
9
10
11
12
#include "config.h"
#include "m_trsolver.h"

int main (int argc, char ** argv)
{
    
    char infile[] = "test.net";
    m_trsolver the_m_trsolver;;
    
    return 0;
    
}


And the full build log:

g++ -Wall -DHAVE_CONFIG_H  -g    -I../qucs/qucs-core -I../qucs/qucs-core/src -I../qucs/qucs-core/src/components -I../qucs/qucs-core/src/components/devices -I../qucs/qucs-core/src/components/digital -I../qucs/qucs-core/src/components/verilog -I../qucs/qucs-core/src/components/microstrip -I../qucs/qucs-core/src/converter -I../qucs/qucs-core/src/m-interface -I../qucs/qucs-core/src/math  -c /home/s0237326/src/qucs_m_interface_test/main.cpp -o obj/Debug/main.o
/home/s0237326/src/qucs_m_interface_test/main.cpp: In function ‘int main(int, char**)’:
/home/s0237326/src/qucs_m_interface_test/main.cpp:10: warning: unused variable ‘infile’
g++ -L../qucs/qucs-core -L../qucs/qucs-core/src -L../qucs/qucs-core/src/components -L../qucs/qucs-core/src/components/devices -L../qucs/qucs-core/src/components/digital -L../qucs/qucs-core/src/components/verilog -L../qucs/qucs-core/src/components/microstrip -L../qucs/qucs-core/src/converter -L../qucs/qucs-core/src/m-interface -L../qucs/qucs-core/src/math  -o bin/Debug/qucs_m_interface_test obj/Debug/main.o    ../qucs/qucs-core/src/libqucsatorfull.a 
obj/Debug/main.o: In function `givens':
/home/s0237326/src/qucs_m_interface_test/../qucs/qucs-core/src/eqnsys.cpp:1341: undefined reference to `xhypot(double, double)'
obj/Debug/main.o: In function `main':
/home/s0237326/src/qucs_m_interface_test/main.cpp:11: undefined reference to `m_trsolver::m_trsolver()'
/home/s0237326/src/qucs_m_interface_test/main.cpp:13: undefined reference to `m_trsolver::~m_trsolver()'
collect2: ld returned 1 exit status
Process terminated with status 1 (0 minutes, 0 seconds)
3 errors, 1 warnings


I'm using code::blocks 10.05 on Scientific Linux 6.1 with gcc 4.4.6 and I'm passing -DHAVE_CONFIG_H as there's lots of

1
2
3
#if HAVE_CONFIG_H
# include <config.h>
#endif 


In the sources, with config.h being generated by autoconf. I should also add that the code compiles fine when built as a program. I have extracted a subset of the code for this program (all but one file) to put into this static library.

The template class is spread over two files, eqnsys.h and eqnsys.cpp. I know it is not best practice to do this, it has probably been done as it is quite large. It is not my code. eqnsys.cpp is included at the bottom of eqnsys.h ( #include "eqnsys.cpp" ). The static helper function is defined in eqnsys.cpp. real.h is #include ed at the top of eqnsys.cpp but not eqnsys.h in case this is relevant.

Can anyone explain the error please?

p.s. This is for a free open source project.

well, the build log says that you compile main.cpp only. So the implementation of xhypot and m_trsolver are not part of your project.

do not put the template in a *.cpp file. Instead use a file extension the compiler doesn't know and hence doesn't want to compile (like .tpp or something like that)
Hi coder777

Thanks, I know that it is not best practice to split the code over two files, but this is someone else's code I am working from. Also if the implementation of xhypot is not part of my project why do the calls to xhypot in the member functions of the template class work fine? I compile main.cpp only as the implementation of the other things is in a static library I am linking to.

Adding the following to the top of eqnsys.cpp:

1
2
template class eqnsys<nr_complex_t>; 
template class eqnsys<nr_double_t>;


To force instantiation does not resolve the issue. If I change the givens function to be a member function instead of a static helper function the error disappears. This is the route I might take, but what is the real root of the issue so I can avoid it in future?

p.s. The m_trsolver problem is a separate, probably simpler issue, I'm concentrating on the first error just now.
Last edited on
Also if the implementation of xhypot is not part of my project why do the calls to xhypot in the member functions of the template class work fine?
Because the compiler needs only the prototypes. The linker is the one how complains, not the compiler.

but what is the real root of the issue so I can avoid it in future?
where are the implementations of xhypot and m_trsolver? Either add the implementation files or the appropriate library to your project
xhypot is a global function declared, in an included header in real.h as:

nr_double_t xhypot (const nr_double_t, const nr_double_t);

and defined in a companion file real.cpp. These are compiled into the static library I link to. xhypot has nothing to do with the template class, it is a non-templated normal global function from a separate source called by the template class in a couple of places. The calls in member function of the template class work fine, the calls in the static function cause the linker error. I have added the library to my project, it is the libqucsatorfull.a library linked in my (rather long) g++ command shown above:

g++ <snip> -o bin/Debug/qucs_m_interface_test obj/Debug/main.o ../qucs/qucs-core/src/libqucsatorfull.a

The linker knows about xhypot, as it does not complain about its use here or elsewhere, only in the call in the static function of the template class, and if I change this from being a static function to being a member function the error goes away. Sorry if I have misunderstood anything you're trying to tell me.

Topic archived. No new replies allowed.