Skip to content

Commit

Permalink
GUACAMOLE-1841: Implement MinGW build for libguac.
Browse files Browse the repository at this point in the history
  • Loading branch information
jmuehlner committed Jan 26, 2024
1 parent a575af6 commit e1dfde0
Show file tree
Hide file tree
Showing 83 changed files with 3,498 additions and 395 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,6 @@ doc/*/doxygen-output

# IDE metadata
nbproject/

# Crash Reports
**/*.stackdump
116 changes: 116 additions & 0 deletions README-windows-build.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# Building guacamole-server for Windows
Certain portions of `guacamole-server` can be built using MinGW on Windows, specifically the libguac libraries. `guacd` itself relies on `fork()` and other functionality that has no equivalent in Windows. Theoretically, Cygwin could provide a compatibility layer for these missing functions, but so far attempts to implement such a build have not resulted in a functional `guacd`.

This document will walk you through a known-working set of steps for building the libguac libraries for a Windows target. The following build steps were tested on a Windows Server 2022 x86_64 build node.

### Build Steps
1. Install MSYS2 (version 20230718 used here)
2. Install MSYS2 packages:
* autoconf-wrapper
* automake-wrapper
* diffutils
* git
* libtool
* libedit-devel
* make
* pkg-config
* wget
* msys2-runtime-devel
* mingw-w64-x86_64-gcc
* mingw-w64-x86_64-libwebsockets
* mingw-w64-x86_64-libtool
* mingw-w64-x86_64-dlfcn
* mingw-w64-x86_64-pkg-config
* mingw-w64-x86_64-cairo
* mingw-w64-x86_64-gcc
* mingw-w64-x86_64-gdb
* mingw-w64-x86_64-libpng
* mingw-w64-x86_64-libjpeg-turbo
* mingw-w64-x86_64-freerdp (version < 3)
* mingw-w64-x86_64-freetds
* mingw-w64-x86_64-postgresql
* mingw-w64-x86_64-libmariadbclient
* mingw-w64-x86_64-libvncserver
* mingw-w64-x86_64-dlfcn
* mingw-w64-x86_64-libgcrypt
* mingw-w64-x86_64-libgxps
* mingw-w64-x86_64-libwebsockets
* mingw-w64-x86_64-libwebp
* mingw-w64-x86_64-libssh2
* mingw-w64-x86_64-openssl
* mingw-w64-x86_64-libvorbis
* mingw-w64-x86_64-pulseaudio
* mingw-w64-x86_64-zlib
*
3. Build `libtelnet` from source using MSYS2 bash shell
```
export PKG_CONFIG_PATH="/mingw64/lib/pkgconfig"
export PATH="$PATH:/mingw64/bin:/usr/bin"
curl -s -L https://github.com/seanmiddleditch/libtelnet/releases/download/0.23/libtelnet-0.23.tar.gz | tar xz
cd libtelnet-0.23
autoreconf -fi
./configure --prefix=/mingw64 --disable-static --disable-util LDFLAGS="-Wl,-no-undefined -L/mingw64/bin/ -L/mingw64/lib" || cat config.log
cat config.log
make LDFLAGS="-no-undefined"
make install
```
4. Fix DLL prefixes so that the build can link against them, e.g. using this script
```
#!/bin/bash
set -e
set -x
# Enable fancy pattern matching on filenames (provides wildcards that can match
# multiple contiguous digits, among others)
shopt -s extglob
# Strip architecture suffix
for LIB in /mingw64/bin/lib*-x64.dll; do
ln -sfv "$LIB" "$(echo "$LIB" | sed 's/-x64.dll$/.dll/')"
done
# Automatically add symlinks that strip the library version suffix
for LIB in /mingw64/bin/lib*-+([0-9]).dll; do
ln -sfv "$LIB" "$(echo "$LIB" | sed 's/-[0-9]*\.dll$/.dll/')"
done
# Automatically add symlinks that strip the library version suffix
for LIB in /mingw64/bin/lib*([^0-9.])@([^0-9.-])+([0-9]).dll; do
ln -sfv "$LIB" "$(echo "$LIB" | sed 's/[0-9]*\.dll$/.dll/')"
done
```
5. Build `guacamole-server` from source using MSYS2 bash shell
```
export PKG_CONFIG_PATH="/mingw64/lib/pkgconfig:/usr/lib/pkgconfig"
export PATH="$PATH:/mingw64/bin:/usr/bin"
# FIXME: Update this to check out master once this PR is ready for merge
git clone https://github.com/jmuehlner/guacamole-server.git
cd guacamole-server
git checkout GUACAMOLE-1841-cygwin-build-clean
autoreconf -fi
export LDFLAGS="-L/mingw64/bin/ -L/usr/bin/ -L/mingw64/lib -lws2_32"
export CFLAGS="-isystem/mingw64/include/ \
-I/mingw64/include/pango-1.0 \
-I/mingw64/include/glib-2.0/ \
-I/mingw64/lib/glib-2.0/include/ \
-I/mingw64/include/harfbuzz/ \
-I/mingw64/include/cairo/ \
-I/mingw64/include/freerdp2 \
-I/mingw64/include/winpr2 \
-Wno-error=expansion-to-defined
-Wno-error=attributes"
./configure --prefix=/mingw64 --with-windows --disable-guacenc --disable-guacd --disable-guaclog || cat config.log
make
make install
```

## Closing Notes
FIXME: Update this document to explain how to configure fonts under Windows once I figure it out.
110 changes: 82 additions & 28 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,35 @@ AC_PROG_LIBTOOL
# Headers
AC_CHECK_HEADERS([fcntl.h stdlib.h string.h sys/socket.h time.h sys/time.h syslog.h unistd.h cairo/cairo.h pngstruct.h])

# windows build
GENERAL_LDFLAGS=
GENERAL_CFLAGS=-Werror -Wall -pedantic
AC_ARG_WITH([windows],
[AS_HELP_STRING([--with-windows],
[build under/for Windows @<:@default=no@:>@])],
[with_windows=yes], [with_windows=no])

AM_CONDITIONAL([WINDOWS_BUILD], [test "x${with_windows}" = "xyes"])

if test "x$with_windows" = "xyes"
then
GENERAL_LDFLAGS=-no-undefined
GENERAL_CFLAGS=-Werror -Wall -Wno-error=expansion-to-defined
AC_DEFINE([WINDOWS_BUILD],,[Build against windows on Windows])

AC_CHECK_LIB([systre], [regcomp], [SYSTRE_LIBS=-lsystre],
AC_MSG_ERROR("libsystre is required for regex functionality"))
else
SYSTRE_LIBS=
fi

# Source characteristics
AC_DEFINE([_XOPEN_SOURCE], [700], [Uses X/Open and POSIX APIs])
AC_DEFINE([__BSD_VISIBLE], [1], [Uses BSD-specific APIs (if available)])

if test "x$with_windows" = "xno"
then
AC_DEFINE([__BSD_VISIBLE], [1], [Uses BSD-specific APIs (if available)])
fi

# Check for whether math library is required
AC_CHECK_LIB([m], [cos],
Expand All @@ -68,13 +94,17 @@ AC_CHECK_LIB([pthread], [pthread_create], [PTHREAD_LIBS=-lpthread
AC_DEFINE([HAVE_LIBPTHREAD],,
[Whether libpthread was found])])

# Windows provides its own timer API, and does not user timer_create
if test "x$with_windows" = "xno"
then
# librt
AC_CHECK_FUNC([timer_create], [AC_MSG_RESULT([timer_create was found without librt.])],
[AC_CHECK_LIB([rt], [timer_create],
[AC_MSG_RESULT([timer_create was found in librt.])
RT_LIBS=-lrt],
[AC_MSG_ERROR([timer_create could not be found.])])
])
fi

# Include libdl for dlopen() if necessary
AC_CHECK_LIB([dl], [dlopen],
Expand All @@ -84,48 +114,67 @@ AC_CHECK_LIB([dl], [dlopen],
[#include <dlfcn.h>])])

#
# libuuid
# UUID library
# First, check librpcrt4 (Windows), then libuuid, and finally OSSP UUID
#

AC_ARG_WITH([librpcrt4],
[AS_HELP_STRING([--with-librpcrt4],
[use librpcrt4 to generate unique identifiers @<:@default=check@:>@])],
[],
[with_librpcrt4=check])

# First, check for librpcrt4 (Windows)
have_librpcrt4=disabled
if test "x$with_librpcrt4" != "xno"
then
have_librpcrt4=yes
AC_CHECK_LIB([rpcrt4], [UuidCreate],
[UUID_LIBS=-lrpcrt4]
[AC_DEFINE([HAVE_LIBRPCRT4],, [Whether librpcrt4 is available])],
[have_librpcrt4=no])
fi

# Next, look for libuuid
have_libuuid=disabled
AC_ARG_WITH([libuuid],
[AS_HELP_STRING([--with-libuuid],
[use libuuid to generate unique identifiers @<:@default=check@:>@])],
[],
[with_libuuid=check])

if test "x$with_libuuid" != "xno"
if test "x$with_libuuid" != "xno" -a "x$have_librpcrt4" != "xyes"
then
have_libuuid=yes
AC_CHECK_LIB([uuid], [uuid_generate],
[UUID_LIBS=-luuid]
[AC_DEFINE([HAVE_LIBUUID],, [Whether libuuid is available])],
[have_libuuid=no])
[UUID_LIBS=-luuid]
[AC_DEFINE([HAVE_LIBUUID],, [Whether libuuid is available])],
[have_libuuid=no])
fi

# OSSP UUID (if libuuid is unavilable)
if test "x${have_libuuid}" != "xyes"
# OSSP UUID (if librpcrt4 and libuuid are unavilable)
if test "x$have_librpcrt4" != "xyes" -a "x$have_libuuid" != "xyes"
then

AC_CHECK_LIB([ossp-uuid], [uuid_make], [UUID_LIBS=-lossp-uuid],
AC_CHECK_LIB([uuid], [uuid_make], [UUID_LIBS=-luuid],
AC_MSG_ERROR([
--------------------------------------------
Unable to find libuuid or the OSSP UUID library.
Either libuuid (from util-linux) or the OSSP UUID library is required for
guacamole-server to be built.
--------------------------------------------])))
AC_CHECK_LIB([uuid], [uuid_make], [UUID_LIBS=-luuid],
AC_MSG_ERROR([
--------------------------------------------
Unable to find librpcrt4 or libuuid or the OSSP UUID library.
Either librpcrt4 (Windows) or libuuid (from util-linux) or the
OSSP UUID library is required for guacamole-server to be built.
--------------------------------------------])))

# Check for and validate OSSP uuid.h header
AC_CHECK_HEADERS([ossp/uuid.h])
AC_CHECK_DECL([uuid_make],,
AC_MSG_ERROR("No OSSP uuid.h found in include path"),
[#ifdef HAVE_OSSP_UUID_H
#include <ossp/uuid.h>
#else
#include <uuid.h>
#endif
])
AC_MSG_ERROR("No OSSP uuid.h found in include path"),
[#ifdef HAVE_OSSP_UUID_H
#include <ossp/uuid.h>
#else
#include <uuid.h>
#endif
])
fi

# cunit
Expand All @@ -140,6 +189,9 @@ AC_SUBST(RT_LIBS)
AC_SUBST(PTHREAD_LIBS)
AC_SUBST(UUID_LIBS)
AC_SUBST(CUNIT_LIBS)
AC_SUBST(GENERAL_LDFLAGS)
AC_SUBST(GENERAL_CFLAGS)
AC_SUBST(SYSTRE_LIBS)

# Library functions
AC_CHECK_FUNCS([clock_gettime gettimeofday memmove memset select strdup nanosleep])
Expand Down Expand Up @@ -366,6 +418,7 @@ AC_SUBST(SSL_LIBS)

have_winsock=disabled
WINSOCK_LIBS=

AC_ARG_WITH([winsock],
[AS_HELP_STRING([--with-winsock],
[support Windows Sockets API @<:@default=check@:>@])],
Expand All @@ -376,10 +429,10 @@ if test "x$with_winsock" != "xno"
then
have_winsock=yes
AC_CHECK_LIB([wsock32], [main],
[WINSOCK_LIBS="-lwsock32"]
[AC_DEFINE([ENABLE_WINSOCK],,
[WINSOCK_LIBS="-lwsock32"]
[AC_DEFINE([ENABLE_WINSOCK],,
[Whether Windows Socket API support is enabled])],
[have_winsock=no])
[have_winsock=no])
fi

AM_CONDITIONAL([ENABLE_WINSOCK], [test "x${have_winsock}" = "xyes"])
Expand Down Expand Up @@ -522,7 +575,7 @@ then

# Whether libvncserver was built against libgcrypt
AC_CHECK_DECL([LIBVNCSERVER_WITH_CLIENT_GCRYPT],
[AC_CHECK_HEADER(gcrypt.h,,
[AC_CHECK_HEADER(gcrypt.h, [VNC_LIBS="$VNC_LIBS -lgcrypt"],
[AC_MSG_WARN([
--------------------------------------------
libvncserver appears to be built against
Expand Down Expand Up @@ -671,7 +724,7 @@ if test "x$with_rdp" != "xno"
then
have_freerdp2=yes
PKG_CHECK_MODULES([RDP], [freerdp2 freerdp-client2 winpr2],
[CPPFLAGS="${RDP_CFLAGS} -Werror $CPPFLAGS"]
[CPPFLAGS="${RDP_CFLAGS} -Werror -Wexpansion-to-defined $CPPFLAGS"]
[AS_IF([test "x${FREERDP2_PLUGIN_DIR}" = "x"],
[FREERDP2_PLUGIN_DIR="`$PKG_CONFIG --variable=libdir freerdp2`/freerdp2"])],
[AC_MSG_WARN([
Expand Down Expand Up @@ -949,7 +1002,7 @@ then
# Whether libssh2 was built against libgcrypt
AC_CHECK_LIB([ssh2], [gcry_control],
[AC_CHECK_HEADER(gcrypt.h,
[AC_DEFINE([LIBSSH2_USES_GCRYPT],,
[AC_DEFINE([LIBSSH2_USES_GCRYPT],[SSH_LIBS="$SSH_LIBS -lgcrypt"],
[Whether libssh2 was built against libgcrypt])],
[AC_MSG_WARN([
--------------------------------------------
Expand Down Expand Up @@ -1196,6 +1249,7 @@ AC_CONFIG_FILES([Makefile
src/protocols/kubernetes/Makefile
src/protocols/kubernetes/tests/Makefile
src/protocols/rdp/Makefile
src/protocols/rdp/guacxpstopdf/Makefile
src/protocols/rdp/tests/Makefile
src/protocols/ssh/Makefile
src/protocols/telnet/Makefile
Expand Down
5 changes: 3 additions & 2 deletions src/common-ssh/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ noinst_HEADERS = \
common-ssh/user.h

libguac_common_ssh_la_CFLAGS = \
-Werror -Wall -pedantic \
@GENERAL_CFLAGS@ \
@COMMON_INCLUDE@ \
@LIBGUAC_INCLUDE@

Expand All @@ -54,5 +54,6 @@ libguac_common_ssh_la_LIBADD = \
libguac_common_ssh_la_LDFLAGS = \
@PTHREAD_LIBS@ \
@SSH_LIBS@ \
@SSL_LIBS@
@SSL_LIBS@ \
@GENERAL_LDFLAGS@

14 changes: 10 additions & 4 deletions src/common-ssh/ssh.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,22 @@
#include <openssl/ssl.h>

#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include <pthread.h>
#include <pwd.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

#ifdef WINDOWS_BUILD
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <netdb.h>
#include <netinet/in.h>
#include <pwd.h>
#include <sys/socket.h>
#endif

#ifdef LIBSSH2_USES_GCRYPT
GCRY_THREAD_OPTION_PTHREAD_IMPL;
#endif
Expand Down
2 changes: 1 addition & 1 deletion src/common-ssh/tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ test_common_ssh_SOURCES = \
sftp/normalize_path.c

test_common_ssh_CFLAGS = \
-Werror -Wall -pedantic \
@GENERAL_CFLAGS@ \
@COMMON_INCLUDE@ \
@COMMON_SSH_INCLUDE@ \
@LIBGUAC_INCLUDE@
Expand Down
2 changes: 1 addition & 1 deletion src/common/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ libguac_common_la_SOURCES = \
surface.c

libguac_common_la_CFLAGS = \
-Werror -Wall -pedantic \
@GENERAL_CFLAGS@ \
@LIBGUAC_INCLUDE@

libguac_common_la_LIBADD = \
Expand Down
Loading

0 comments on commit e1dfde0

Please sign in to comment.