Search code examples
c++cmakestdopensusedrake

Integration of drake to OpenSUSE - error: cannot convert std::string_view


I am trying to build drake from source in OpenSUSE Leap 15.4. I have a repository where I document my progress.

I am almost there. I got to build step ~9500 out of 10500.

This can be seen as a follow-up to Integration of drake to OpenSUSE - build error with spdlog and fmt Part 2

I tried to circumvent the previous error mentioned in this question by building fmt and spdlog from source in two ways:

  1. I built fmt version 8.1.1 and spdlog version 1.10.0 from source
  2. I built fmt version 10.0.0 and spdlog version 1.12.0 from source

In both cases I encountered the following error

ERROR: /home/dan/drake/common/BUILD.bazel:569:16: Linking common/resource_tool failed: (Exit 1): gcc-10 failed: error executing command (from target //common:resource_tool) /usr/bin/gcc-10 @bazel-out/k8-opt/bin/common/resource_tool-2.params

Use --sandbox_debug to see verbose messages from the sandbox and retain the sandbox build root for debugging
/usr/bin/ld: external/spdlog/lib/libspdlog.a(spdlog.cpp.o): relocation R_X86_64_32S against `.rodata' can not be used when making a PIE object; recompile with -fPIE
/usr/bin/ld: failed to set dynamic section sizes: bad value
collect2: error: ld returned 1 exit status

I solved this by recompiling fmt and spdlog with -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE.

After correcting this I get the following (probably the same, at least similar) error for both approaches mentioned above:

  1. (fmt 8.1.1 + spdlog 1.10) https://gist.github.com/hedaniel7/7dbfc20121472d82169ae9626b56c705

(small sample):

multibody/tree/multibody_tree.cc: In instantiation of 'int drake::multibody::internal::MultibodyTree<T>::NumBodiesWithName(std::string_view) const [with T = double; std::string_view = std::basic_string_view<char>]':
multibody/tree/multibody_tree.cc:3778:1:   required from here
multibody/tree/multibody_tree.cc:370:59: error: cannot convert 'std::string_view' {aka 'std::basic_string_view<char>'} to 'const key_type&' {aka 'const std::__cxx11::basic_string<char>&'}
  370 |   return static_cast<int>(rigid_bodies_.names_map().count(name));
      |                                                           ^~~~
      |                                                           |
      |                                                           std::string_view {aka std::basic_string_view<char>}
  1. (fmt 10.0.0 + spdlog 1.12.0) https://gist.github.com/hedaniel7/93d1910eadb0709a1249be7c7a1be209
multibody/tree/element_collection.cc: In instantiation of 'void drake::multibody::internal::ElementCollection<T, Element, Index>::Rename(Index, std::string) [with T = double; Element = drake::multibody::Frame; Index = drake::TypeSafeIndex<drake::multibody::FrameTag>; std::string = std::__cxx11::basic_string<char>]':
multibody/tree/element_collection.cc:160:16:   required from here
bazel-out/k8-opt/bin/multibody/tree/_virtual_includes/multibody_tree_core/drake/multibody/tree/element_collection.h:136:21: warning: unused parameter 'index' [-Wunused-parameter]
  136 |   void Rename(Index index, std::string name);
      |               ~~~~~~^~~~~

This is the OpenSUSE Dockerfile that I used to compile drake in:

# Use OpenSUSE Leap 15.4 as base
FROM opensuse/leap:15.4

# Install vim, sudo, and other necessary tools and libraries for drake
RUN zypper --non-interactive update && \
    zypper --non-interactive install -y vim sudo git cmake make java-1_8_0-openjdk-devel \
    glib2-devel lapack-devel libX11-devel ocl-icd-devel opencl-headers patch patchelf \
    pkg-config python3-devel python3-pygame zlib-devel pkg-config eigen3-devel \
    libmumps5 mumps-devel gcc-fortran nasm wget unzip tar gzip openmpi-devel
    # spdlog-devel   spdlog-devel install spdlog-devel and fmt-devel
    # llvm-clang llvm-clang-devel not installed as there are too old

# Add the repository for GCC 10
RUN zypper addrepo -f http://download.opensuse.org/repositories/devel:/gcc/openSUSE_Leap_15.4/ devel_gcc && \
    zypper --non-interactive --gpg-auto-import-keys refresh && \
    zypper --non-interactive install -y gcc10 gcc10-c++

# Set GCC 10 as the default compiler
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 100 --slave /usr/bin/g++ g++ /usr/bin/g++-10 && \
    update-alternatives --install /usr/bin/cc cc /usr/bin/gcc 30 && \
    update-alternatives --set cc /usr/bin/gcc && \
    update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++ 30 && \
    update-alternatives --set c++ /usr/bin/g++

# Download and build fmt
RUN wget https://github.com/fmtlib/fmt/releases/download/8.0.1/fmt-8.0.1.zip && \
    unzip fmt-8.0.1.zip && \
    cd fmt-8.0.1 && \
    mkdir build && cd build && \
    cmake .. && \
    make && \
    sudo make install

# Download and build spdlog
RUN wget https://github.com/gabime/spdlog/archive/v1.6.0.tar.gz && \
    tar xzf v1.6.0.tar.gz && \
    cd spdlog-1.6.0 && \
    mkdir build && cd build && \
    cmake .. -DSPDLOG_BUILD_SHARED=ON -DCMAKE_CXX_FLAGS="-fPIC" -DSPDLOG_FMT_EXTERNAL=ON && \
    make && \
    sudo make install

# Install Bazelisk
RUN curl -L https://github.com/bazelbuild/bazelisk/releases/download/v1.7.5/bazelisk-linux-amd64 > /usr/local/bin/bazelisk && \
    chmod +x /usr/local/bin/bazelisk && \
    ln -s /usr/local/bin/bazelisk /usr/local/bin/bazel

# Download and place jchart2d-3.3.2.jar in /usr/share/java/jchart2d.jar
RUN wget https://repo1.maven.org/maven2/net/sf/jchart2d/jchart2d/3.3.2/jchart2d-3.3.2.jar -O /usr/share/java/jchart2d.jar

# Create .pc files for LAPACK and BLAS
RUN echo -e "prefix=/usr\nexec_prefix=\${prefix}\nlibdir=\${exec_prefix}/lib64\nincludedir=\${prefix}/include\n\nName: LAPACK\nDescription: Linear Algebra Package\nVersion: 3.9.0\nLibs: -L\${libdir} -llapack\nCflags: -I\${includedir}" > /usr/share/pkgconfig/lapack.pc && \
    echo -e "prefix=/usr\nexec_prefix=\${prefix}\nlibdir=\${exec_prefix}/lib64\nincludedir=\${prefix}/include\n\nName: BLAS\nDescription: Basic Linear Algebra Subprograms\nVersion: 3.9.0\nLibs: -L\${libdir} -lblas\nCflags: -I\${includedir}" > /usr/share/pkgconfig/blas.pc

# Set up the environment for user 'dan'
RUN groupadd -r dan && \
    useradd -m -s /bin/bash -r -g dan dan && \
    mkdir -p /home/dan/drake && \
    chown -R dan:dan /home/dan/drake && \
    echo "dan ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers

USER dan
ENV HOME /home/dan
WORKDIR $HOME

# Install dependencies for pyenv and Python build
RUN sudo zypper --non-interactive install -y git gcc make zlib-devel libbz2-devel libopenssl-devel readline-devel \
    sqlite3-devel python3-clang15 clang15-devel

# Install pyenv and Python 3.10
RUN git clone https://github.com/pyenv/pyenv.git $HOME/.pyenv && \
    echo 'export PYENV_ROOT="$HOME/.pyenv"' >> $HOME/.bashrc && \
    echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> $HOME/.bashrc && \
    echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n  eval "$(pyenv init --path)"\nfi' >> $HOME/.bashrc && \
    /bin/bash -c "source $HOME/.bashrc && pyenv install 3.10.0 && pyenv global 3.10.0"

# Ensure the selected Python version 3.10 is used and install PyYAML
RUN /bin/bash -c "source $HOME/.bashrc && pyenv rehash && pip install PyYAML"

# Set environment variables for GCC to ensure Bazel uses the correct version
ENV CC=/usr/bin/gcc-10
ENV CXX=/usr/bin/g++-10
ENV PYENV_ROOT $HOME/.pyenv
ENV PATH $PYENV_ROOT/shims:$PYENV_ROOT/bin:$PATH
ENV LD_LIBRARY_PATH=/usr/lib/llvm-14/lib:$LD_LIBRARY_PATH
ENV CMAKE_PREFIX_PATH=/usr/local/lib/cmake:${CMAKE_PREFIX_PATH}

Some additional information about the docker image:

dan@1065f1f67b07:~/drake/cmake> gcc --version
gcc (SUSE Linux) 10.5.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

dan@1065f1f67b07:~/drake/cmake> clang --version
clang version 15.0.7
Target: x86_64-suse-linux
Thread model: posix
InstalledDir: /usr/bin

#include <iostream>

int main() {
  #if __cplusplus == 201703L
    std::cout << "C++17\n";
  #elif __cplusplus == 201402L
    std::cout << "C++14\n";
  #elif __cplusplus == 201103L
    std::cout << "C++11\n";
  #elif __cplusplus == 199711L
    std::cout << "C++98\n";
  #else
    std::cout << "pre-standard C++\n";
  #endif
  return 0;
}
in test_std_version.cpp
outputs:
dan@1065f1f67b07:~/drake/cmake> ./test_std_version
C++14

I uploaded docker images on docker hub so that one see and experiment with the resulting state and also skip the long compilation time. Here are the steps to use them:

git clone https://github.com/hedaniel7/Drake-OpenSUSE-Integration
cd Drake-OpenSUSE-Integration
git checkout 187d96d0b915473bf286a476be0bc064d62e8d31
cd DockerHub
docker pull danielhe7/drake-opensuse-integration:fmt-8.1.1-spdlog-1.10 (or danielhe7/drake-opensuse-integration:fmt-10.0.0-spdlog-1.12)
docker-compose run drake-opensuse

Solution

  • Are you using a version of Drake that incorporates this PR? Recent Drake must be built in C++20 mode (or newer). As of that PR, that's a project-wide default now. Prior to that PR, the choice of C++20 was part of the platform-specific setup/ubuntu/source_distribution scripting that might have gone missing in the SUSE setup.

    Edit: Aha, I see now. The map lookup feature being used there is "Heterogeneous lookup for unordered containers" which per https://en.cppreference.com/w/cpp/compiler_support/20 requires the C++ standard library from GCC 11 as a minimum. Your example is using GCC 10 it seems.