11

I'm currently trying to shrink one of our docker images using alpine:

FROM python:2.7-alpine

However, I am having trouble pip installing matplotlib.h:

EOF
warning: no previously-included files matching '*.pyo' found anywhere in distribution
warning: no previously-included files matching '*.pyd' found anywhere in distribution
numpy/core/src/multiarray/numpyos.c:18:21: fatal error: xlocale.h: No such file or directory
compilation terminated.
numpy/core/src/multiarray/numpyos.c:18:21: fatal error: xlocale.h: No such file or directory
compilation terminated.
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/tmp/pip-build-kCID_8/matplotlib/setup.py", line 383, in <module>
    **extra_args
  File "/usr/local/lib/python2.7/distutils/core.py", line 111, in setup
    _setup_distribution = dist = klass(attrs)
  File "/usr/local/lib/python2.7/site-packages/setuptools/dist.py", line 269, in __init__
    self.fetch_build_eggs(attrs['setup_requires'])
  File "/usr/local/lib/python2.7/site-packages/setuptools/dist.py", line 313, in fetch_build_eggs
    replace_conflicting=True,
  File "/usr/local/lib/python2.7/site-packages/pkg_resources/__init__.py", line 826, in resolve
    dist = best[req.key] = env.best_match(req, ws, installer)
  File "/usr/local/lib/python2.7/site-packages/pkg_resources/__init__.py", line 1071, in best_match
    return self.obtain(req, installer)
  File "/usr/local/lib/python2.7/site-packages/pkg_resources/__init__.py", line 1083, in obtain
    return installer(requirement)
  File "/usr/local/lib/python2.7/site-packages/setuptools/dist.py", line 380, in fetch_build_egg
    return cmd.easy_install(req)
  File "/usr/local/lib/python2.7/site-packages/setuptools/command/easy_install.py", line 640, in easy_install
    return self.install_item(spec, dist.location, tmpdir, deps)
  File "/usr/local/lib/python2.7/site-packages/setuptools/command/easy_install.py", line 670, in install_item
    dists = self.install_eggs(spec, download, tmpdir)
  File "/usr/local/lib/python2.7/site-packages/setuptools/command/easy_install.py", line 850, in install_eggs
    return self.build_and_install(setup_script, setup_base)
  File "/usr/local/lib/python2.7/site-packages/setuptools/command/easy_install.py", line 1078, in build_and_install
    self.run_setup(setup_script, setup_base, args)
  File "/usr/local/lib/python2.7/site-packages/setuptools/command/easy_install.py", line 1066, in run_setup
    raise DistutilsError("Setup script exited with %s" % (v.args[0],))
distutils.errors.DistutilsError: Setup script exited with error: Command "gcc -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -DHAVE_NPY_CONFIG_H=1 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE=1 -DHAVE_CBLAS -Ibuild/src.linux-x86_64-2.7/numpy/core/src/private -Inumpy/core/include -Ibuild/src.linux-x86_64-2.7/numpy/core/include/numpy -Inumpy/core/src/private -Inumpy/core/src -Inumpy/core -Inumpy/core/src/npymath -Inumpy/core/src/multiarray -Inumpy/core/src/umath -Inumpy/core/src/npysort -I/usr/local/include/python2.7 -Ibuild/src.linux-x86_64-2.7/numpy/core/src/private -Ibuild/src.linux-x86_64-2.7/numpy/core/src/private -Ibuild/src.linux-x86_64-2.7/numpy/core/src/private -c numpy/core/src/multiarray/numpyos.c -o build/temp.linux-x86_64-2.7/numpy/core/src/multiarray/numpyos.o" failed with exit status 1

I realize this is probably because of musl.

Here are the relevant bits of my Dockerfile:

# xmlsec is only available in the testing repo
RUN apk add --no-cache --virtual .build-deps \
  xmlsec \
  xmlsec-dev \
  py-numpy \
  py-numpy-dev \
  --repository http://dl-3.alpinelinux.org/alpine/edge/testing/ \
  --allow-untrusted

RUN apk add --no-cache --virtual .build-deps \
  build-base \
  postgresql-dev \
  libffi-dev \
  nodejs \
  swig \
  git \
  libpng-dev \
  freetype-dev \
  libxml2-dev \
  libxslt-dev \
  python-dev \
  musl-dev \
  tk-dev \
  gfortran \
  py-setuptools \
  netcat-openbsd

RUN pip install -r requirements.txt

This is my requirements.txt:

setuptools==19.7
alabaster==0.7.4
amqp==1.4.6
anyjson==0.3.3
authy==2.1.2
awscli==1.9.12
Babel==1.3
backports.ssl-match-hostname==3.4.0.2
blessings==1.6
boto==2.9.9
certifi==2015.4.28
click==4.0
cryptography==1.0.1
Django==1.8.2
django-oauth-toolkit==0.8.1
django-appconf==1.0.1
django-compressor==1.5
django-cors-headers==1.1.0
django-coverage==1.2.4
django-crispy-forms==1.5.2
django-crontab==0.6.0
django-debug-panel==0.8.1
django-debug-toolbar==1.3.0
django-easy-pdf==0.1.0
django-email-extras==0.3.1
django-filter==0.10.0
django-forms-builder==0.11.1
django-libsass==0.3
django-markdown-deux==1.0.5
django-model-utils==2.2
django-nose==1.4
django-pgjson==0.3.1
django-phonenumber-field==0.7.2
django-pickling==0.1
django-ratelimit==0.6.0
django-redis==4.0.0
djangorestframework==3.3.1
djangorestframework-csv==1.3.4
django-rq==0.7.0
django-s3-cache==1.4.2
django-sphinx==2.2.4
django-storages==1.1.8
django-templatetag-handlebars==1.3.0
django-timedeltafield==0.7.10
django-twilio==0.8.0
docutils==0.12
ecdsa==0.11
extras==0.0.3
factory-boy==2.5.2
fake-factory==0.5.1
flex==4.3.0
functools32==3.2.3-1
gdata==2.0.18
gnureadline==6.3.3
greenlet==0.4.7
gunicorn==19.3.0
html5lib==0.999
httplib2==0.9.1
httpretty==0.8.10
inflection==0.3.1
ipdb==0.8
ipython==3.1.0
Jinja2==2.7.3
jsonschema==2.5.1
libsass==0.8.2
linecache2==1.0.0
lockfile==0.9.1
lxml==3.4.4
matplotlib==1.5.0
mimeparse==0.1.3
mistune==0.6
mock==1.3.0
newrelic==2.50.0.39
nose==1.3.6
nose-progressive==1.5.1
numpy==1.9.2
oauth2client==1.4.11
oauthlib==0.7.2
pandas==0.16.1
paramiko==1.15.2
pbr==1.0.1
pep8==1.6.2
phonenumbers==7.0.9
Pillow==2.8.1
pipdeptree==0.4.2
progressbar33==2.4
psycopg2==2.5.5
ptyprocess==0.5
pyasn1==0.1.7
pyasn1-modules==0.0.5
pycrypto==2.6.1
Pygments==2.0.2
PyJWT==1.3.0
pyOpenSSL==0.13
PyPDF2==1.24
python-daemon==1.6
python-dateutil==2.4.2
python-gnupg==0.3.7
python-logstash==0.4.6
python-memcached==1.54
python-mimeparse==0.1.4
python-openid==2.2.5
python-saml==2.1.3
python-social-auth==0.2.12
pytz==2015.4
PyYAML==3.11
pyzmq==14.6.0
raven==5.5.0
redis==2.10.3
reportlab==3.1.44
requests==2.7.0
requests-oauthlib==0.5.0
rq==0.5.2
rq-scheduler==0.5.1
rsa==3.1.4
simplejson==3.7.2
six==1.10.0
soaplib==2.0.0-beta2
sorl-thumbnail==12.2
Sphinx==1.3.1
sphinx-me==0.3
sqlparse==0.1.15
ssh==1.8.0
stripe==1.27.1
suds==0.4
terminado==0.5
testtools==1.8.0
traceback2==1.4.0
Unidecode==0.4.17
unittest2==1.0.1
uritemplate==0.6
vobject==0.6.6
Werkzeug==0.9.6
whitenoise==1.0.6
xhtml2pdf==0.0.6
django-absoluteuri==1.1.0

What do I need to do to get it to install?

synic
  • 793
  • 1
  • 8
  • 13

3 Answers3

13

I solved this issue by adding:

RUN ln -s /usr/include/locale.h /usr/include/xlocale.h

Everything could install properly. But I'm not sure it's good practice.

Céline Aussourd
  • 600
  • 1
  • 5
  • 14
  • I understand where you're coming from - but I feel so much better being able to codify this in my Dockerfile (with an appropriate link back to this exact post in a comment). Docker, notwithstanding its critics, is pretty impressive in part because of things like this. – lol Oct 21 '16 at 05:07
  • This works for Cygwin too. Numpy just tries to load xlocale.h if available and for some reason it thinks it is available in Cygwin of all places, but it doesn't rely on special capability of xlocale.h. – CMCDragonkai Jan 03 '17 at 12:34
  • What provides `/usr/include/locale.h` ? I am using an alpine image and already install `make python gcc libffi-dev linux-headers libgcc libstdc++` however the needed file is not there to link to in the first place – Michael M Dec 01 '17 at 01:25
  • @MichaelMügge That's the `musl-dev` package – Céline Aussourd Dec 01 '17 at 10:13
2

You probably need to use an alpine Linux docker image that uses glibc and replace musl-dev with glibc-headers, since the missing header files are bundled in glibc-headers.

All the top results in the Docker Hub when you look for glibc enabled alpine linux docker images use the same source for glibc APK packages.

That build does not include headers, but could be tweaked to do so by including another subpackage with the missing files, something along the lines of (untested):

headers() {
  mkdir -p "$subpkgdir"/usr/glibc-compat
  cp -a "$srcdir"/usr/glibc-compat/include "$subpkgdir"/usr/glibc-compat
}

in the APKBUILD file.

Having researched this, I question the usefulness of having the headers in your final container, though. It seems to me it would be much more useful to have an intermediate container to build the dependency that requires the headers, if at all possible, and install the resulting package in your container.

dawud
  • 15,096
  • 3
  • 42
  • 61
  • Hrmm, this did not work for me. I get the same error about `xlocale.h`. I saw that it installed `musl-dev` anyway, one of those packages seems to require it. `libc-dev` installed too, as far as I can tell. – synic Apr 20 '16 at 14:54
  • Can you share your `requirements.txt` (or the relevant portion that triggers the build that actually requires `matplotlib.h`), to reproduce that locally? – dawud Apr 20 '16 at 15:00
  • Ok, I added it to the OP – synic Apr 20 '16 at 15:03
  • After a little research, it requires a non-trivial amount of time to provide a working solution, I have tried to outline the requirements and why the header files are not there. I leave it to you to fill in the blanks. Hope it's useful, though. – dawud Apr 20 '16 at 22:00
2

These dependencies worked for me: docker run -c 'apk update && apk add g++ make subversion gcc gfortran ca-certificates python3-dev libpng-dev freetype-dev python3; ln -s /usr/include/locale.h /usr/include/xlocale.h; python3 -m pip install matplotlib'

Replace python3 with python if you want 2.7

(in addition to the @Celine's answer)

Bryce Guinta
  • 183
  • 1
  • 5