競プロ C++ をdockerでコンパイルしたい 3

前までの記事で、Ubuntu に build-essential をインストールするDockerfile を書き、コンパイルをuser権限で行うようにした。コンテナ内の bash から操作することで C++コンパイルを行う。

前回 timtoronto634.hatenablog.com

今日は

  • コンテナ起動時に引数としてcppファイルとコンパイル先までのpathを与えたらコンパイルだけコンテナでやってくれる
  • docker-compose を使うのをやめてどこからでもコンパイルできるようにする

のを実装する。気ままにdockerの復習しながら進んでいく感じ。

最終的にはdocker-entrypoint.shを書いて、そこでいろいろ処理を加えたかったが(コンパイル対象のファイル名を受け取ってコンパイル後の実行ファイル名を決めるなど)、それはいったん放置。

復習

いったんコンテナ起動時に引数を与えるときの挙動を確認する。

dockerfile 内で指定した ENTRYPOINT は必ず実行し、CMD に引数を書いておくとそれがデフォルトの引数として機能する

試しに以下のdockerfileを書く

FROM ubuntu:18.04

RUN apt-get update && \
    apt-get install -y build-essential 

ARG UID=1000

RUN useradd -m -u ${UID} docker

# switch to the added user
USER ${UID}

ENTRYPOINT ["ls"]
CMD [ "-a" ]

ビルドして引数を何も与えずに実行すると以下*1

$ docker-compose run --rm eachfile
.              ABC129  ABC135  ABC149  ABC156  ABC163
..             ABC130  ABC136  ABC151  ABC157  ABC165
.dockerignore #以下略

ls -a の実行結果が得られる。ここで引数として-lを与えてみる

$ docker-compose run --rm eachfile -l
total 124
drwxr-xr-x 3 docker docker 4096 Aug 11 03:50 ABC126
drwxr-xr-x 3 docker docker 4096 Aug 11 03:50 ABC129
# 以下略

ここでは`ls -l'の実行結果が得られる。

余談だが、ここでCMDを与えないでおいても、引数としてオプションを書くとしっかり実行された。また、ENTRYPOINTもCMDもDockerfile中に一つしか書けないため、複数実行したければdocker-entrypoint.sh等を書いてそれをENTRYPOINTに渡す。

コンテナ起動時に引数としてcppファイルとコンパイル先までのpathを与える

以上を踏まえて、Dockerfileには

ENTRYPOINT ["g++", "-o"]
CMD ["hello_world/hello", "hello_world/hello.cpp"]

を書いておけば、docker-compose run --rm eachfile 実行ファイル名 元ファイル名.cpp とできる。

もうわざわざbashでなかに入ってコマンドを打つ必要はない。g++を書く代わりになる。

docker-compose を使うのをやめてどこからでもコンパイルできるようにする

ここまではdocker-compose を使って書いてきた。ボリュームのマウントの設定書くために使っていたのだが、ほんとにマウントの設定以外に利点がない。むしろ、docker-compose.ymlのファイルがあるディレクトリでしかコマンドを実行できないのがとってもめんどくさい。

そこで、マウントの部分はエイリアスを書いてあげて、どこのディレクトリからでもコンパイル用のイメージからコンテナを作成できるようにした。

$ vim ~/.bashrc から alias g++o='docker run -v $(pwd):/codes/ --rm eachfile' を追加。ちなみに、シングルクォーテーションでかくことに注意

参考

pocketstudio.net

qiita.com

*1:eachfileはイメージ