简体   繁体   中英

Undefined symbol for HDF5 when using g++

I can't seem to get the c++ bindings for the HDF5 library to compile when using gcc.

The test program is the example found at: https://support.hdfgroup.org/ftp/HDF5/current/src/unpacked/c++/examples/h5tutr_crtdat.cpp

My cmake file reads as follows:

cmake_minimum_required(VERSION 3.1.0)

project(readhdf5 C CXX)

find_package(HDF5 COMPONENTS C CXX HL REQUIRED)

link_directories(${HDF5_INCLUDE_DIRS})
include_directories(${HDF5_INCLUDE_DIRS})

add_executable(readdata ../src/main.cpp)

target_link_libraries(readdata ${HDF5_LIBRARIES})
target_link_libraries(readdata ${HDF5_CXX_LIBRARIES})

Which I am using with the command:

cmake -DCMAKE_C_COMPILER=gcc-8 -DCMAKE_CXX_COMPILER=g++-8 ..

The error I recieve is:

me@comp:~/Downloads/hdf5-cmake-example-master/build$ make
[ 50%] Linking CXX executable readdata
Undefined symbols for architecture x86_64:
  "H5::H5File::H5File(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned int, H5::FileCreatPropList const&, H5::FileAccPropList const&)", referenced from:
      _main in main.cpp.o
  "H5::H5Location::createDataSet(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, H5::DataType const&, H5::DataSpace const&, H5::DSetCreatPropList const&) const", referenced from:
      _main in main.cpp.o
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status
make[2]: *** [readdata] Error 1
make[1]: *** [CMakeFiles/readdata.dir/all] Error 2
make: *** [all] Error 2

I'm having difficulty working out the cause of the error. If I do not specify the compiler it defaults to clang/clang++ which compiles fine. If I use only the C bindings then it compiles fine. If I specify the compilers as h5cc and h5c++ wrappers, then it compiles fine.

I'm not sure why the gcc/g++ compiler can't find the source code where clang/clang++ can.

I'm using macOS High Sierra. HDF5 was installed using Homebrew.

Thanks very much for your suggestions.

I understand what an undefined symbol is and how they're usually fixed. However the HDF5 library doesn't seem to follow the typical pattern of how an external library is linked. The question is not about how to fix undefined symbols in general but why they are not found only when using gcc in this case.

I suspect the answer requires specific knowledge of this library rather than general c++.

I encountered very similar problems with HDF5 and C++, which ultimately where related to this ABI issue , which also affects clang (when it cannot be fixed via resorting to an older ABI). If your problem is caused by the same issue, read on.

Ultimately, I solved this by avoiding std::string in the interface to the HDF5 library. This implies

  • not using any HDF5 functions taking/returning std::string
  • not using any HDF5 structures using std::string

For most cases you can simply use the version of the HDF5 routines taking const char* and pass string::c_str() . However, there are two more difficult cases.

  1. HDF5 exceptions are based on std::string , so you cannot use them, ie catch other than via catch(...)

  2. Reading a std::string via HDF5. To this end I actually re-implemented the corresponding routine (stolen from the HDF5 source code) to compile it with the correct ABI for std::string . Here it is:

     // // reading a std::string, see H5DataSet.cpp // std::string read_string(H5::DataSet const&data_set, H5::DataType const&mem_type, H5::DataSpace const&mem_space, H5::DataSpace const&file_space, H5::DSetMemXferPropList const&xfer_plist = H5::DSetMemXferPropList::DEFAULT) { const auto is_variable_len = H5Tis_variable_str(mem_type.getId()); if(is_variable_len<0) throw std::runtime_error("read_string: H5Tis_variable_str failed"); std::string strg; if(!is_variable_len) { const auto data_size = data_set.getInMemDataSize(); if(data_size>0) { std::unique_ptr<char[]> strg_C{new char[data_size+1]}; std::memset(strg_C.get(), 0, data_size+1); if(0>H5Dread(data_set.getId(), mem_type.getId(), mem_space.getId(), file_space.getId(), xfer_plist.getId(), strg_C.get())) throw std::runtime_error("read_string: H5Dread failed for fixed length string"); strg = strg_C.get(); } } else { char*strg_C; if(0>H5Dread(data_set.getId(), mem_type.getId(), mem_space.getId(), file_space.getId(), xfer_plist.getId(), &strg_C)) throw std::runtime_error("read_string: H5Dread failed for variable length string"); strg = strg_C; std::free(strg_C); } return strg; } 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM