【问题标题】:Cannot compile C++ code whilst building image, but can after container is running?在构建映像时无法编译 C++ 代码,但在容器运行后可以吗?
【发布时间】:2021-03-11 01:27:25
【问题描述】:

我正在尝试对 github 存储库 (KPConv) 进行 dockerize。该存储库包含用于在tensorflow 中构建和训练神经网络模型的代码。该模型在 C++ 中实现了自己的custom tensorflow operationsKPConv/tf_custom_ops。它提供了一个 bash 文件来编译操作

#!/bin/bash

# Get TF variables
TF_INC=$(python3 -c 'import tensorflow as tf; print(tf.sysconfig.get_include())')
TF_LIB=$(python3 -c 'import tensorflow as tf; print(tf.sysconfig.get_lib())')

# Neighbors op
g++ -std=c++11 -shared tf_neighbors/tf_neighbors.cpp tf_neighbors/neighbors/neighbors.cpp cpp_utils/cloud/cloud.cpp -o tf_neighbors.so -fPIC -I$TF_INC -I$TF_INC/external/nsync/public -L$TF_LIB -ltensorflow_framework -O2 -D_GLIBCXX_USE_CXX11_ABI=0
g++ -std=c++11 -shared tf_neighbors/tf_batch_neighbors.cpp tf_neighbors/neighbors/neighbors.cpp cpp_utils/cloud/cloud.cpp -o tf_batch_neighbors.so -fPIC -I$TF_INC -I$TF_INC/external/nsync/public -L$TF_LIB -ltensorflow_framework -O2 -D_GLIBCXX_USE_CXX11_ABI=0

# Subsampling op
g++ -std=c++11 -shared tf_subsampling/tf_subsampling.cpp tf_subsampling/grid_subsampling/grid_subsampling.cpp cpp_utils/cloud/cloud.cpp -o tf_subsampling.so -fPIC -I$TF_INC -I$TF_INC/external/nsync/public -L$TF_LIB -ltensorflow_framework -O2 -D_GLIBCXX_USE_CXX11_ABI=0
g++ -std=c++11 -shared tf_subsampling/tf_batch_subsampling.cpp tf_subsampling/grid_subsampling/grid_subsampling.cpp cpp_utils/cloud/cloud.cpp -o tf_batch_subsampling.so -fPIC -I$TF_INC -I$TF_INC/external/nsync/public -L$TF_LIB -ltensorflow_framework -O2 -D_GLIBCXX_USE_CXX11_ABI=0

在我的 Dockerfile 中,我尝试在构建映像时调用此脚本来编译操作

FROM tensorflow/tensorflow:1.12.0-devel-gpu-py3

RUN apt-get update && apt install -y --fix-missing --no-install-recommends\
    python3-setuptools python3-pip python3-tk

RUN pip install --upgrade pip
RUN pip3 install numpy scikit-learn psutil matplotlib pyqt5 laspy tensorflow-gpu==1.12.0

COPY . /kpconv

WORKDIR /kpconv/tf_custom_ops
RUN sh compile_op.sh

WORKDIR /kpconv/cpp_wrappers
RUN sh compile_wrappers.sh

WORKDIR /kpconv

# Build
# sudo docker build -t kpconv-test .

# Run
# sudo docker run --rm -it --runtime=nvidia kpconv-test /bin/bash

尽管无论我尝试什么(我不会在此问题的内容中添加的详尽列表),它总是无法编译代码。特别是例外(或部分例外)

ImportError: libcuda.so.1: cannot open shared object file: No such file or directory

不过,这不一定是问题。


我决定暂时搁置这个问题,并注释掉 Dockerfile 中 RUN compile_op.sh 的行。这导致了成功的图像构建。然后我启动了容器。经过一些其他工作后,我决定看看如果在容器内运行sh compile_op.sh 会发生什么。这神奇地工作没有问题。

$ sudo docker run --rm -it --runtime=nvidia kpconv-test /bin/bash
root@c36376e71177:/kpconv# cd tf_custom_ops/
root@c36376e71177:/kpconv/tf_custom_ops# sh compile_op.sh 
root@c36376e71177:/kpconv/tf_custom_ops#

进一步的证据是通过调用 KPConv 中提供的训练脚本之一来尝试开始神经网络的训练运行。

首先,没有sh compile_op.sh

$ sudo docker run --rm -it --runtime=nvidia kpconv-test /bin/bash
root@64ed930c5aca:/kpconv# python training_ModelNet40.py 
Traceback (most recent call last):
<...>
tensorflow.python.framework.errors_impl.NotFoundError: tf_custom_ops/tf_neighbors.so: cannot open shared object file: No such file or directory
root@64ed930c5aca:/kpconv# 

虽然编译后编译的.sos可以导入,脚本也可以继续运行(我其实没有数据集)

$ sudo docker run --rm -it --runtime=nvidia kpconv-test /bin/bash
root@938a9d7bc2b0:/kpconv# cd tf_custom_ops/
root@938a9d7bc2b0:/kpconv/tf_custom_ops# sh compile_op.sh 
root@938a9d7bc2b0:/kpconv/tf_custom_ops# cd ..
root@938a9d7bc2b0:/kpconv# python training_ModelNet40.py 

Dataset Preparation
*******************
<...>
OSError: Data/ModelNet40/modelnet40_normal_resampled/modelnet40_train.txt not found.
root@938a9d7bc2b0:/kpconv#

在 Dockerfile 中调用 sh compile_op.sh 与在容器中调用 sh compile_op.sh 是否存在一些根本区别,导致前者失败而后者成功?


我感觉答案可能在于在 Dockerfile 中使用 RUN sh ...。也许shdocker build 过程中无法访问“正确的”$PATH 或其他环境变量...?

【问题讨论】:

  • 容器是否已经包含 g++,因为您从未安装 build-essential。我可能对 tensorflow 包了解不够。
  • 也许在您尝试运行编译时尚未安装该库,并且 docker 文件中的后续操作安装该库。

标签: c++ docker tensorflow g++


【解决方案1】:

这一切都让我想起了使用 Dockerfile 在克隆的 GitLab 项目中编译 ROS。

在那里,我还必须进行 C++ 编译,而且只能使用 bash shell,而不是 sh shell,请参见下面的示例。

当我收到错误catkin_make: command not found 时,是因为我没有sourced ROS。 在 Dockerfile 中采购 ROS 必须通过运行它来完成,至少在将它添加到 .bashrc 时我无法让它运行(这将是 #RUN /bin/bash -c "echo 'source /opt/ros/melodic/setup.bash' &gt;&gt; ~/.bashrc;source ~/.bashrc' - 但不起作用)。这可以代替:

RUN /bin/bash -c 'source /opt/ros/melodic/setup.bash;\
    cd /rosyard;\
    catkin_make -j8 # compile;\
    echo "source /MY_PROJECT/devel/setup.bash" >> ~/.bashrc'

最后一个命令将在每次启动 bash 时获取已编译的 ROS,在您启动容器 bash 时也是如此。

显然,C++ 编译 (catkin_make) 在图像内部工作。 如果我最后在没有 CMD 的情况下构建映像,我必须在容器中获取已编译的 ROS,因为它需要在 shell 的每次启动时完成——即使它只是容器中的一个新 shell。解决这个问题的唯一方法是在映像中启动 bash,并使用 CMD 来获取已编译的 ROS(未经测试)。

我对您的项目的了解不足以知道源命令,但似乎您应该在编译之前进行源代码,因为在我的情况下,在图像中编译 C++ 是有效的。你应该使用RUN /bin/bash -c "..." 来编译bash,而不是sh,在“/bin/sh: 1: MY_COMMAND: not found” 上查看更多关于这种差异的信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-25
    • 2014-01-16
    • 1970-01-01
    • 2021-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-20
    相关资源
    最近更新 更多