У меня есть проект, который использует систему сборки autotools для создания статической библиотеки. Я хочу протестировать эту библиотеку, создав небольшую тестовую программу, которая ссылается на нее.
Тестовая программа создается в IDE code :: blocks. Пути, содержащие заголовки, были добавлены в каталоги поиска и добавлена включенная библиотека.
Когда я компилирую свою тестовую программу, я получаю следующую ошибку:
obj/Debug/main.o: In function `givens':
<snip> undefined reference to `xhypot(double, double)'
Тем не менее, xhypot является глобальной функцией, объявленной во включенном заголовке в real.h
как:
nr_double_t xhypot (const nr_double_t, const nr_double_t);
и определен в сопутствующем файле 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);
}
}
Тип nr_double_t определен в config.h как:
/* The global type of double representation. */
#define nr_double_t double
Где оскорбительный звонок xhypot
происходит в статической вспомогательной функции для класса шаблона, например, так:
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;
}
Тем не мение, xhypot
также вызывается в других нестатических функциях-членах класса с точно таким же синтаксисом (т.е. xhypot(double,double)
и если я заменю линию nr_double_t z = xhypot (a, b);
в этом статическом методе с линией nr_double_t z = 0.0;
ошибка исчезает.
Вот вся моя тестовая программа:
#include "config.h"#include "m_trsolver.h"
int main (int argc, char ** argv)
{
char infile[] = "test.net";
m_trsolver the_m_trsolver;;
return 0;
}
И полный журнал сборки:
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
Я использую code :: blocks 10.05 в Scientific Linux 6.1 с gcc 4.4.6 и передаю -DHAVE_CONFIG_H, так как есть много
#if HAVE_CONFIG_H
# include <config.h>
#endif
В источниках, с config.h
генерируется автоконф. Я должен также добавить, что код компилируется нормально при сборке в виде программы. Я извлек подмножество кода для этой программы (все, кроме одного файла) для помещения в эту статическую библиотеку.
Шаблон класса распространяется на два файла, eqnsys.h
а также eqnsys.cpp
, Я знаю, что это не лучшая практика, это, вероятно, было сделано, поскольку оно довольно большое. Это не мой код. eqnsys.cpp
включен в нижней части eqnsys.h
( #include "eqnsys.cpp"
). Статическая вспомогательная функция определена в eqnsys.cpp
, real.h
является #include
Эд на вершине eqnsys.cpp
но нет eqnsys.h
в случае, если это актуально. Добавление следующего в начало eqnsys.cpp
:
template class eqnsys<nr_complex_t>;
template class eqnsys<nr_double_t>;
Принудительное создание экземпляра не решает проблему. Если я изменю функцию givens на функцию-член вместо статической вспомогательной функции, ошибка исчезнет. Я мог бы пойти по этому пути, но какова истинная причина проблемы, чтобы я мог избежать ее в будущем?
Основываясь на командной строке сборки, вы только компилируете main.cpp
и вы не связываете какие-либо библиотеки. Вы должны связать библиотеку, которая содержит недостающие символы, или скомпилировать их источники в свой исполняемый файл.
В вашем случае, я думаю, правильное решение — это связать статическую библиотеку (которую вы пытаетесь протестировать) с вашей тестовой программой.
Это почти наверняка проблема создания экземпляра шаблона из-за того, что код вашего шаблона находится в .cpp, а не в .h.
Либо переместите свой код в заголовок — чтобы, когда это требуется компилятору, он мог создать экземпляр шаблона для типа, требуемого на лету, или оставить код в .cpp, но принудительно создать экземпляр шаблона (в верхней части файла .cpp) для шаблон arg вам нужно, добавив. Например:
// Explicite template instantiations
#pragma warning(disable: 4660) // For template-class specialization is already instantiated.
template class MyTemplateClass<MyTemplateParamClass>;