1

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.

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.

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:

/* 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:

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:

#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

#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 #includeed at the top of eqnsys.cpp but not eqnsys.h in case this is relevant. Adding the following to the top of eqnsys.cpp:

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?

crobar
  • 2,810
  • 4
  • 28
  • 46
  • 2
    That's not what a "definition" means. `nr_double_t xhypot (const nr_double_t, const nr_double_t);` is just a declaration in C++, and `#define nr_double_t double` is a preprocessor definition. The linker complains about `m_trsolver` though, not `nr_double_t`. – Luchian Grigore May 24 '13 at 17:41
  • 1
    You're missing some object file or library? – Some programmer dude May 24 '13 at 17:41
  • @LuchianGrigore, yes, I made an error in the terminology, I mean `xhypot` is declared as `nr_double_t xhypot (const nr_double_t, const nr_double_t);` and the `nr_double_t` type is defined in `config.h` as `double`. The linker does complain about no `m_trsolver`, but the first error is about `xhypot(double, double)`. I don't know if these are related. I will edit to make a couple of corrections. – crobar May 25 '13 at 10:00
  • possible duplicate of [What is an undefined reference/unresolved external symbol error and how do I fix it?](http://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix) – Raymond Chen May 27 '13 at 21:44
  • @RaymondChen, thanks for the link, but looking through them I don't quite see the exact same problem. This might be my lack of understanding though. – crobar May 27 '13 at 22:05
  • "Failure to link against appropriate libraries/object files or compile implementation files." – Raymond Chen May 27 '13 at 22:25
  • @RaymondChen, yes, but there is no issue with linking other than in this one static function, and the error is with the `xhypot` function which is defined in other sources and works elsewhere in the same template class, why? This is not explained in that answer, I have read many other questions on stack overflow, but haven't seen the same problem. – crobar May 27 '13 at 22:29
  • It's in another answer: the function that is missing is not the same one you defined. There is probably a member function called xhypot that the other methods are calling. You never did say where xhypot is actually defined. Step in the debugger to see where the calls from nonstatic members are going. – Raymond Chen May 27 '13 at 22:38
  • @RaymondChen, `xhypot` is declared in a file `real.h` and defined in `real.cpp` it is a global function. It is called in other member functions of the template class with the exact same syntax as in this static member function, i.e. `xhypot(double,double)`. If I replace the line `nr_double_t z = xhypot (a, b);` in the static member function with `nr_double_t z = 0.0` the error disappears. `xhypot` is not a member function of the template class. – crobar May 28 '13 at 08:06
  • I've edited the question to make it more specific and potentially useful to others. – crobar May 28 '13 at 08:25
  • @RaymondChen, I made a mistake, the call occurs in a static helper function, not a member function. – crobar May 28 '13 at 09:05
  • I don't see real.o in the build log. I suspect the functions that "successfully" call xhypot are never actually called. – Raymond Chen May 28 '13 at 13:19

2 Answers2

0

Based on the build command line, you're only compiling main.cpp and you're not linking any libraries. You must a link a library which contains the missing symbols, or compile their sources into your executable as well.

In your case, I think the correct solution is to link the static library (which you're trying to test) into your test program.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • The library I'm linking to is `libqucsatorfull.a`, which I thought was being done by this bit of the command: `-L../qucs/qucs-core/src/math -o bin/Debug/qucs_m_interface_test obj/Debug/main.o ../qucs/qucs-core/src/libqucsatorfull.a`. Have I misunderstood? – crobar May 25 '13 at 09:55
  • @crobar You're right, I somehow missed that bit of the line. My bad. Is there a definition (body) of the function `xhypot` in the library? – Angew is no longer proud of SO May 25 '13 at 10:01
  • @Andrew, yes, I made a mistake originally, but only in that `xhypot` is declared in a header `real.h` (not a file named `eqnsys.h`), and definately has a definition in the corresponding `real.cpp`. – crobar May 25 '13 at 10:26
  • @crobar Is `real.cpp` part of the library? And is the definition of `nr_double_t` the same in both `real.cpp` and your test `main.cpp`? – Angew is no longer proud of SO May 25 '13 at 10:28
  • @Andrew, yes, real.cpp is part of the library and `nr_double_t` is defined in `config.h` which is the same `config.h` included in my program (it is generated for the library by autoconf). – crobar May 25 '13 at 10:52
  • @crobar This makes me out of ideas, sorry. Can you come up with a minimal complete example and post it here? – Angew is no longer proud of SO May 25 '13 at 11:04
  • @Andrew, thanks anyway, I'll see if I can narrow down the problem. – crobar May 25 '13 at 19:42
  • @Andrew, the class where the call to `xhypot` is is a template class, could this be significant? – crobar May 26 '13 at 16:52
0

This is almost certainly a template instantiation issue due to the fact that your template code is in the .cpp not the .h.
Either move your code to the header - so that when the compiler needs it it can instantiate the template for the type required on the fly or leave code in .cpp but force instantiation of the template (at the top of your .cpp file) for the template arg you need by adding . E.g:

// Explicite template instantiations
#pragma warning(disable: 4660) // For template-class specialization is already instantiated.
template class MyTemplateClass<MyTemplateParamClass>;
Ricibob
  • 7,505
  • 5
  • 46
  • 65
  • I added: `template class eqnsys;` and `template class eqnsys;`, which are the two types I know will be used, to the top of `eqnsys.cpp`. But I still get the same error. – crobar May 28 '13 at 11:16