Openpmd-api: Linker error when switching off MPI (and hence ADIOS1)

Created on 29 Aug 2018  Â·  10Comments  Â·  Source: openPMD/openPMD-api

Describe the bug
When building and installing openPMD using the CMake script without support for MPI (which will also switch off support for ADIOS1), attempts to include the installed library into another project will fail.

To Reproduce
Build the library without support for MPI:
cmake -D openPMD_USE_MPI=OFF -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON <path to source>
Output:

-- The C compiler identification is GNU 8.2.0
-- The CXX compiler identification is GNU 8.2.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Could NOT find HDF5: Found unsuitable version "", but required is at least "1.8.13" (found HDF5_hdf5_LIBRARY-NOTFOUND)
-- Can NOT find 'adios_config' - set ADIOS_ROOT, ADIOS_DIR or INSTALL_PREFIX, or check your PATH
-- Could NOT find ADIOS (missing: ADIOS_LIBRARIES ADIOS_INCLUDE_DIRS) (Required is at least version "1.13.1")
-- Found PythonInterp: /usr/bin/python3.6 (found version "3.6.6") 
-- Found PythonLibs: /usr/lib/x86_64-linux-gnu/libpython3.6m.so
-- Performing Test HAS_CPP14_FLAG
-- Performing Test HAS_CPP14_FLAG - Success
-- pybind11 v2.2.3
-- pybind11: Using INTERNAL version 2.2.3
-- MPark.Variant: Using INTERNAL version 1.3.0
-- Catch2: Using INTERNAL version 2.2.1
-- Performing Test HAS_FLTO
-- Performing Test HAS_FLTO - Success
-- LTO enabled
-- Note: Skipping Python example tests (missing example files)
-- Note: run
    . /home/franz/workspace/openPMD-api/.travis/download_samples.sh
to add example files to samples/git-sample/ directory!

openPMD build configuration:
  library Version: 0.4.0
  openPMD Standard: 1.1.0
  C++ Compiler: GNU 8.2.0 
    /usr/bin/c++

  Installation prefix: /usr/local
        bin: bin
        lib: lib
    include: include
      cmake: lib/cmake/openPMD
     python: lib/python3.6/site-packages

  Additionally, install following third party libraries:
    MPark.Variant: ON

  Build Type: Release
  Testing: ON
  Internal VERIFY: ON
  Build Options:
    MPI: OFF
    HDF5: OFF
    ADIOS1: OFF
    ADIOS2: OFF
    INVASIVE_TESTS: ON
    PYTHON: ON

-- Configuring done
-- Generating done
-- Build files have been written to: /home/franz/shk/openPMD-api-build

Install the library using cmake --build . --target install and create a new sample project that includes the library (e.g. the example in the openPMD documentation).

Use CMake to build this project, CMakeLists.txt:

cmake_minimum_required(VERSION 3.0)
project(openPMD_test)

add_executable(openPMD_test main.cpp)

target_compile_features(openPMD_test PRIVATE cxx_std_17)

list(APPEND CMAKE_PREFIX_PATH /usr/local/include)

find_package(openPMD REQUIRED)
target_link_libraries(openPMD_test PRIVATE openPMD)

Use cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON <path to sample project>:

-- The C compiler identification is GNU 8.2.0
-- The CXX compiler identification is GNU 8.2.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/franz/workspace/c++/openPMD_bugreport/build

Build the sample project using cmake --build .:

/usr/bin/cmake -H/home/franz/workspace/c++/openPMD_bugreport -B/home/franz/workspace/c++/openPMD_bugreport/build --check-build-system CMakeFiles/Makefile.cmake 0
/usr/bin/cmake -E cmake_progress_start /home/franz/workspace/c++/openPMD_bugreport/build/CMakeFiles /home/franz/workspace/c++/openPMD_bugreport/build/CMakeFiles/progress.marks
/usr/bin/make -f CMakeFiles/Makefile2 all
make[1]: Verzeichnis „/home/franz/workspace/c++/openPMD_bugreport/build“ wird betreten
/usr/bin/make -f CMakeFiles/openPMD_test.dir/build.make CMakeFiles/openPMD_test.dir/depend
make[2]: Verzeichnis „/home/franz/workspace/c++/openPMD_bugreport/build“ wird betreten
cd /home/franz/workspace/c++/openPMD_bugreport/build && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /home/franz/workspace/c++/openPMD_bugreport /home/franz/workspace/c++/openPMD_bugreport /home/franz/workspace/c++/openPMD_bugreport/build /home/franz/workspace/c++/openPMD_bugreport/build /home/franz/workspace/c++/openPMD_bugreport/build/CMakeFiles/openPMD_test.dir/DependInfo.cmake --color=
Scanning dependencies of target openPMD_test
make[2]: Verzeichnis „/home/franz/workspace/c++/openPMD_bugreport/build“ wird verlassen
/usr/bin/make -f CMakeFiles/openPMD_test.dir/build.make CMakeFiles/openPMD_test.dir/build
make[2]: Verzeichnis „/home/franz/workspace/c++/openPMD_bugreport/build“ wird betreten
[ 50%] Building CXX object CMakeFiles/openPMD_test.dir/main.cpp.o
/usr/bin/c++    -std=gnu++17 -o CMakeFiles/openPMD_test.dir/main.cpp.o -c /home/franz/workspace/c++/openPMD_bugreport/main.cpp
[100%] Linking CXX executable openPMD_test
/usr/bin/cmake -E cmake_link_script CMakeFiles/openPMD_test.dir/link.txt --verbose=1
/usr/bin/c++    -rdynamic CMakeFiles/openPMD_test.dir/main.cpp.o  -o openPMD_test -lopenPMD 
/usr/bin/ld: //usr/local/lib/libopenPMD.a(AbstractIOHandlerHelper.cpp.o): in function `openPMD::createIOHandler(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, openPMD::AccessType, openPMD::Format)':
AbstractIOHandlerHelper.cpp:(.text+0x165): undefined reference to `openPMD::ADIOS1IOHandler::ADIOS1IOHandler(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, openPMD::AccessType)'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/openPMD_test.dir/build.make:87: openPMD_test] Fehler 1
make[2]: Verzeichnis „/home/franz/workspace/c++/openPMD_bugreport/build“ wird verlassen
make[1]: *** [CMakeFiles/Makefile2:76: CMakeFiles/openPMD_test.dir/all] Fehler 2
make[1]: Verzeichnis „/home/franz/workspace/c++/openPMD_bugreport/build“ wird verlassen
make: *** [Makefile:87: all] Fehler 2

Expected behavior
The library should be possible to include into other projects after building it without support for MPI.

Software Environment:

  • version of openPMD-api: 0.4.0-alpha
  • installed openPMD-api via: from source
  • operating system: Debian Testing
  • CMake: 3.12.1

Additional context
A current workaround is to comment out the line return std::make_shared< ADIOS1IOHandler >(path, accessType); in /src/IO/AbstractIOHandlerHelper.cpp, the library will include without any errors then.

C++14 install question

Most helpful comment

Ok, so it was on my side. It's working fine now, thanks for your help!

All 10 comments

Thanks for this detailed and concise report!

To be honest, I have lost track of the valid build configurations regarding ADIOS1. The library itself is not intended to be used for the purposes we aim for in this API (frictionless serial/MPI interoperability in single source). See https://github.com/ornladios/ADIOS/issues/183 if you're interested.
We had to go through a set of hoops merely to get it to compile in the current status: https://github.com/openPMD/openPMD-api/pull/223 https://github.com/openPMD/openPMD-api/pull/258 https://github.com/openPMD/openPMD-api/pull/254
I honestly have never linked explicitly against our built library, so there may be more in store for us when you explore this further. Rambling aside and coming back to your report:

building and installing [...] without support for MPI (which will also switch off support for ADIOS1)

That is actually not our desired behaviour and might be a bug in our CMakeLists.txt. The whole ADIOS1 hacking mentioned above that @ax3l did was supposed to enable as many combinations as possible, including openPMD_USE_MPI=OFF/openPMD_USE_MPI=AUTO. ADIOS1 should not be disabled just because of the fact that MPI is disabled.

Looking at the CMake logic, I can not see an apparent problem there.

The likely reason why ADIOS gets disabled in the first place in your build is that it can not be found:

-- Can NOT find 'adios_config' - set ADIOS_ROOT, ADIOS_DIR or INSTALL_PREFIX, or check your PATH
-- Could NOT find ADIOS (missing: ADIOS_LIBRARIES ADIOS_INCLUDE_DIRS) (Required is at least version "1.13.1")

You may have to adjust your environment (see PIConGPU).

... which still does not solve the linking problem.
The signature openPMD::ADIOS1IOHandler::ADIOS1IOHandler(std::string, openPMD::AccessType) is always provided by the serial ADIOS1 backend, independent of whether it is built with or without an available ADIOS1 library.
That library gets linked into every build of the library, no matter if the features are active or not.

Are you able to build the examples and tests from the CMakeLists.txt, @franzpoeschel ?

I'm honestly out of ideas what the cause could be. My suspicion is that this if(openPMD_HAVE_ADIOS1) works fine for building the library, but breaks downstream. @ax3l?

Thx!
I will take care of this. He has the special case of "no backends" which we don't cover in CI. Will fix CMake accordingly.

Looks to me like C++17 strings are again incompatible with C++11 strings? nope, tested.

target_compile_features(openPMD_test PRIVATE cxx_std_17)

...

/usr/bin/ld:
/usr/local/lib/libopenPMD.a(AbstractIOHandlerHelper.cpp.o): in function openPMD::createIOHandler(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, openPMD::AccessType, openPMD::Format)': AbstractIOHandlerHelper.cpp:(.text+0x165): undefined reference toopenPMD::ADIOS1IOHandler::ADIOS1IOHandler(std::__cxx11::basic_string, std::allocator >, openPMD::AccessType)'

The complete main.cpp:

#include <openPMD/openPMD.hpp>

#include <iostream>
#include <memory>
#include <cstddef>


using std::cout;
using namespace openPMD;

int main()
{
    Series series = Series(
        "../samples/git-sample/data%T.h5",
        AccessType::READ_ONLY
    );
    cout << "Read a Series with openPMD standard version "
         << series.openPMD() << '\n';

    cout << "The Series contains " << series.iterations.size() << " iterations:";
    for( auto const& i : series.iterations )
        cout << "\n\t" << i.first;
    cout << '\n';

    Iteration i = series.iterations[100];
    cout << "Iteration 100 contains " << i.meshes.size() << " meshes:";
    for( auto const& m : i.meshes )
        cout << "\n\t" << m.first;
    cout << '\n';
    cout << "Iteration 100 contains " << i.particles.size() << " particle species:";
    for( auto const& ps : i.particles )
        cout << "\n\t" << ps.first;
    cout << '\n';

    MeshRecordComponent E_x = i.meshes["E"]["x"];
    Extent extent = E_x.getExtent();
    cout << "Field E/x has shape (";
    for( auto const& dim : extent )
        cout << dim << ',';
    cout << ") and has datatype " << E_x.getDatatype() << '\n';

    Offset chunk_offset = {1, 1, 1};
    Extent chunk_extent = {2, 2, 1};
    auto chunk_data = E_x.loadChunk<double>(chunk_offset, chunk_extent);
    cout << "Queued the loading of a single chunk from disk, "
            "ready to execute\n";
    series.flush();
    cout << "Chunk has been read from disk\n"
         << "Read chunk contains:\n";
    for( size_t row = 0; row < chunk_extent[0]; ++row )
    {
        for( size_t col = 0; col < chunk_extent[1]; ++col )
            cout << "\t"
                 << '(' << row + chunk_offset[0] << '|' << col + chunk_offset[1] << '|' << 1 << ")\t"
                 << chunk_data.get()[row*chunk_extent[1]+col];
        cout << '\n';
    }

    return 0;
}

Looks to me like C++17 strings are again incompatible with C++11 strings?

You grabbed a hammer and there might be a nail:
https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html
This is older and referrs to ABI incompatabilities between GCC<5.1/C++03 and GCC>=5.1/C++11, but the symptoms look very similar.

Could be. But I think I just forgot to pass the dummy-ADIOS lib to the CMake config package. We will debug this, he sits next seat to me :D

@C0nsultant The tests and examples build without any problems.

First note: the linker line in CMakeLists.txt of depending projects should read openPMD::openPMD not openPMD:

target_link_libraries(targetName PRIVATE openPMD::openPMD)

(PRIVATE or PUBLIC depends on the usage, e.g. if it's used in public headers again)

Yep, that's the error. You just find the include already because you installed in a system path.

Ok, so it was on my side. It's working fine now, thanks for your help!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

lucafedeli88 picture lucafedeli88  Â·  3Comments

PrometheusPi picture PrometheusPi  Â·  3Comments

ax3l picture ax3l  Â·  4Comments

steindev picture steindev  Â·  4Comments

ax3l picture ax3l  Â·  3Comments