Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linker error when switching off MPI (and hence ADIOS1) #317

Closed
franzpoeschel opened this issue Aug 29, 2018 · 10 comments
Closed

Linker error when switching off MPI (and hence ADIOS1) #317

franzpoeschel opened this issue Aug 29, 2018 · 10 comments

Comments

@franzpoeschel
Copy link
Contributor

franzpoeschel commented Aug 29, 2018

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.

@C0nsultant
Copy link
Member

C0nsultant commented Aug 29, 2018

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 ornladios/ADIOS#183 if you're interested.
We had to go through a set of hoops merely to get it to compile in the current status: #223 #258 #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?

@ax3l
Copy link
Member

ax3l commented Aug 29, 2018

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.

@ax3l
Copy link
Member

ax3l commented Aug 29, 2018

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 to openPMD::ADIOS1IOHandler::ADIOS1IOHandler(std::__cxx11::basic_string<char, std::char_traits, std::allocator >, openPMD::AccessType)'

@franzpoeschel
Copy link
Contributor Author

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;
}

@C0nsultant
Copy link
Member

C0nsultant commented Aug 29, 2018

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.

@ax3l
Copy link
Member

ax3l commented Aug 29, 2018

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

@franzpoeschel
Copy link
Contributor Author

@C0nsultant The tests and examples build without any problems.

@ax3l
Copy link
Member

ax3l commented Aug 29, 2018

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)

@ax3l
Copy link
Member

ax3l commented Aug 29, 2018

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

@franzpoeschel
Copy link
Contributor Author

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

@ax3l ax3l changed the title Include error when switching off MPI (and hence ADIOS1) Linker error when switching off MPI (and hence ADIOS1) Aug 29, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants