Linker error with Boost Serialization using a specific class in a test executable but not in the executable
I am using Boost 1.49, OpenCV 2.3.1, CMake 2.8 in a C ++ project.
I am creating two executables with the same header file, one for production and the other for testing. The file contest.hpp
indicates:
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);
}
}
and they are implemented in a file contest.cpp
like
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;
}
}
}
And test-contest.cpp
mundanely checks them like
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);
}
where sr
and are ar
defined common.hpp
as
namespace ar = ::boost::archive;
namespace sr = ::boost::serialization;
Make files are generated from CMake configuration, for example:
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)
So the moral of this story is that both contest
are test-contest
compiled and linked to the same headers and libraries . Please note that other Boost libraries are linked and tested successfully.
When it comes to make
after cmake 'Unix Makefiles' ..
, for contest
he says
[ 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
but for 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
And IMHO the weirdest part, there is no error for serialize(Archive, cv::Point, int)
which is from the same header / library in OpenCV with serialize(Archive, cv::Rect_<int>, int)
or cv::Size_<int>
. Their serialization / testing functions are almost identical.
I am linking these serialize
functions from a file contest.cpp
successfully. I tried to replace Rect
with Rect_<int>
in the definitions, without any changes. I tried to reorder the libraries in CMakeLists.txt
and took boost_serialization
from the end to its current location, to no avail.
Where am I doing this wrong?
source to share
It seems to me you need implementations of three functions serialize
ported from contest.cpp
to contest.hpp
.
For what reasons, see Why templates can only be implemented in a header file? or Why does the injection and declaration of a template class have to be in the same header file?
source to share