Ошибка компоновщика с Boost Serialization с использованием определенного класса в тестовом исполняемом файле, но не в производственном исполняемом файле - PullRequest
3 голосов
/ 27 марта 2012

Я использую Boost 1.49, OpenCV 2.3.1, CMake 2.8 в проекте C ++.

Я создаю два исполняемых файла с одним и тем же заголовочным файлом, один для производства, а другой для тестирования. Файл contest.hpp указывает:

namespace boost
{
   namespace serialization 
   {

   template<class Archive>
   void serialize(Archive& ar, cv::Point& p, const unsigned int version);

   template<class Archive>
   void serialize(Archive& ar, cv::Rect_<int>& r, const unsigned int version);

   template<class Archive>
   void serialize(Archive& ar, cv::Size_<int>& s, const unsigned int version);
   }
}

и они реализованы в contest.cpp файле типа

namespace boost
{
    namespace serialization
    {

    template<class Archive>
    void serialize(Archive& ar, cv::Point& p, const unsigned int version)
    {
        ar & p.x;
        ar & p.y;
    }

    template<class Archive>
    void serialize(Archive& ar, cv::Rect_<int>& r, const unsigned int version)
    {
        ar & r.x;
        ar & r.y;
        ar & r.height;
        ar & r.width;
    }

    template<class Archive>
    void serialize(Archive& ar, cv::Size_<int>& s, const unsigned int version)
    {
        ar & s.width;
        ar & s.height;
    }

    }
}

И test-contest.cpp обычным образом проверяет подобные

    BOOST_AUTO_TEST_CASE(Serialization1)
{

Point point_write(3, 5);
{
    ofstream point_file("Point.txt");
    ar::text_oarchive point_archive(point_file);
    sr::serialize(point_archive, point_write, 0);
}
Point point_read(0, 0);
{
    ifstream point_file("Point.txt");
    ar::text_iarchive point_archive(point_file);
    sr::serialize(point_archive, point_read, 0);
}
BOOST_CHECK(point_read == point_write);


Rect rect_write(3, 5, 1, 7);
{
    ofstream rect_file("Rect.txt");
    ar::text_oarchive rect_archive(rect_file);
    sr::serialize(rect_archive, rect_write, 0);
}
Rect rect_read(0, 0, 0, 0);
{
    ifstream rect_file("Rect.txt");
    ar::text_iarchive rect_archive(rect_file);
    sr::serialize(rect_archive, rect_read, 0);
}
BOOST_CHECK((rect_read.x) == (rect_write.y) && (rect_read.y) == (rect_write.y));

Size size_write(3, 5);
{
    ofstream size_file("Size.txt");
    ar::text_oarchive size_archive(size_file);
    sr::serialize(size_archive, size_write, 0);
}
Size size_read(0, 0);
{
    ifstream size_file("Size.txt");
    ar::text_iarchive size_archive(size_file);
    sr::serialize(size_archive, size_read, 0);
}
BOOST_CHECK(size_read == size_write);
}

, где sr и ar определены в common.hpp как

namespace ar = ::boost::archive;
namespace sr = ::boost::serialization;

make-файлы создаются из конфигурации CMake, например:

link_directories(${DEPENDENCY_DIR}/libboost/lib)
link_directories(${DEPENDENCY_DIR}/libopencv/lib)

add_executable(test-contest test-contest.cpp contest.cpp)
add_executable(contest main.cpp contest.cpp)

target_link_libraries(test-contest boost_serialization opencv_core opencv_highgui opencv_imgproc boost_program_options boost_unit_test_framework boost_filesystem)

target_link_libraries(contest boost_serialization opencv_core opencv_highgui opencv_imgproc boost_program_options boost_filesystem)

Итак, мораль этой истории состоит в том, что contest и test-contest скомпилированы и связаны с одинаковыми библиотеками header и . Обратите внимание, что другие библиотеки Boost связаны и успешно протестированы.

Когда дело доходит до make после cmake 'Unix Makefiles' .., для contest это говорит

[ 40%] Building CXX object CMakeFiles/contest.dir/main.cpp.o
[ 60%] Building CXX object CMakeFiles/contest.dir/contest.cpp.o
Linking CXX executable contest
[ 60%] Built target contest

но для test-contest

[ 80%] Building CXX object CMakeFiles/test-contest.dir/test-contest.cpp.o
[100%] Building CXX object CMakeFiles/test-contest.dir/contest.cpp.o
Linking CXX executable test-contest
CMakeFiles/test-contest.dir/test-contest.cpp.o: In function `otap::TPageImage::Serialization1::test_method()':
/home/iesahin/Repository/otapexplorer/cli/contest-2012/test-contest.cpp:119: undefined reference to `void boost::serialization::serialize<boost::archive::text_oarchive>(boost::archive::text_oarchive&, cv::Rect_<int>&, unsigned int)'
/home/iesahin/Repository/otapexplorer/cli/contest-2012/test-contest.cpp:125: undefined reference to `void boost::serialization::serialize<boost::archive::text_iarchive>(boost::archive::text_iarchive&, cv::Rect_<int>&, unsigned int)'
/home/iesahin/Repository/otapexplorer/cli/contest-2012/test-contest.cpp:133: undefined reference to `void boost::serialization::serialize<boost::archive::text_oarchive>(boost::archive::text_oarchive&, cv::Size_<int>&, unsigned int)'
/home/iesahin/Repository/otapexplorer/cli/contest-2012/test-contest.cpp:139: undefined reference to `void boost::serialization::serialize<boost::archive::text_iarchive>(boost::archive::text_iarchive&, cv::Size_<int>&, unsigned int)'
collect2: ld returned 1 exit status
make[2]: *** [test-contest] Error 1

И, ИМХО, самая странная часть в том, что нет ошибок для serialize(Archive, cv::Point, int) из того же заголовка / библиотеки в OpenCV с serialize(Archive, cv::Rect_<int>, int) или cv::Size_<int>. Их функции сериализации / тестирования определены почти одинаково.

Я успешно связываю эти serialize функции из файла contest.cpp. Я попытался заменить Rect на Rect_<int> в определениях, без изменений. Я попытался изменить порядок библиотек в CMakeLists.txt и взял boost_serialization с конца на его текущее место, но безрезультатно.

Где я делаю это неправильно?

1 Ответ

2 голосов
/ 27 марта 2012

Я думаю, вам нужны реализации ваших трех serialize функций, перемещенных с contest.cpp на contest.hpp.

По причинам, см. Почему шаблоны могут быть реализованы только в файле заголовка? или Почему реализация и объявление класса шаблона должны находиться в одном файле заголовка?

...