Repository: apache/guacamole-server
Pull request #575: GUACAMOLE-1374: Migrate to LOG_LEVEL and modular Docker build.
Author: login: mike-jumper
Created: 2025-02-14T10:06:32Z | Merged: 2025-04-22T19:33:35Z

This change migrates to a Docker build leveraging multiple modular stages that cover each of guacamole-server's dependencies, avoiding unnecessary recompilation of dependencies that are not changing (something that is slowing down rebuilds for testing quite a bit, particularly if any download from GitHub times out).

For consistency's sake, I've also added a `LOG_LEVEL` variable to replace `GUACD_LOG_LEVEL`, in line with the guacamole-client image.


Diff:
diff --git a/Dockerfile b/Dockerfile
index 0288dcb503..e85bb4328a 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -25,46 +25,24 @@
 # NOTE: Using 3.18 because the required openssl1.1-compat-dev package was
 # removed in more recent versions.
 ARG ALPINE_BASE_IMAGE=3.18
-FROM alpine:${ALPINE_BASE_IMAGE} AS builder
 
-# FreeRDP version (default to version 3)
-ARG FREERDP_VERSION=3
+# The target architecture of the build. Valid values are "ARM" and "X86". By
+# default, this is detected automatically.
+ARG BUILD_ARCHITECTURE
 
-# Install build dependencies
-RUN apk add --no-cache                \
-        autoconf                      \
-        automake                      \
-        build-base                    \
-        cairo-dev                     \
-        cjson-dev                     \
-        cmake                         \
-        cunit-dev                     \
-        git                           \
-        grep                          \
-        krb5-dev                      \
-        libjpeg-turbo-dev             \
-        libpng-dev                    \
-        libtool                       \
-        libwebp-dev                   \
-        make                          \
-        openssl1.1-compat-dev         \
-        pango-dev                     \
-        pulseaudio-dev                \
-        sdl2-dev                      \
-        sdl2_ttf-dev                  \
-        util-linux-dev                \
-        webkit2gtk-dev
+# The number of processes that may run simultaneously during the build. By
+# default, this is detected automatically.
+ARG BUILD_JOBS
 
-# Copy source to container for sake of build
+# The directory that will house the guacamole-server source during the build 
 ARG BUILD_DIR=/tmp/guacamole-server
-COPY . ${BUILD_DIR}
 
-#
-# Base directory for installed build artifacts.
-#
-# NOTE: Due to limitations of the Docker image build process, this value is
-# duplicated in an ARG in the second stage of the build.
-#
+# FreeRDP version (default to version 3)
+ARG FREERDP_VERSION=3
+
+# The final install location for guacamole-server and all dependencies. NOTE:
+# This value is hard-coded in the entrypoint. Any change to this value must be
+# propagated there.
 ARG PREFIX_DIR=/opt/guacamole
 
 #
@@ -84,6 +62,8 @@ ARG WITH_LIBWEBSOCKETS='v\d+(\.\d+)+'
 # options are needed)
 #
 
+ARG FREERDP_ARM_OPTS=""
+
 ARG FREERDP_OPTS="\
     -DBUILTIN_CHANNELS=OFF \
     -DCHANNEL_URBDRC=OFF \
@@ -112,7 +92,6 @@ ARG FREERDP_OPTS="\
     -DWITH_SERVER_INTERFACE=OFF \
     -DWITH_SHADOW_MAC=OFF \
     -DWITH_SHADOW_X11=OFF \
-    -DWITH_SSE2=ON \
     -DWITH_SWSCALE=OFF \
     -DWITH_WAYLAND=OFF \
     -DWITH_X11=OFF \
@@ -127,19 +106,40 @@ ARG FREERDP_OPTS="\
     -DWITH_XV=OFF \
     -DWITH_ZLIB=ON"
 
+ARG FREERDP_X86_OPTS=""
+
+ARG GUACAMOLE_SERVER_ARM_OPTS=""
+
 ARG GUACAMOLE_SERVER_OPTS="\
-    --disable-guaclog"
+    --disable-guaclog \
+    CPPFLAGS=-Wno-error=deprecated-declarations"
+
+ARG GUACAMOLE_SERVER_X86_OPTS=""
+
+ARG LIBSSH2_ARM_OPTS=""
 
 ARG LIBSSH2_OPTS="\
     -DBUILD_EXAMPLES=OFF \
     -DBUILD_SHARED_LIBS=ON"
 
+ARG LIBSSH2_X86_OPTS=""
+
+ARG LIBTELNET_ARM_OPTS=""
+
 ARG LIBTELNET_OPTS="\
     --disable-static \
     --disable-util"
 
+ARG LIBTELNET_X86_OPTS=""
+
+ARG LIBVNCCLIENT_ARM_OPTS=""
+
 ARG LIBVNCCLIENT_OPTS=""
 
+ARG LIBVNCCLIENT_X86_OPTS=""
+
+ARG LIBWEBSOCKETS_ARM_OPTS=""
+
 ARG LIBWEBSOCKETS_OPTS="\
     -DDISABLE_WERROR=ON \
     -DLWS_WITHOUT_SERVER=ON \
@@ -150,8 +150,143 @@ ARG LIBWEBSOCKETS_OPTS="\
     -DLWS_WITHOUT_TEST_SERVER_EXTPOLL=ON \
     -DLWS_WITH_STATIC=OFF"
 
-# Build guacamole-server and its core protocol library dependencies
-RUN ${BUILD_DIR}/src/guacd-docker/bin/build-all.sh
+ARG LIBWEBSOCKETS_X86_OPTS=""
+
+#
+# Base builder image that will be used by subsequent build stages, including
+# for building dependencies of guacamole-server.
+#
+
+FROM alpine:${ALPINE_BASE_IMAGE} AS builder
+ARG BUILD_DIR
+
+# Install build dependencies
+RUN apk add --no-cache                \
+        autoconf                      \
+        automake                      \
+        build-base                    \
+        cairo-dev                     \
+        cjson-dev                     \
+        cmake                         \
+        cunit-dev                     \
+        git                           \
+        grep                          \
+        krb5-dev                      \
+        libjpeg-turbo-dev             \
+        libpng-dev                    \
+        libtool                       \
+        libwebp-dev                   \
+        make                          \
+        openssl1.1-compat-dev         \
+        pango-dev                     \
+        pulseaudio-dev                \
+        sdl2-dev                      \
+        sdl2_ttf-dev                  \
+        util-linux-dev                \
+        webkit2gtk-dev
+
+# Copy generic, automatic build script
+COPY ./src/guacd-docker/bin/autobuild.sh ${BUILD_DIR}/src/guacd-docker/bin/
+
+#
+# Build dependency: libssh2
+#
+
+FROM builder AS libssh2
+ARG BUILD_DIR
+ARG LIBSSH2_ARM_OPTS
+ARG LIBSSH2_OPTS
+ARG LIBSSH2_X86_OPTS
+ARG PREFIX_DIR
+ARG WITH_LIBSSH2
+
+RUN ${BUILD_DIR}/src/guacd-docker/bin/autobuild.sh "LIBSSH2" \
+    "https://github.com/libssh2/libssh2"
+
+#
+# Build dependency: libtelnet
+#
+
+FROM builder AS libtelnet
+ARG BUILD_DIR
+ARG LIBTELNET_ARM_OPTS
+ARG LIBTELNET_OPTS
+ARG LIBTELNET_X86_OPTS
+ARG PREFIX_DIR
+ARG WITH_LIBTELNET
+
+RUN ${BUILD_DIR}/src/guacd-docker/bin/autobuild.sh "LIBTELNET" \
+    "https://github.com/seanmiddleditch/libtelnet"
+
+#
+# Build dependency: libvncclient
+#
+
+FROM builder AS libvncclient
+ARG BUILD_DIR
+ARG LIBVNCCLIENT_ARM_OPTS
+ARG LIBVNCCLIENT_OPTS
+ARG LIBVNCCLIENT_X86_OPTS
+ARG PREFIX_DIR
+ARG WITH_LIBVNCCLIENT
+
+RUN ${BUILD_DIR}/src/guacd-docker/bin/autobuild.sh "LIBVNCCLIENT" \
+    "https://github.com/LibVNC/libvncserver"
+
+#
+# Build dependency: libwebsockets
+#
+
+FROM builder AS libwebsockets
+ARG BUILD_DIR
+ARG LIBWEBSOCKETS_ARM_OPTS
+ARG LIBWEBSOCKETS_OPTS
+ARG LIBWEBSOCKETS_X86_OPTS
+ARG PREFIX_DIR
+ARG WITH_LIBWEBSOCKETS
+
+RUN ${BUILD_DIR}/src/guacd-docker/bin/autobuild.sh "LIBWEBSOCKETS" \
+    "https://github.com/warmcat/libwebsockets"
+
+#
+# Build dependency: FreeRDP
+#
+
+FROM builder AS freerdp
+ARG BUILD_DIR
+ARG FREERDP_ARM_OPTS
+ARG FREERDP_OPTS
+ARG FREERDP_X86_OPTS
+ARG PREFIX_DIR
+ARG WITH_FREERDP
+
+RUN ${BUILD_DIR}/src/guacd-docker/bin/autobuild.sh "FREERDP" \
+    "https://github.com/FreeRDP/FreeRDP"
+
+#
+# STAGE 7: Collect dependencies built by previous stages and build
+# guacamole-server.
+#
+
+FROM builder AS guacamole-server
+ARG BUILD_DIR
+ARG FREERDP_VERSION
+ARG GUACAMOLE_SERVER_ARM_OPTS
+ARG GUACAMOLE_SERVER_OPTS
+ARG GUACAMOLE_SERVER_X86_OPTS
+ARG PREFIX_DIR
+
+# Copy dependencies built in previous stages
+COPY --from=freerdp ${PREFIX_DIR} ${PREFIX_DIR}
+COPY --from=libssh2 ${PREFIX_DIR} ${PREFIX_DIR}
+COPY --from=libtelnet ${PREFIX_DIR} ${PREFIX_DIR}
+COPY --from=libvncclient ${PREFIX_DIR} ${PREFIX_DIR}
+COPY --from=libwebsockets ${PREFIX_DIR} ${PREFIX_DIR}
+
+# Use guacamole-server source from build context
+COPY . ${BUILD_DIR}
+
+RUN ${BUILD_DIR}/src/guacd-docker/bin/autobuild.sh "GUACAMOLE_SERVER" "${BUILD_DIR}"
 
 # Determine location of the FREERDP library based on the version.
 ARG FREERDP_LIB_PATH=${PREFIX_DIR}/lib/freerdp${FREERDP_VERSION}
@@ -163,25 +298,16 @@ RUN ${BUILD_DIR}/src/guacd-docker/bin/list-dependencies.sh \
         ${FREERDP_LIB_PATH}/*guac*.so   \
         > ${PREFIX_DIR}/DEPENDENCIES
 
-# Use same Alpine version as the base for the runtime image
-FROM alpine:${ALPINE_BASE_IMAGE}
-
-#
-# Base directory for installed build artifacts. See also the
-# CMD directive at the end of this build stage.
 #
-# NOTE: Due to limitations of the Docker image build process, this value is
-# duplicated in an ARG in the first stage of the build.
+# STAGE 8: Final, runtime image.
 #
-ARG PREFIX_DIR=/opt/guacamole
 
-# Runtime environment
-ENV LC_ALL=C.UTF-8
-ENV LD_LIBRARY_PATH=${PREFIX_DIR}/lib
-ENV GUACD_LOG_LEVEL=info
+# Use same Alpine version as the base for the runtime image
+FROM alpine:${ALPINE_BASE_IMAGE} AS runtime
+ARG PREFIX_DIR
 
 # Copy build artifacts into this stage
-COPY --from=builder ${PREFIX_DIR} ${PREFIX_DIR}
+COPY --from=guacamole-server ${PREFIX_DIR} ${PREFIX_DIR}
 
 # Bring runtime environment up to date and install runtime dependencies
 RUN apk add --no-cache                \
@@ -196,6 +322,10 @@ RUN apk add --no-cache                \
         util-linux-login && \
     xargs apk add --no-cache < ${PREFIX_DIR}/DEPENDENCIES
 
+# Runtime environment
+ENV LC_ALL=C.UTF-8
+ENV LD_LIBRARY_PATH=${PREFIX_DIR}/lib
+
 # Checks the operating status every 5 minutes with a timeout of 5 seconds
 HEALTHCHECK --interval=5m --timeout=5s CMD nc -z 127.0.0.1 4822 || exit 1
 
@@ -211,9 +341,5 @@ USER guacd
 # Expose the default listener port
 EXPOSE 4822
 
-# Start guacd, listening on port 0.0.0.0:4822
-#
-# Note the path here MUST correspond to the value specified in the 
-# PREFIX_DIR build argument.
-#
-CMD /opt/guacamole/sbin/guacd -b 0.0.0.0 -L $GUACD_LOG_LEVEL -f
+COPY ./src/guacd-docker/bin/entrypoint.sh /opt/guacamole/
+ENTRYPOINT [ "/opt/guacamole/entrypoint.sh" ]
diff --git a/src/guacd-docker/bin/autobuild.sh b/src/guacd-docker/bin/autobuild.sh
new file mode 100755
index 0000000000..a38181eb98
--- /dev/null
+++ b/src/guacd-docker/bin/autobuild.sh
@@ -0,0 +1,144 @@
+#!/bin/sh -e
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+##
+## @fn autobuild.sh
+##
+## Automatically builds the source of guacamole-server or its various core
+## protocol library dependencies. Usage of GNU Autotools vs. CMake is
+## automatically detected. Additional build options may be provided using
+## environment variables, including architecture-specific options.
+##
+## @param VAR_BASE
+##     The text that should be used as the base for environment variables
+##     that control the build. The following variables will be read:
+##
+##     - [VAR_BASE]_OPTS: Options that should be passed to the build regardless
+##       of architecture.
+##
+##     - [VAR_BASE]_ARM_OPTS: Options that should be passed to the build only
+##       if built for ARM CPUs.
+##
+##     - [VAR_BASE]_X86_OPTS: Options that should be passed to the build only
+##       if built for x86 (Intel, AMD) CPUs.
+##
+##     - WITH_[VAR_BASE]: The git reference (tag, commit, etc.) that should be
+##       built, or a regular expression that matches the version tag that
+##       should be built (the largest-numbered tag will be chosen). This
+##       variable is only applicable if the source is being pulled from a git
+##       repository (the URL of a git repository is provided for LOCATION).
+##
+## @param LOCATION
+##     The location of the source to be used for the build. This may be a
+##     directory or the URL of a git repository.
+##
+
+VAR_BASE="$1"
+LOCATION="$2"
+
+# Pre-populate build control variables such that the custom build prefix is
+# used for C headers, locating libraries, etc.
+export CFLAGS="-I${PREFIX_DIR}/include"
+export LDFLAGS="-L${PREFIX_DIR}/lib"
+export PKG_CONFIG_PATH="${PREFIX_DIR}/lib/pkgconfig" 
+
+# Ensure thread stack size will be 8 MB (glibc's default on Linux) rather than
+# 128 KB (musl's default)
+export LDFLAGS="$LDFLAGS -Wl,-z,stack-size=8388608"
+
+PATTERN_VAR="WITH_${VAR_BASE}"
+PATTERN="$(printenv "${PATTERN_VAR}" || true)"
+
+# Allow dependencies to be manually omitted with the tag/commit pattern "NO"
+if [ "$PATTERN" = "NO" ]; then
+    echo "NOT building $REPO_DIR (explicitly skipped)"
+    exit
+fi
+
+# Clone repository and change to top-level directory of source
+if echo "$LOCATION" | grep -q '://'; then
+    cd /tmp
+    git clone "$LOCATION"
+    SRC_DIR="$(basename "$LOCATION" .git)"
+else
+    SRC_DIR="$LOCATION"
+fi
+
+# Determine architecture that we're building on
+if [ -z "$BUILD_ARCHITECTURE" ]; then
+    case "$(uname -m)" in
+        arm|armv6l|armv7l|armv8l|aarch64)
+            BUILD_ARCHITECTURE="ARM"
+            ;;
+        i386|i686|x86_64)
+            BUILD_ARCHITECTURE="X86"
+            ;;
+        *)
+            BUILD_ARCHITECTURE="UNKNOWN"
+            ;;
+    esac
+fi
+
+# Determine how many procesess we can potentially run at once for the build
+if [ -z "$BUILD_JOBS" ]; then
+    BUILD_JOBS="$(nproc)"
+fi
+
+echo "Build architecture: $BUILD_ARCHITECTURE"
+echo "Build parallelism: $BUILD_JOBS job(s)"
+cd "$SRC_DIR/"
+
+OPTION_VAR="${VAR_BASE}_OPTS"
+ARCH_OPTION_VAR="${VAR_BASE}_${BUILD_ARCHITECTURE}_OPTS"
+BUILD_OPTS="$(printenv "${OPTION_VAR}" || true) $(printenv "${ARCH_OPTION_VAR}" || true)"
+
+# Download (if necessary) and log location of source
+if [ -e .git ]; then
+
+    # Locate tag/commit based on provided pattern
+    VERSION="$(git tag -l --sort=-v:refname | grep -Px -m1 "$PATTERN" \
+        || echo "$PATTERN")"
+
+    # Switch to desired version of source
+    echo "Building $SRC_DIR @ $VERSION ..."
+    git -c advice.detachedHead=false checkout "$VERSION"
+
+else
+    echo "Building $SRC_DIR ..."
+fi
+
+# Configure build using CMake or GNU Autotools, whichever happens to be
+# used by the library being built
+if [ -e CMakeLists.txt ]; then
+    cmake \
+        -B "${SRC_DIR}-build" -S . \
+        -DCMAKE_INSTALL_PREFIX:PATH="$PREFIX_DIR" \
+        $BUILD_OPTS
+
+    # Build and install
+    cmake --build "${SRC_DIR}-build" --parallel "$BUILD_JOBS"
+    cmake --install "${SRC_DIR}-build"
+else
+    [ -e configure ] || autoreconf -fi
+    ./configure --prefix="$PREFIX_DIR" $BUILD_OPTS
+
+    # Build and install
+    make -j"$BUILD_JOBS" && make install
+fi
diff --git a/src/guacd-docker/bin/build-all.sh b/src/guacd-docker/bin/build-all.sh
deleted file mode 100755
index 430419cfe9..0000000000
--- a/src/guacd-docker/bin/build-all.sh
+++ /dev/null
@@ -1,136 +0,0 @@
-#!/bin/sh -e
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-##
-## @fn build-all.sh
-##
-## Builds the source of guacamole-server and its various core protocol library
-## dependencies.
-##
-
-# Pre-populate build control variables such that the custom build prefix is
-# used for C headers, locating libraries, etc.
-export CFLAGS="-I${PREFIX_DIR}/include"
-export LDFLAGS="-L${PREFIX_DIR}/lib"
-export PKG_CONFIG_PATH="${PREFIX_DIR}/lib/pkgconfig" 
-
-# Ensure thread stack size will be 8 MB (glibc's default on Linux) rather than
-# 128 KB (musl's default)
-export LDFLAGS="$LDFLAGS -Wl,-z,stack-size=8388608"
-
-##
-## Builds and installs the source at the given git repository, automatically
-## switching to the version of the source at the tag/commit that matches the
-## given pattern.
-##
-## @param URL
-##     The URL of the git repository that the source should be downloaded from.
-##
-## @param PATTERN
-##     The Perl-compatible regular expression that the tag must match. If no
-##     tag matches the regular expression, the pattern is assumed to be an
-##     exact reference to a commit, branch, etc. acceptable by git checkout.
-##
-## @param ...
-##     Any additional command-line options that should be provided to CMake or
-##     the configure script.
-##
-install_from_git() {
-
-    URL="$1"
-    PATTERN="$2"
-    shift 2
-
-    # Calculate top-level directory name of resulting repository from the
-    # provided URL
-    REPO_DIR="$(basename "$URL" .git)"
-
-    # Allow dependencies to be manually omitted with the tag/commit pattern "NO"
-    if [ "$PATTERN" = "NO" ]; then
-        echo "NOT building $REPO_DIR (explicitly skipped)"
-        return
-    fi
-
-    # Clone repository and change to top-level directory of source
-    cd /tmp
-    git clone "$URL"
-    cd $REPO_DIR/
-
-    # Locate tag/commit based on provided pattern
-    VERSION="$(git tag -l --sort=-v:refname | grep -Px -m1 "$PATTERN" \
-        || echo "$PATTERN")"
-
-    # Switch to desired version of source
-    echo "Building $REPO_DIR @ $VERSION ..."
-    git -c advice.detachedHead=false checkout "$VERSION"
-
-    # Configure build using CMake or GNU Autotools, whichever happens to be
-    # used by the library being built
-    if [ -e CMakeLists.txt ]; then
-        cmake \
-            -B "${REPO_DIR}-build" -S . \
-            -DCMAKE_INSTALL_PREFIX:PATH="$PREFIX_DIR" \
-            "$@"
-
-        # Build and install
-        cmake --build "${REPO_DIR}-build"
-        cmake --install "${REPO_DIR}-build"
-    else
-        [ -e configure ] || autoreconf -fi
-        ./configure --prefix="$PREFIX_DIR" "$@"
-
-        # Build and install
-        make && make install
-    fi
-}
-
-#
-# Determine any option overrides to guarantee successful build
-#
-
-export BUILD_ARCHITECTURE="$(arch)" # Determine architecture building on
-echo "Build architecture: $BUILD_ARCHITECTURE"
-
-case $BUILD_ARCHITECTURE in
-    armv6l|armv7l|aarch64)
-        export FREERDP_OPTS_OVERRIDES="-DWITH_SSE2=OFF" # Disable SSE2 on ARM
-        ;;
-    *)
-        export FREERDP_OPTS_OVERRIDES=""
-        ;;
-esac
-
-#
-# Build and install core protocol library dependencies
-#
-
-install_from_git "https://github.com/FreeRDP/FreeRDP" "$WITH_FREERDP" $FREERDP_OPTS $FREERDP_OPTS_OVERRIDES
-install_from_git "https://github.com/libssh2/libssh2" "$WITH_LIBSSH2" $LIBSSH2_OPTS
-install_from_git "https://github.com/seanmiddleditch/libtelnet" "$WITH_LIBTELNET" $LIBTELNET_OPTS
-install_from_git "https://github.com/LibVNC/libvncserver" "$WITH_LIBVNCCLIENT" $LIBVNCCLIENT_OPTS
-install_from_git "https://github.com/warmcat/libwebsockets" "$WITH_LIBWEBSOCKETS" $LIBWEBSOCKETS_OPTS
-
-#
-# Build guacamole-server
-#
-
-cd "$BUILD_DIR"
-autoreconf -fi && ./configure --prefix="$PREFIX_DIR" $GUACAMOLE_SERVER_OPTS
-make && make check && make install
diff --git a/src/guacd-docker/bin/entrypoint.sh b/src/guacd-docker/bin/entrypoint.sh
new file mode 100755
index 0000000000..e7da4a341f
--- /dev/null
+++ b/src/guacd-docker/bin/entrypoint.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# Warn about deprecation of GUACD_LOG_LEVEL
+if [ -n "$GUACD_LOG_LEVEL" ]; then
+    echo "WARNING: The GUACD_LOG_LEVEL environment variable has been deprecated in favor of the LOG_LEVEL environment variable. Please migrate your configuration when possible." >&2
+fi
+
+# Listen on 0.0.0.0:4822, logging messages at the info level. Allow log level
+# to be overridden with LOG_LEVEL, and other behavior to be overridden with
+# additional command-line options passed to Docker.
+exec /opt/guacamole/sbin/guacd -f -b 0.0.0.0 -L "${LOG_LEVEL:-${GUACD_LOG_LEVEL:-info}}" "$@"


Reviews:
user: login: aaron-iles
body: LGTM. Testing the build now.
state: APPROVED
author_association: NONE
submitted_at: 2025-02-19T14:21:32Z
user: login: mattieb
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-19T11:47:18Z
user: login: necouchman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-21T15:54:17Z
user: login: mike-jumper
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T07:15:46Z
user: login: mike-jumper
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T07:20:26Z
user: login: necouchman
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T19:33:18Z

Review comments:
diff_hunk: @@ -127,19 +106,39 @@ ARG FREERDP_OPTS="\
     -DWITH_XV=OFF \
     -DWITH_ZLIB=ON"
 
+ARG FREERDP_X86_OPTS="-DWITH_SSE2=ON"
path: Dockerfile
user: login: mattieb
body: You may be able to use WITH_SIMD across all architectures in modern versions of FreeRDP—it [replaces WITH_SSE2](https://github.com/FreeRDP/FreeRDP/blob/6a4bbfc04712885e4322a48988b4833cd3c46ea0/cmake/DetectIntrinsicSupport.cmake#L5) anyway.
created_at: 2025-04-19T11:47:18Z
author_association: NONE
diff_hunk: @@ -0,0 +1,144 @@
+#!/bin/sh -e
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+##
+## @fn autobuild.sh
+##
+## Automatically builds the source of guacamole-server or its various core
+## protocol library dependencies. Usage of GNU Autotools vs. CMake is
+## automatically detected. Additional build options may be provided using
+## environment variables, including architecture-specific options.
+##
+## @param VAR_BASE
+##     The text that should be used as the base for environment variables
+##     that control the build. The following variables will be read:
+##
+##     - [VAR_BASE]_OPTS: Options that should be passed to the build regardless
+##       of architecture.
+##
+##     - [VAR_BASE]_ARM_OPTS: Options that should be passed to the build only
+##       if built for ARM CPUs.
+##
+##     - [VAR_BASE]_X86_OPTS: Options that should be passed to the build only
+##       if built for x86 (Intel, AMD) CPUs.
+##
+##     - WITH_[VAR_BASE]: The git reference (tag, commit, etc.) that should be
+##       built, or a regular expression that matches the version tag that
+##       should be built (the largest-numbered tag will be chosen). This
+##       variable is only applicable if the source is being pulled from a git
+##       repository (the URL of a git repository is provided for LOCATION).
+##
+## @param LOCATION
+##     The location of the source to be used for the build. This may be a
+##     directory or the URL of a git repository.
+##
+
+VAR_BASE="$1"
+LOCATION="$2"
+
+# Pre-populate build control variables such that the custom build prefix is
+# used for C headers, locating libraries, etc.
+export CFLAGS="-I${PREFIX_DIR}/include"
+export LDFLAGS="-L${PREFIX_DIR}/lib"
+export PKG_CONFIG_PATH="${PREFIX_DIR}/lib/pkgconfig" 
+
+# Ensure thread stack size will be 8 MB (glibc's default on Linux) rather than
+# 128 KB (musl's default)
+export LDFLAGS="$LDFLAGS -Wl,-z,stack-size=8388608"
+
+PATTERN_VAR="WITH_${VAR_BASE}"
+PATTERN="$(printenv "${PATTERN_VAR}" || true)"
+
+# Allow dependencies to be manually omitted with the tag/commit pattern "NO"
+if [ "$PATTERN" = "NO" ]; then
+    echo "NOT building $REPO_DIR (explicitly skipped)"
+    exit
+fi
+
+# Clone repository and change to top-level directory of source
+if echo "$LOCATION" | grep -q '://'; then
+    cd /tmp
+    git clone "$LOCATION"
+    SRC_DIR="$(basename "$LOCATION" .git)"
+else
+    SRC_DIR="$LOCATION"
+fi
+
+# Determine architecture that we're building on
+if [ -z "$BUILD_ARCHITECTURE" ]; then
+    case "$(uname -m)" in
+        armv6l|armv7l|aarch64)
+            BUILD_ARCHITECTURE="ARM"
+            ;;
+        x86_64)
+            BUILD_ARCHITECTURE="X86"
path: src/guacd-docker/bin/autobuild.sh
user: login: necouchman
body: I know 32-bit x86 has mostly gone away, but are there any known issues with Guacamole running in a 32-bit x86 environment? Should this be broadened to include both i686 and x86_64?
created_at: 2025-04-21T15:54:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -127,19 +106,39 @@ ARG FREERDP_OPTS="\
     -DWITH_XV=OFF \
     -DWITH_ZLIB=ON"
 
+ARG FREERDP_X86_OPTS="-DWITH_SSE2=ON"
path: Dockerfile
user: login: mike-jumper
body: Welp, this would still have to be `WITH_SSE2` for builds against FreeRDP 2.x, but thankfully it looks like both `WITH_SSE2` (2.x) and `WITH_SIMD` (3.x) are the default. I'll just remove the option.
created_at: 2025-04-22T07:15:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,144 @@
+#!/bin/sh -e
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+##
+## @fn autobuild.sh
+##
+## Automatically builds the source of guacamole-server or its various core
+## protocol library dependencies. Usage of GNU Autotools vs. CMake is
+## automatically detected. Additional build options may be provided using
+## environment variables, including architecture-specific options.
+##
+## @param VAR_BASE
+##     The text that should be used as the base for environment variables
+##     that control the build. The following variables will be read:
+##
+##     - [VAR_BASE]_OPTS: Options that should be passed to the build regardless
+##       of architecture.
+##
+##     - [VAR_BASE]_ARM_OPTS: Options that should be passed to the build only
+##       if built for ARM CPUs.
+##
+##     - [VAR_BASE]_X86_OPTS: Options that should be passed to the build only
+##       if built for x86 (Intel, AMD) CPUs.
+##
+##     - WITH_[VAR_BASE]: The git reference (tag, commit, etc.) that should be
+##       built, or a regular expression that matches the version tag that
+##       should be built (the largest-numbered tag will be chosen). This
+##       variable is only applicable if the source is being pulled from a git
+##       repository (the URL of a git repository is provided for LOCATION).
+##
+## @param LOCATION
+##     The location of the source to be used for the build. This may be a
+##     directory or the URL of a git repository.
+##
+
+VAR_BASE="$1"
+LOCATION="$2"
+
+# Pre-populate build control variables such that the custom build prefix is
+# used for C headers, locating libraries, etc.
+export CFLAGS="-I${PREFIX_DIR}/include"
+export LDFLAGS="-L${PREFIX_DIR}/lib"
+export PKG_CONFIG_PATH="${PREFIX_DIR}/lib/pkgconfig" 
+
+# Ensure thread stack size will be 8 MB (glibc's default on Linux) rather than
+# 128 KB (musl's default)
+export LDFLAGS="$LDFLAGS -Wl,-z,stack-size=8388608"
+
+PATTERN_VAR="WITH_${VAR_BASE}"
+PATTERN="$(printenv "${PATTERN_VAR}" || true)"
+
+# Allow dependencies to be manually omitted with the tag/commit pattern "NO"
+if [ "$PATTERN" = "NO" ]; then
+    echo "NOT building $REPO_DIR (explicitly skipped)"
+    exit
+fi
+
+# Clone repository and change to top-level directory of source
+if echo "$LOCATION" | grep -q '://'; then
+    cd /tmp
+    git clone "$LOCATION"
+    SRC_DIR="$(basename "$LOCATION" .git)"
+else
+    SRC_DIR="$LOCATION"
+fi
+
+# Determine architecture that we're building on
+if [ -z "$BUILD_ARCHITECTURE" ]; then
+    case "$(uname -m)" in
+        armv6l|armv7l|aarch64)
+            BUILD_ARCHITECTURE="ARM"
+            ;;
+        x86_64)
+            BUILD_ARCHITECTURE="X86"
path: src/guacd-docker/bin/autobuild.sh
user: login: mike-jumper
body: Sure, easy enough.
created_at: 2025-04-22T07:20:26Z
author_association: CONTRIBUTOR

PR comments:
user: login: necouchman
created_at: 2025-04-21T15:54:54Z
body: Just one comment from me, plus the one that @mattieb mentioned above, and this should be ready to merge.
author_association: CONTRIBUTOR
user: login: mike-jumper
created_at: 2025-04-22T08:18:53Z
body: Went ahead and added `CPPFLAGS=-Wno-error=deprecated-declarations` to `GUACAMOLE_SERVER_OPTS`, as well, to work around the FreeRDP header warnings until addressed in FreeRDP or GCC.
author_association: CONTRIBUTOR