campreilly / UnderSeaModelingLibrary

The Under Sea Modeling Library (USML) is a collection of C++ software development modules for sonar modeling and simulation.
Other
45 stars 22 forks source link

Compiling usml_test in Windows creates duplicate symbol for data_grid<double,1> #81

Closed campreilly closed 9 years ago

campreilly commented 9 years ago

As part of preparing for USML 1.0.0 release, we are re-testing our ability to compile and run using Microsoft Visual C++ 2010 Express. When we compile usml_test with debug, the link sees duplicate symbols for all data_grid<double,1> methods.

campreilly commented 9 years ago
1>------ Rebuild All started: Project: ZERO_CHECK, Configuration: Debug Win32 ------
1>  Checking Build System
1>  CMake is re-running because C:/Development/Projects/usml-build/CMakeFiles/generate.stamp is out-of-date.
1>    the file 'C:/Development/Projects/usml/CMakeLists.txt'
1>    is newer than 'C:/Development/Projects/usml-build/CMakeFiles/generate.stamp.depend'
1>    result='-1'
1>  -- USML version 1.0.0
1>  -- Boost version: 1.57.0
1>  -- processing ublas
1>  -- processing types
1>  -- processing netcdf
1>  -- processing ocean
1>  -- processing waveq3d
1>  -- processing ublas/test
1>  -- processing types/test
1>  -- processing netcdf/test
1>  -- processing ocean/test
1>  -- processing waveq3d/test
1>  -- Configuring done
1>  -- Generating done
1>  -- Build files have been written to: C:/Development/Projects/usml-build
2>------ Rebuild All started: Project: usml, Configuration: Debug Win32 ------
2>  Building Custom Rule C:/Development/Projects/usml/CMakeLists.txt
2>  CMake does not need to re-run because C:\Development\Projects\usml-build\CMakeFiles\generate.stamp is up-to-date.
2>  randgen.cc
2>  trapfpe.cc
2>  wposition.cc
2>  wposition1.cc
2>  wvector.cc
2>  wvector1.cc
2>  netcdf_bathy.cc
2>  netcdf_profile.cc
2>  netcdf_woa.cc
2>  ascii_arc_bathy.cc
2>  ascii_profile.cc
2>  attenuation_constant.cc
2>  attenuation_thorp.cc
2>  boundary_flat.cc
2>  boundary_slope.cc
2>  profile_catenary.cc
2>  profile_linear.cc
2>  profile_model.cc
2>  profile_munk.cc
2>  profile_n2.cc
2>  reflect_loss_beckmann.cc
2>  reflect_loss_netcdf.cc
2>  reflect_loss_rayleigh.cc
2>  reflect_loss_rayleigh_grid.cc
2>  ode_integ.cc
2>  proploss.cc
2>  reflection_model.cc
2>  spreading_hybrid_gaussian.cc
2>  spreading_ray.cc
2>  wave_front.cc
2>  wave_queue.cc
2>  wave_queue_netcdf.cc
2>     Creating library C:/Development/Projects/usml-build/Debug/usml.lib and object C:/Development/Projects/usml-build/Debug/usml.exp
2>     Creating library C:/Development/Projects/usml-build/Debug/usml.lib and object C:/Development/Projects/usml-build/Debug/usml.exp
2>  usml.vcxproj -> C:\Development\Projects\usml-build\Debug\usml.dll
3>------ Rebuild All started: Project: usml_test, Configuration: Debug Win32 ------
3>  Building Custom Rule C:/Development/Projects/usml/CMakeLists.txt
3>  CMake does not need to re-run because C:\Development\Projects\usml-build\CMakeFiles\generate.stamp is up-to-date.
3>  usml_test.cc
3>  matrix_test.cc
3>  randgen_test.cc
3>  vector_test.cc
3>  datagrid_test.cc
3>  position_test.cc
3>  sequence_test.cc
3>  read_bathy_test.cc
3>  read_profile_test.cc
3>  attenuation_test.cc
3>  boundary_test.cc
3>  profile_test.cc
3>  reflect_loss_test.cc
3>  eigenray_test.cc
3>  proploss_test.cc
3>  reflection_test.cc
3>  refraction_test.cc
3>usml.lib(usml.dll) : error LNK2005: "public: double __thiscall usml::types::data_grid<double,1>::data(unsigned int const *)const " (?data@?$data_grid@N$00@types@usml@@QBENPBI@Z) already defined in datagrid_test.obj
3>usml.lib(usml.dll) : error LNK2005: "public: void __thiscall usml::types::data_grid<double,1>::edge_limit(unsigned int,bool)" (?edge_limit@?$data_grid@N$00@types@usml@@QAEXI_N@Z) already defined in datagrid_test.obj
3>usml.lib(usml.dll) : error LNK2005: "public: void __thiscall usml::types::data_grid<double,1>::interp_type(unsigned int,enum usml::types::GRID_INTERP_TYPE)" (?interp_type@?$data_grid@N$00@types@usml@@QAEXIW4GRID_INTERP_TYPE@23@@Z) already defined in datagrid_test.obj
3>usml.lib(usml.dll) : error LNK2005: "public: void __thiscall usml::types::data_grid<double,1>::data(unsigned int const *,double)" (?data@?$data_grid@N$00@types@usml@@QAEXPBIN@Z) already defined in datagrid_test.obj
3>usml.lib(usml.dll) : error LNK2005: "public: __thiscall usml::types::data_grid<double,1>::data_grid<double,1>(class usml::types::seq_vector * * const)" (??0?$data_grid@N$00@types@usml@@QAE@QAPAVseq_vector@12@@Z) already defined in datagrid_test.obj
3>usml.lib(usml.dll) : error LNK2005: "public: virtual __thiscall usml::types::data_grid<double,1>::~data_grid<double,1>(void)" (??1?$data_grid@N$00@types@usml@@UAE@XZ) already defined in datagrid_test.obj
3>C:\Development\Projects\usml-build\Debug\usml_test.exe : fatal error LNK1169: one or more multiply defined symbols found
========== Rebuild All: 2 succeeded, 1 failed, 0 skipped ==========
campreilly commented 9 years ago

This appears to be a problem with Microsoft DLL export and C++ templates, similar to the one discussed on http://www.codesynthesis.com/~boris/blog/2010/01/18/dll-export-cxx-templates/ .

It appears that the usml.dll and the usml_test.exe are both trying to create a non-inline version of data_grid<double,1>. Because the DLL exporting logic is not right, usml_test.exe doesn't realize that usml.dll already has a copy of this template specialization.

At the suggestion of this article, we tried

campreilly commented 9 years ago

If we explicitly export the template class, the problem seems to go away. Do do this, we created a new USML_DLLEXPORT symbol in usml_config.h. If building shared libraries on Windows, USML_DLLEXPORT becomes __declspec(dllexport); in other cases it is empty.

Unlike, USML_DECLSPEC, it does not switch between dllimport and dllexport.