1##
2# osgeo/gdal:alpine-normal
3
4# This file is available at the option of the licensee under:
5# Public domain
6# or licensed under X/MIT (LICENSE.TXT) Copyright 2019 Even Rouault <even.rouault@spatialys.com>
7
8ARG ALPINE_VERSION=3.13
9FROM alpine:${ALPINE_VERSION} as builder
10
11# Derived from osgeo/proj by Howard Butler <howard@hobu.co>
12LABEL maintainer="Even Rouault <even.rouault@spatialys.com>"
13
14# Setup build env for PROJ
15RUN apk add --no-cache wget curl unzip make libtool autoconf automake pkgconfig g++ sqlite sqlite-dev
16
17ARG PROJ_DATUMGRID_LATEST_LAST_MODIFIED
18RUN \
19    mkdir -p /build_projgrids/usr/share/proj \
20    && curl -LOs http://download.osgeo.org/proj/proj-datumgrid-latest.zip \
21    && unzip -q -j -u -o proj-datumgrid-latest.zip  -d /build_projgrids/usr/share/proj \
22    && rm -f *.zip
23
24# For PROJ and GDAL
25ARG POPPLER_DEV=poppler-dev
26RUN apk add --no-cache \
27    linux-headers \
28    curl-dev tiff-dev \
29    zlib-dev zstd-dev \
30    libjpeg-turbo-dev libpng-dev openjpeg-dev libwebp-dev expat-dev \
31    py3-numpy-dev python3-dev py3-numpy \
32    ${POPPLER_DEV} postgresql-dev \
33    openexr-dev libheif-dev xerces-c-dev geos-dev cfitsio-dev \
34    netcdf-dev hdf5-dev freexl-dev \
35    # For spatialite (and GDAL)
36    libxml2-dev \
37    && mkdir -p /build_thirdparty/usr/lib
38
39# Build szip
40ARG SZIP_VERSION=2.1.1
41RUN if test "${SZIP_VERSION}" != ""; then ( \
42    wget -q https://support.hdfgroup.org/ftp/lib-external/szip/${SZIP_VERSION}/src/szip-${SZIP_VERSION}.tar.gz \
43    && tar xzf szip-${SZIP_VERSION}.tar.gz \
44    && rm -f szip-${SZIP_VERSION}.tar.gz \
45    && cd szip-${SZIP_VERSION} \
46    && CFLAGS=-O2 ./configure --prefix=/usr --disable-static \
47    && make -j$(nproc) \
48    && make install \
49    && cp -P /usr/lib/libsz*.so* /build_thirdparty/usr/lib \
50    && for i in /build_thirdparty/usr/lib/*; do strip -s $i 2>/dev/null || /bin/true; done \
51    && cd .. \
52    && rm -rf szip-${SZIP_VERSION} \
53    ); fi
54
55# Build hdf4
56ARG HDF4_VERSION=4.2.15
57RUN if test "${HDF4_VERSION}" != "" -a "$(uname -m)" = "x86_64"; then ( \
58    apk add --no-cache byacc flex portablexdr-dev \
59    && mkdir hdf4 \
60    && wget -q https://support.hdfgroup.org/ftp/HDF/releases/HDF${HDF4_VERSION}/src/hdf-${HDF4_VERSION}.tar.gz -O - \
61        | tar xz -C hdf4 --strip-components=1 \
62    && cd hdf4 \
63    && LDFLAGS=-lportablexdr ./configure --prefix=/usr --enable-shared --disable-static \
64        --with-szlib=/usr --disable-fortran --disable-netcdf \
65    && make -j$(nproc) \
66    && make install \
67    && cp -P /usr/lib/libdf*.so* /build_thirdparty/usr/lib \
68    && cp -P /usr/lib/libmfhdf*.so* /build_thirdparty/usr/lib \
69    && for i in /build_thirdparty/usr/lib/*; do strip -s $i 2>/dev/null || /bin/true; done \
70    && cd .. \
71    && rm -rf hdf4 \
72    && apk del byacc flex portablexdr-dev \
73    ); fi
74
75# Build likbkea
76ARG KEA_VERSION=1.4.13
77RUN if test "${KEA_VERSION}" != ""; then ( \
78    apk add --no-cache cmake \
79    && wget -q https://github.com/ubarsc/kealib/archive/kealib-${KEA_VERSION}.zip \
80    && unzip -q kealib-${KEA_VERSION}.zip \
81    && rm -f kealib-${KEA_VERSION}.zip \
82    && cd kealib-kealib-${KEA_VERSION} \
83    && cmake . -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Release \
84        -DCMAKE_INSTALL_PREFIX=/usr -DHDF5_INCLUDE_DIR=/usr/include/hdf5 \
85        -DHDF5_LIB_PATH=/usr/lib -DLIBKEA_WITH_GDAL=OFF \
86    && make -j$(nproc) \
87    && make install \
88    && cd .. \
89    && rm -rf kealib-kealib-${KEA_VERSION} \
90    && cp -P /usr/lib/libkea*.so* /build_thirdparty/usr/lib \
91    && for i in /build_thirdparty/usr/lib/*; do strip -s $i 2>/dev/null || /bin/true; done \
92    && apk del cmake \
93    ); fi
94
95# Build openjpeg
96# ARG OPENJPEG_VERSION=2.3.1
97RUN if test "${OPENJPEG_VERSION}" != ""; then ( \
98    apk add --no-cache cmake \
99    && wget -q https://github.com/uclouvain/openjpeg/archive/v${OPENJPEG_VERSION}.tar.gz \
100    && tar xzf v${OPENJPEG_VERSION}.tar.gz \
101    && rm -f v${OPENJPEG_VERSION}.tar.gz \
102    && cd openjpeg-${OPENJPEG_VERSION} \
103    && cmake . -DBUILD_SHARED_LIBS=ON  -DBUILD_STATIC_LIBS=OFF -DCMAKE_BUILD_TYPE=Release \
104        -DCMAKE_INSTALL_PREFIX=/usr \
105    && make -j$(nproc) \
106    && make install \
107    && rm -f /usr/lib/libopenjp2.so.2.3.0 \
108    && cp -P /usr/lib/libopenjp2*.so* /build_thirdparty/usr/lib \
109    && for i in /build_thirdparty/usr/lib/*; do strip -s $i 2>/dev/null || /bin/true; done \
110    && cd .. \
111    && rm -rf openjpeg-${OPENJPEG_VERSION} \
112    && apk del cmake \
113    ); fi
114
115# Build libdeflate
116ARG LIBDEFLATE_VERSION=1.7
117RUN if test "${LIBDEFLATE_VERSION}" != ""; then ( \
118    mkdir libdeflate \
119    && wget -q https://github.com/ebiggers/libdeflate/archive/v${LIBDEFLATE_VERSION}.tar.gz -O - \
120        | tar xz -C libdeflate --strip-components=1 \
121    && cd libdeflate \
122    && make -j$(nproc) PREFIX=/usr install \
123    && cp -P /usr/lib/libdeflate.so* /build_thirdparty/usr/lib \
124    && for i in /build_thirdparty/usr/lib/*; do strip -s $i 2>/dev/null || /bin/true; done \
125    && cd .. \
126    && rm -rf libdeflate \
127    ); fi
128
129RUN apk add --no-cache rsync ccache
130ARG RSYNC_REMOTE
131
132# Build PROJ
133ARG PROJ_VERSION=master
134RUN mkdir proj \
135    && wget -q https://github.com/OSGeo/PROJ/archive/${PROJ_VERSION}.tar.gz -O - \
136        | tar xz -C proj --strip-components=1 \
137    && cd proj \
138    && ./autogen.sh \
139    && if test "${RSYNC_REMOTE}" != ""; then \
140        echo "Downloading cache..."; \
141        rsync -ra ${RSYNC_REMOTE}/proj/ $HOME/; \
142        echo "Finished"; \
143        export CC="ccache gcc"; \
144        export CXX="ccache g++"; \
145        export PROJ_DB_CACHE_DIR="$HOME/.ccache"; \
146        ccache -M 100M; \
147    fi \
148    && ./configure --prefix=/usr --disable-static --enable-lto \
149    && make -j$(nproc) \
150    && make install \
151    && make install DESTDIR="/build_proj" \
152    && if test "${RSYNC_REMOTE}" != ""; then \
153        ccache -s; \
154        echo "Uploading cache..."; \
155        rsync -ra --delete $HOME/.ccache ${RSYNC_REMOTE}/proj/; \
156        echo "Finished"; \
157        rm -rf $HOME/.ccache; \
158        unset CC; \
159        unset CXX; \
160    fi \
161    && cd .. \
162    && rm -rf proj \
163    && for i in /build_proj/usr/lib/*; do strip -s $i 2>/dev/null || /bin/true; done \
164    && for i in /build_proj/usr/bin/*; do strip -s $i 2>/dev/null || /bin/true; done
165
166# Build spatialite
167ARG SPATIALITE_VERSION=5.0.1
168RUN if test "${SPATIALITE_VERSION}" != "" -a "$(uname -m)" = "x86_64"; then ( \
169    wget -q http://www.gaia-gis.it/gaia-sins/libspatialite-${SPATIALITE_VERSION}.tar.gz \
170    && tar xzf libspatialite-${SPATIALITE_VERSION}.tar.gz \
171    && rm -f libspatialite-${SPATIALITE_VERSION}.tar.gz \
172    && cd libspatialite-${SPATIALITE_VERSION} \
173    && apk add --no-cache minizip-dev \
174    && if test "${RSYNC_REMOTE}" != ""; then \
175        echo "Downloading cache..."; \
176        rsync -ra ${RSYNC_REMOTE}/spatialite/ $HOME/; \
177        echo "Finished"; \
178        export CC="ccache gcc"; \
179        export CXX="ccache g++"; \
180        ccache -M 100M; \
181    fi \
182    && ./configure --prefix=/usr --disable-static --disable-rttopo \
183    && make -j$(nproc) \
184    && make install \
185    && if test "${RSYNC_REMOTE}" != ""; then \
186        ccache -s; \
187        echo "Uploading cache..."; \
188        rsync -ra --delete $HOME/.ccache ${RSYNC_REMOTE}/spatialite/; \
189        echo "Finished"; \
190        rm -rf $HOME/.ccache; \
191        unset CC; \
192        unset CXX; \
193    fi \
194    && mkdir -p /build_spatialite/usr/lib \
195    && cp -P /usr/lib/libspatialite*.so* /build_spatialite/usr/lib \
196    && for i in /build_spatialite/usr/lib/*; do strip -s $i 2>/dev/null || /bin/true; done \
197    && cd .. \
198    && rm -rf libspatialite-${SPATIALITE_VERSION} \
199    ); else \
200        mkdir -p /build_spatialite/usr/lib; \
201    fi
202
203# Build GDAL
204ARG GDAL_VERSION=master
205ARG GDAL_RELEASE_DATE
206ARG GDAL_BUILD_IS_RELEASE
207RUN if test "${GDAL_VERSION}" = "master"; then \
208        export GDAL_VERSION=$(curl -Ls https://api.github.com/repos/OSGeo/gdal/commits/HEAD -H "Accept: application/vnd.github.VERSION.sha"); \
209        export GDAL_RELEASE_DATE=$(date "+%Y%m%d"); \
210    fi \
211    && if test "x${GDAL_BUILD_IS_RELEASE}" = "x"; then \
212        export GDAL_SHA1SUM=${GDAL_VERSION}; \
213    fi \
214    && export GDAL_EXTRA_ARGS="" \
215    && export GDAL_EXTRA_ARGS="--with-geos ${GDAL_EXTRA_ARGS}" \
216    && if test "${XERCESC_VERSION}" != ""; then \
217        export GDAL_EXTRA_ARGS="--with-xerces ${GDAL_EXTRA_ARGS}"; \
218    fi \
219    && if test "${HDF4_VERSION}" != "" -a "$(uname -m)" = "x86_64"; then \
220        apk add --no-cache portablexdr-dev \
221        && export LDFLAGS="-lportablexdr ${LDFLAGS}" \
222        && export GDAL_EXTRA_ARGS="--with-hdf4 ${GDAL_EXTRA_ARGS}"; \
223    fi \
224    && export GDAL_EXTRA_ARGS="--with-hdf5 ${GDAL_EXTRA_ARGS}" \
225    && export GDAL_EXTRA_ARGS="--with-netcdf ${GDAL_EXTRA_ARGS}" \
226    && if test "${SPATIALITE_VERSION}" != "" -a "$(uname -m)" = "x86_64"; then \
227        export GDAL_EXTRA_ARGS="--with-spatialite ${GDAL_EXTRA_ARGS}"; \
228    fi \
229    && if test "${POPPLER_DEV}" != ""; then \
230        export GDAL_EXTRA_ARGS="--with-poppler ${GDAL_EXTRA_ARGS}"; \
231    fi \
232    && echo ${GDAL_EXTRA_ARGS} \
233    && mkdir gdal \
234    && wget -q https://github.com/OSGeo/gdal/archive/${GDAL_VERSION}.tar.gz -O - \
235        | tar xz -C gdal --strip-components=1 \
236    && cd gdal/gdal \
237    && if test "${RSYNC_REMOTE}" != ""; then \
238        echo "Downloading cache..."; \
239        rsync -ra ${RSYNC_REMOTE}/gdal/ $HOME/; \
240        echo "Finished"; \
241        # Little trick to avoid issues with Python bindings
242        printf "#!/bin/sh\nccache gcc \$*" > ccache_gcc.sh; \
243        chmod +x ccache_gcc.sh; \
244        printf "#!/bin/sh\nccache g++ \$*" > ccache_g++.sh; \
245        chmod +x ccache_g++.sh; \
246        export CC=$PWD/ccache_gcc.sh; \
247        export CXX=$PWD/ccache_g++.sh; \
248        ccache -M 1G; \
249    fi \
250    && ./configure --prefix=/usr --without-libtool \
251    --with-hide-internal-symbols \
252    --with-proj=/usr \
253    --with-libtiff=internal --with-rename-internal-libtiff-symbols \
254    --with-geotiff=internal --with-rename-internal-libgeotiff-symbols \
255    # --enable-lto
256    ${GDAL_EXTRA_ARGS} \
257    --with-python \
258    && make -j$(nproc) \
259    && make install DESTDIR="/build" \
260    && (cd apps && make -j$(nproc) multireadtest && cp multireadtest /build/usr/bin) \
261    && if test "${RSYNC_REMOTE}" != ""; then \
262        ccache -s; \
263        echo "Uploading cache..."; \
264        rsync -ra --delete $HOME/.ccache ${RSYNC_REMOTE}/gdal/; \
265        echo "Finished"; \
266        rm -rf $HOME/.ccache; \
267        unset CC; \
268        unset CXX; \
269    fi \
270    && cd ../.. \
271    && rm -rf gdal \
272    && mkdir -p /build_gdal_python/usr/lib \
273    && mkdir -p /build_gdal_python/usr/bin \
274    && mkdir -p /build_gdal_version_changing/usr/include \
275    && mv /build/usr/lib/python3.8          /build_gdal_python/usr/lib \
276    && mv /build/usr/lib                    /build_gdal_version_changing/usr \
277    && mv /build/usr/include/gdal_version.h /build_gdal_version_changing/usr/include \
278    && mv /build/usr/bin/*.py               /build_gdal_python/usr/bin \
279    && mv /build/usr/bin                    /build_gdal_version_changing/usr \
280    && for i in /build_gdal_version_changing/usr/lib/*; do strip -s $i 2>/dev/null || /bin/true; done \
281    && for i in /build_gdal_python/usr/lib/python3.8/site-packages/osgeo/*.so; do strip -s $i 2>/dev/null || /bin/true; done \
282    && for i in /build_gdal_version_changing/usr/bin/*; do strip -s $i 2>/dev/null || /bin/true; done \
283    # Remove resource files of uncompiled drivers
284    && (for i in \
285            # unused
286            /build/usr/share/gdal/*.svg \
287            # unused
288            /build/usr/share/gdal/*.png \
289       ;do rm $i; done)
290
291# Build final image
292FROM alpine:${ALPINE_VERSION} as runner
293
294RUN date
295
296ARG POPPLER=poppler
297RUN apk add --no-cache \
298        libstdc++ \
299        sqlite-libs \
300        libcurl tiff \
301        zlib zstd-libs\
302        libjpeg-turbo libpng libwebp expat \
303        icu-libs \
304        python3 py3-numpy ${POPPLER} pcre libpq libxml2 portablexdr openjpeg \
305        netcdf hdf5 freexl \
306        openexr libheif xerces-c geos cfitsio minizip \
307    # Remove /usr/lib/libopenjp2.so.2.3.0 since we are building v2.3.1 manually
308    # && rm -f /usr/lib/libopenjp2.so.2.3.0 \
309    # libturbojpeg.so is not used by GDAL. Only libjpeg.so*
310    && rm -f /usr/lib/libturbojpeg.so* \
311    # libpoppler-cpp.so is not used by GDAL. Only libpoppler.so*
312    && rm -f /usr/lib/libpoppler-cpp.so* \
313    # Only libwebp.so is used by GDAL
314    && rm -f /usr/lib/libwebpmux.so* /usr/lib/libwebpdemux.so* /usr/lib/libwebpdecoder.so* \
315    && ln -s /usr/bin/python3 /usr/bin/python
316
317# Order layers starting with less frequently varying ones
318COPY --from=builder  /build_thirdparty/usr/ /usr/
319
320COPY --from=builder  /build_projgrids/usr/ /usr/
321
322COPY --from=builder  /build_spatialite/usr/ /usr/
323
324COPY --from=builder  /build_proj/usr/share/proj/ /usr/share/proj/
325COPY --from=builder  /build_proj/usr/include/ /usr/include/
326COPY --from=builder  /build_proj/usr/bin/ /usr/bin/
327COPY --from=builder  /build_proj/usr/lib/ /usr/lib/
328
329COPY --from=builder  /build/usr/share/gdal/ /usr/share/gdal/
330COPY --from=builder  /build/usr/include/ /usr/include/
331COPY --from=builder  /build_gdal_python/usr/ /usr/
332COPY --from=builder  /build_gdal_version_changing/usr/ /usr/
333