I’m having an issue with the latest OCaml Alpine Docker images from OCamlPro. The repository is here. Since it is on GitLab, I can’t post an issue there, so I figured I would post here and see if anyone else has run into the same issue.
Here is a Dockerfile with a minimum example that triggers the issue.
FROM ocamlpro/ocaml:4.14-2022-07-04
RUN opam switch create hehe ocaml-system
RUN opam install ocamlfind
And the error that occurs:
The following actions will be performed:
- install ocamlfind 1.9.5
<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><>
-> retrieved ocamlfind.1.9.5 (https://opam.ocaml.org/cache)
[ERROR] The installation of ocamlfind failed at "make install".
#=== ERROR while installing ocamlfind.1.9.5 ===================================#
# context 2.1.2 | linux/x86_64 | ocaml-system.4.14.0 | https://opam.ocaml.org#226c72e8
# path ~/.opam/hehe/.opam-switch/build/ocamlfind.1.9.5
# command /usr/bin/make install
# exit-code 2
# env-file ~/.opam/log/ocamlfind-1-8c2333.env
# output-file ~/.opam/log/ocamlfind-1-8c2333.out
### output ###
# [...]
# install -d "`dirname \"/home/ocaml/.opam/hehe/lib/findlib.conf\"`"
# test -f "/home/ocaml/.opam/hehe/lib/findlib.conf" || install -c findlib.conf "/home/ocaml/.opam/hehe/lib/findlib.conf"
# make[1]: Leaving directory '/home/ocaml/.opam/hehe/.opam-switch/build/ocamlfind.1.9.5'
# for p in findlib; do ( cd src/$p; /usr/bin/make install ); done
# make[1]: Entering directory '/home/ocaml/.opam/hehe/.opam-switch/build/ocamlfind.1.9.5/src/findlib'
# install -d "/home/ocaml/.opam/hehe/lib/findlib"
# install -d "/home/ocaml/.opam/hehe/bin"
# install -d "/usr/local/lib/ocaml"
# install: can't change permissions of /usr/local/lib/ocaml: Operation not permitted
# make[1]: *** [Makefile:126: install] Error 1
# make[1]: Leaving directory '/home/ocaml/.opam/hehe/.opam-switch/build/ocamlfind.1.9.5/src/findlib'
# make: *** [Makefile:24: install] Error 2
I was previously using this image, and it does work. Here is a working version, using the older image. (Only change is the base image.)
FROM ocamlpro/ocaml:4.12-2021-08-29
RUN opam switch create hehe ocaml-system
RUN opam install ocamlfind
A bit of an update: if I take the older docker image and update the the opam repository before installing ocamlfind, it breaks.
FROM ocamlpro/ocaml:4.12-2021-08-29
RUN opam switch create hehe ocaml-system
# Adding this line triggers the error.
RUN opam update
RUN opam install ocamlfind
Here is the error:
The following actions will be performed:
- install ocamlfind 1.9.5
<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><>
-> retrieved ocamlfind.1.9.5 (https://opam.ocaml.org/cache)
[ERROR] The installation of ocamlfind failed at "make install".
#=== ERROR while installing ocamlfind.1.9.5 ===================================#
# context 2.1.0 | linux/x86_64 | ocaml-system.4.12.0 | https://opam.ocaml.org#cb4d2b35
# path ~/.opam/hehe/.opam-switch/build/ocamlfind.1.9.5
# command /usr/bin/make install
# exit-code 2
# env-file ~/.opam/log/ocamlfind-1-c067f2.env
# output-file ~/.opam/log/ocamlfind-1-c067f2.out
### output ###
# [...]
# install -d "`dirname \"/home/ocaml/.opam/hehe/lib/findlib.conf\"`"
# test -f "/home/ocaml/.opam/hehe/lib/findlib.conf" || install -c findlib.conf "/home/ocaml/.opam/hehe/lib/findlib.conf"
# make[1]: Leaving directory '/home/ocaml/.opam/hehe/.opam-switch/build/ocamlfind.1.9.5'
# for p in findlib; do ( cd src/$p; /usr/bin/make install ); done
# make[1]: Entering directory '/home/ocaml/.opam/hehe/.opam-switch/build/ocamlfind.1.9.5/src/findlib'
# install -d "/home/ocaml/.opam/hehe/lib/findlib"
# install -d "/home/ocaml/.opam/hehe/bin"
# install -d "/usr/local/lib/ocaml"
# install: can't change permissions of /usr/local/lib/ocaml: Operation not permitted
# make[1]: *** [Makefile:126: install] Error 1
# make[1]: Leaving directory '/home/ocaml/.opam/hehe/.opam-switch/build/ocamlfind.1.9.5/src/findlib'
# make: *** [Makefile:24: install] Error 2
Update 2
Installing directly from the release, ocamlfind 1.9.1 works, but ocamlfind 1.9.5 does not work.
1.9.1 is the version installed in the ocamlpro/ocaml:4.12-2021-08-29 image
1.9.5 is the version installed when using ocamlpro/ocaml:4.14-2022-07-04, or when using the 4.12 image and then updating opam first
Update 3
Using the base compiler rather than the system compiler seems to fix it. Both 1.9.1 and 1.9.5 work with the ocaml-base-compiler, but only 1.9.1 works with the system compiler.
E.g.,
RUN opam switch create hehe ocaml-base-compiler.4.14.0
works, but
RUN opam switch create hehe ocaml-system
does not.
Why use the system compiler in the first place?
So why was I even using the system compiler in the first place? Here is a line from the readme of the OCamlPro docker images:
No switches are pre-created, but you are encouraged to use the provided system compiler to avoid re-building OCaml.
So I will probably switch to the base compiler for now.
I’m not sure if this is an issue stemming from ocamlfind 1.9.5 or with the Docker though.
Thanks for the detailed report. This actually seems like an issue with the ocamlfind.1.9.5 package in the upstream opam-repository when using a system compiler; (your findings make sense since the difference between the Docker images generated each week is basically the opam update)
So why was I even using the system compiler in the first place? Here is a line from the readme of the OCamlPro docker images:
Yes, the point is to save some CPU cycles while allowing you to create your switch as you see fit (as most README build instructions should start with something like opam switch create . --deps)
I believe this can likely be reproduced outside of Docker and will investigate. Your logs clearly show the build system of ocamlfind trying to write into /usr which is plain wrong.
Some further head scratching and looking at Docker images has determined that the bug doesn’t surface when using GNU coreutils - the install command in that doesn’t do anything if a target directory already exists, but BusyBox install (the default on Alpine, but replaced with coreutils if you do apk add opam) does a permissions check even when nothing needs to be done.