diff options
Diffstat (limited to 'cmake')
-rw-r--r-- | cmake/cmake.h.in | 60 | ||||
-rw-r--r-- | cmake/gitcommit.cmake | 63 | ||||
-rw-r--r-- | cmake/gtk.cmake | 89 | ||||
-rw-r--r-- | cmake/licence.cmake | 39 | ||||
-rw-r--r-- | cmake/platforms/unix.cmake | 234 | ||||
-rw-r--r-- | cmake/platforms/windows.cmake | 202 | ||||
-rw-r--r-- | cmake/setup.cmake | 113 | ||||
-rw-r--r-- | cmake/toolchain-mingw.cmake | 12 | ||||
-rw-r--r-- | cmake/toolchain-winegcc.cmake | 33 | ||||
-rwxr-xr-x | cmake/winegcc | 29 |
10 files changed, 874 insertions, 0 deletions
diff --git a/cmake/cmake.h.in b/cmake/cmake.h.in new file mode 100644 index 00000000..5ad32515 --- /dev/null +++ b/cmake/cmake.h.in @@ -0,0 +1,60 @@ +#cmakedefine NO_IPV6 +#cmakedefine NO_GSSAPI +#cmakedefine STATIC_GSSAPI + +#cmakedefine NO_MULTIMON + +#cmakedefine01 HAVE_WINRESRC_H +#cmakedefine01 HAVE_WINRES_H +#cmakedefine01 HAVE_WIN_H +#cmakedefine01 HAVE_NO_STDINT_H +#cmakedefine01 HAVE_AFUNIX_H +#cmakedefine01 HAVE_GCP_RESULTSW +#cmakedefine01 HAVE_ADDDLLDIRECTORY +#cmakedefine01 HAVE_GETNAMEDPIPECLIENTPROCESSID +#cmakedefine01 HAVE_SETDEFAULTDLLDIRECTORIES +#cmakedefine01 HAVE_STRTOUMAX +#cmakedefine01 HAVE_DWMAPI_H + +#cmakedefine NOT_X_WINDOWS +#cmakedefine OMIT_UTMP + +#cmakedefine01 HAVE_ASM_HWCAP_H +#cmakedefine01 HAVE_SYS_AUXV_H +#cmakedefine01 HAVE_SYS_SYSCTL_H +#cmakedefine01 HAVE_SYS_TYPES_H +#cmakedefine01 HAVE_GLOB_H +#cmakedefine01 HAVE_UTMP_H +#cmakedefine01 HAVE_FUTIMES +#cmakedefine01 HAVE_GETADDRINFO +#cmakedefine01 HAVE_POSIX_OPENPT +#cmakedefine01 HAVE_PTSNAME +#cmakedefine01 HAVE_SETRESUID +#cmakedefine01 HAVE_SETRESGID +#cmakedefine01 HAVE_STRSIGNAL +#cmakedefine01 HAVE_UPDWTMPX +#cmakedefine01 HAVE_FSTATAT +#cmakedefine01 HAVE_DIRFD +#cmakedefine01 HAVE_SETPWENT +#cmakedefine01 HAVE_ENDPWENT +#cmakedefine01 HAVE_GETAUXVAL +#cmakedefine01 HAVE_ELF_AUX_INFO +#cmakedefine01 HAVE_SYSCTLBYNAME +#cmakedefine01 HAVE_CLOCK_MONOTONIC +#cmakedefine01 HAVE_CLOCK_GETTIME +#cmakedefine01 HAVE_SO_PEERCRED +#cmakedefine01 HAVE_NULLARY_SETPGRP +#cmakedefine01 HAVE_BINARY_SETPGRP +#cmakedefine01 HAVE_PANGO_FONT_FAMILY_IS_MONOSPACE +#cmakedefine01 HAVE_PANGO_FONT_MAP_LIST_FAMILIES + +#cmakedefine01 HAVE_AES_NI +#cmakedefine01 HAVE_SHA_NI +#cmakedefine01 HAVE_SHAINTRIN_H +#cmakedefine01 HAVE_CLMUL +#cmakedefine01 HAVE_NEON_CRYPTO +#cmakedefine01 HAVE_NEON_PMULL +#cmakedefine01 HAVE_NEON_VADDQ_P128 +#cmakedefine01 HAVE_NEON_SHA512 +#cmakedefine01 HAVE_NEON_SHA512_INTRINSICS +#cmakedefine01 USE_ARM64_NEON_H diff --git a/cmake/gitcommit.cmake b/cmake/gitcommit.cmake new file mode 100644 index 00000000..0aa8a095 --- /dev/null +++ b/cmake/gitcommit.cmake @@ -0,0 +1,63 @@ +# Pure cmake script to write out cmake_commit.c and cmake_version.but + +set(DEFAULT_COMMIT "unavailable") +set(commit "${DEFAULT_COMMIT}") + +set(TOPLEVEL_SOURCE_DIR ${CMAKE_SOURCE_DIR}) + +execute_process( + COMMAND ${GIT_EXECUTABLE} rev-parse --show-toplevel + OUTPUT_VARIABLE git_worktree + ERROR_VARIABLE stderr + RESULT_VARIABLE status) +string(REGEX REPLACE "\n$" "" git_worktree "${git_worktree}") + +if(status EQUAL 0) + if(git_worktree STREQUAL CMAKE_SOURCE_DIR) + execute_process( + COMMAND ${GIT_EXECUTABLE} rev-parse HEAD + OUTPUT_VARIABLE git_commit + ERROR_VARIABLE stderr + RESULT_VARIABLE status) + if(status EQUAL 0) + string(REGEX REPLACE "\n$" "" commit "${git_commit}") + else() + if(commit STREQUAL "unavailable") + message("Unable to determine git commit: 'git rev-parse HEAD' returned status ${status} and error output:\n${stderr}\n") + endif() + endif() + else() + if(commit STREQUAL "unavailable") + message("Unable to determine git commit: top-level source dir ${CMAKE_SOURCE_DIR} is not the root of a repository") + endif() + endif() +else() + if(commit STREQUAL "unavailable") + message("Unable to determine git commit: 'git rev-parse --show-toplevel' returned status ${status} and error output:\n${stderr}\n") + endif() +endif() + +if(OUTPUT_TYPE STREQUAL header) + file(WRITE "${OUTPUT_FILE}" "\ +/* + * cmake_commit.c - string literal giving the source git commit, if known. + * + * Generated by cmake/gitcommit.cmake. + */ + +#include \"putty.h\" +const char commitid[] = \"${commit}\"; +") +elseif(OUTPUT_TYPE STREQUAL halibut) + if(commit STREQUAL "unavailable") + file(WRITE "${OUTPUT_FILE}" "\ +\\versionid no version information available +") + else() + file(WRITE "${OUTPUT_FILE}" "\ +\\versionid built from git commit ${commit} +") + endif() +else() + message(FATAL_ERROR "Set OUTPUT_TYPE when running this script") +endif() diff --git a/cmake/gtk.cmake b/cmake/gtk.cmake new file mode 100644 index 00000000..13ff7705 --- /dev/null +++ b/cmake/gtk.cmake @@ -0,0 +1,89 @@ +# Look for GTK, of any version. + +set(PUTTY_GTK_VERSION "ANY" + CACHE STRING "Which major version of GTK to build with") +set_property(CACHE PUTTY_GTK_VERSION + PROPERTY STRINGS ANY 3 2 1 NONE) + +set(GTK_FOUND FALSE) + +macro(try_pkg_config_gtk VER PACKAGENAME) + if(NOT GTK_FOUND AND + (PUTTY_GTK_VERSION STREQUAL ANY OR PUTTY_GTK_VERSION STREQUAL ${VER})) + find_package(PkgConfig) + pkg_check_modules(GTK ${PACKAGENAME}) + if(GTK_FOUND) + set(GTK_VERSION ${VER}) + endif() + endif() +endmacro() +try_pkg_config_gtk(3 gtk+-3.0) +try_pkg_config_gtk(2 gtk+-2.0) + +if(NOT GTK_FOUND AND + (PUTTY_GTK_VERSION STREQUAL ANY OR PUTTY_GTK_VERSION STREQUAL 1)) + message("-- Checking for GTK1 (via gtk-config)") + find_program(GTK_CONFIG gtk-config) + if(GTK_CONFIG) + execute_process(COMMAND ${GTK_CONFIG} --cflags + OUTPUT_VARIABLE gtk_config_cflags + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE gtk_config_cflags_result) + execute_process(COMMAND ${GTK_CONFIG} --libs + OUTPUT_VARIABLE gtk_config_libs + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE gtk_config_libs_result) + + if(gtk_config_cflags_result EQUAL 0 AND gtk_config_libs_result EQUAL 0) + + set(GTK_INCLUDE_DIRS) + set(GTK_LIBRARY_DIRS) + set(GTK_LIBRARIES) + + separate_arguments(gtk_config_cflags NATIVE_COMMAND + ${gtk_config_cflags}) + foreach(opt ${gtk_config_cflags}) + string(REGEX MATCH "^-I" ok ${opt}) + if(ok) + string(REGEX REPLACE "^-I" "" optval ${opt}) + list(APPEND GTK_INCLUDE_DIRS ${optval}) + endif() + endforeach() + + separate_arguments(gtk_config_libs NATIVE_COMMAND + ${gtk_config_libs}) + foreach(opt ${gtk_config_libs}) + string(REGEX MATCH "^-l" ok ${opt}) + if(ok) + list(APPEND GTK_LIBRARIES ${opt}) + endif() + string(REGEX MATCH "^-L" ok ${opt}) + if(ok) + string(REGEX REPLACE "^-L" "" optval ${opt}) + list(APPEND GTK_LIBRARY_DIRS ${optval}) + endif() + endforeach() + + message("-- Found GTK1") + set(GTK_FOUND TRUE) + endif() + endif() +endif() + +if(GTK_FOUND) + # Check for some particular Pango functions. + function(pango_check_subscope) + set(CMAKE_REQUIRED_INCLUDES ${GTK_INCLUDE_DIRS}) + set(CMAKE_REQUIRED_LINK_OPTIONS ${GTK_LDFLAGS}) + set(CMAKE_REQUIRED_LIBRARIES ${GTK_LIBRARIES}) + check_symbol_exists(pango_font_family_is_monospace "pango/pango.h" + HAVE_PANGO_FONT_FAMILY_IS_MONOSPACE) + check_symbol_exists(pango_font_map_list_families "pango/pango.h" + HAVE_PANGO_FONT_MAP_LIST_FAMILIES) + set(HAVE_PANGO_FONT_FAMILY_IS_MONOSPACE + ${HAVE_PANGO_FONT_FAMILY_IS_MONOSPACE} PARENT_SCOPE) + set(HAVE_PANGO_FONT_MAP_LIST_FAMILIES + ${HAVE_PANGO_FONT_MAP_LIST_FAMILIES} PARENT_SCOPE) + endfunction() + pango_check_subscope() +endif() diff --git a/cmake/licence.cmake b/cmake/licence.cmake new file mode 100644 index 00000000..e356ae93 --- /dev/null +++ b/cmake/licence.cmake @@ -0,0 +1,39 @@ +# Pure cmake script to generate licence.h from LICENCE + +file(READ "${LICENCE_FILE}" LICENCE_TEXT) + +function(c_string_escape outvar value) + string(REPLACE "\\" "\\\\" value "${value}") + string(REPLACE "\"" "\\\"" value "${value}") + set("${outvar}" "${value}" PARENT_SCOPE) +endfunction() + +set(copyright_regex "PuTTY is copyright ([0-9]+-[0-9]+ [^\n]*[^\n.])\\.?\n") +string(REGEX MATCH "${copyright_regex}" COPYRIGHT_NOTICE "${LICENCE_TEXT}") +string(REGEX REPLACE "${copyright_regex}" "\\1" + COPYRIGHT_NOTICE "${COPYRIGHT_NOTICE}") +c_string_escape(COPYRIGHT_NOTICE "${COPYRIGHT_NOTICE}") + +string(REGEX REPLACE "\n$" "" LICENCE_TEXT "${LICENCE_TEXT}") +string(REPLACE "\r" "" LICENCE_TEXT "${LICENCE_TEXT}") +string(REPLACE "\n\n" "\r" LICENCE_TEXT "${LICENCE_TEXT}") +string(REPLACE "\n" " " LICENCE_TEXT "${LICENCE_TEXT}") +string(REPLACE "\r" "\n" LICENCE_TEXT "${LICENCE_TEXT}") + +c_string_escape(LICENCE_TEXT "${LICENCE_TEXT}") +string(REPLACE "\n" "\" \\\n parsep \\\n \"" + LICENCE_TEXT "${LICENCE_TEXT}") + +file(WRITE "${OUTPUT_FILE}" "\ +/* + * licence.h - macro definitions for the PuTTY licence. + * + * Generated by cmake/licence.cmake from ./LICENCE. + * You should edit those files rather than editing this one. + */ + +#define LICENCE_TEXT(parsep) \\ + \"${LICENCE_TEXT}\" + +#define SHORT_COPYRIGHT_DETAILS \"${COPYRIGHT_NOTICE}\" +") diff --git a/cmake/platforms/unix.cmake b/cmake/platforms/unix.cmake new file mode 100644 index 00000000..4d056d0a --- /dev/null +++ b/cmake/platforms/unix.cmake @@ -0,0 +1,234 @@ +set(PUTTY_GSSAPI DYNAMIC + CACHE STRING "Build PuTTY with dynamically or statically linked \ +Kerberos / GSSAPI support, if possible") +set_property(CACHE PUTTY_GSSAPI + PROPERTY STRINGS DYNAMIC STATIC OFF) + +include(CheckIncludeFile) +include(CheckLibraryExists) +include(CheckSymbolExists) +include(CheckCSourceCompiles) +include(GNUInstallDirs) + +set(CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} + -D_DEFAULT_SOURCE -D_GNU_SOURCE) + +check_include_file(sys/auxv.h HAVE_SYS_AUXV_H) +check_include_file(asm/hwcap.h HAVE_ASM_HWCAP_H) +check_include_file(sys/sysctl.h HAVE_SYS_SYSCTL_H) +check_include_file(sys/types.h HAVE_SYS_TYPES_H) +check_include_file(glob.h HAVE_GLOB_H) +check_include_file(utmp.h HAVE_UTMP_H) +check_include_file(utmpx.h HAVE_UTMPX_H) + +check_symbol_exists(futimes "sys/time.h" HAVE_FUTIMES) +check_symbol_exists(getaddrinfo "sys/types.h;sys/socket.h;netdb.h" + HAVE_GETADDRINFO) +check_symbol_exists(posix_openpt "stdlib.h;fcntl.h" HAVE_POSIX_OPENPT) +check_symbol_exists(ptsname "stdlib.h" HAVE_PTSNAME) +check_symbol_exists(setresuid "unistd.h" HAVE_SETRESUID) +check_symbol_exists(setresgid "unistd.h" HAVE_SETRESGID) +check_symbol_exists(strsignal "string.h" HAVE_STRSIGNAL) +check_symbol_exists(updwtmpx "utmpx.h" HAVE_UPDWTMPX) +check_symbol_exists(fstatat "sys/types.h;sys/stat.h;unistd.h" HAVE_FSTATAT) +check_symbol_exists(dirfd "sys/types.h;dirent.h" HAVE_DIRFD) +check_symbol_exists(setpwent "sys/types.h;pwd.h" HAVE_SETPWENT) +check_symbol_exists(endpwent "sys/types.h;pwd.h" HAVE_ENDPWENT) +check_symbol_exists(getauxval "sys/auxv.h" HAVE_GETAUXVAL) +check_symbol_exists(elf_aux_info "sys/auxv.h" HAVE_ELF_AUX_INFO) +check_symbol_exists(sysctlbyname "sys/types.h;sys/sysctl.h" HAVE_SYSCTLBYNAME) +check_symbol_exists(CLOCK_MONOTONIC "time.h" HAVE_CLOCK_MONOTONIC) +check_symbol_exists(clock_gettime "time.h" HAVE_CLOCK_GETTIME) + +check_c_source_compiles(" +#define _GNU_SOURCE +#include <features.h> +#include <sys/socket.h> +int main(int argc, char **argv) { + struct ucred cr; + socklen_t crlen = sizeof(cr); + return getsockopt(0, SOL_SOCKET, SO_PEERCRED, &cr, &crlen) + + cr.pid + cr.uid + cr.gid; +}" HAVE_SO_PEERCRED) + +check_c_source_compiles(" +#include <sys/types.h> +#include <unistd.h> + +int main(int argc, char **argv) { + setpgrp(); +}" HAVE_NULLARY_SETPGRP) +check_c_source_compiles(" +#include <sys/types.h> +#include <unistd.h> + +int main(int argc, char **argv) { + setpgrp(0, 0); +}" HAVE_BINARY_SETPGRP) + +if(HAVE_GETADDRINFO AND PUTTY_IPV6) + set(NO_IPV6 OFF) +else() + set(NO_IPV6 ON) +endif() + +if(HAVE_UTMPX_H) + set(OMIT_UTMP OFF) +else() + set(OMIT_UTMP ON) +endif() + +include(cmake/gtk.cmake) + +if(GTK_FOUND) + # See if we have X11 available. This requires libX11 itself, and also + # the GDK integration to X11. + find_package(X11) + + function(check_x11) + list(APPEND CMAKE_REQUIRED_INCLUDES ${GTK_INCLUDE_DIRS}) + check_include_file(gdk/gdkx.h HAVE_GDK_GDKX_H) + + if(X11_FOUND AND HAVE_GDK_GDKX_H) + set(NOT_X_WINDOWS OFF PARENT_SCOPE) + else() + set(NOT_X_WINDOWS ON PARENT_SCOPE) + endif() + endfunction() + check_x11() +else() + # If we didn't even have GTK, behave as if X11 is not available. + # (There's nothing useful we could do with it even if there was.) + set(NOT_X_WINDOWS ON) +endif() + +include_directories(${CMAKE_SOURCE_DIR}/charset ${GTK_INCLUDE_DIRS} ${X11_INCLUDE_DIR}) +link_directories(${GTK_LIBRARY_DIRS}) + +function(add_optional_system_lib library testfn) + check_library_exists(${library} ${testfn} "" HAVE_LIB${library}) + if (HAVE_LIB${library}) + set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES};-l${library}) + link_libraries(-l${library}) + endif() +endfunction() + +add_optional_system_lib(m pow) +add_optional_system_lib(rt clock_gettime) +add_optional_system_lib(xnet socket) + +set(extra_dirs charset) + +if(PUTTY_GSSAPI STREQUAL DYNAMIC) + add_optional_system_lib(dl dlopen) + if(HAVE_NO_LIBdl) + message(WARNING + "Could not find libdl -- cannot provide dynamic GSSAPI support") + set(NO_GSSAPI ON) + endif() +endif() + +if(PUTTY_GSSAPI STREQUAL STATIC) + set(KRB5_CFLAGS) + set(KRB5_LDFLAGS) + + # First try using pkg-config + find_package(PkgConfig) + pkg_check_modules(KRB5 krb5-gssapi) + + # Failing that, try the dedicated krb5-config + if(NOT KRB5_FOUND) + find_program(KRB5_CONFIG krb5-config) + if(KRB5_CONFIG) + execute_process(COMMAND ${KRB5_CONFIG} --cflags gssapi + OUTPUT_VARIABLE krb5_config_cflags + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE krb5_config_cflags_result) + execute_process(COMMAND ${KRB5_CONFIG} --libs gssapi + OUTPUT_VARIABLE krb5_config_libs + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE krb5_config_libs_result) + + if(krb5_config_cflags_result EQUAL 0 AND krb5_config_libs_result EQUAL 0) + set(KRB5_INCLUDE_DIRS) + set(KRB5_LIBRARY_DIRS) + set(KRB5_LIBRARIES) + + # We can safely put krb5-config's cflags directly into cmake's + # cflags, without bothering to extract the include directories. + set(KRB5_CFLAGS ${krb5_config_cflags}) + + # But krb5-config --libs isn't so simple. It will actually + # deliver a mix of libraries and other linker options. We have + # to separate them for cmake purposes, because if we pass the + # whole lot to add_link_options then they'll appear too early + # in the command line (so that by the time our own code refers + # to GSSAPI functions it'll be too late to search these + # libraries for them), and if we pass the whole lot to + # link_libraries then it'll get confused about options that + # aren't libraries. + separate_arguments(krb5_config_libs NATIVE_COMMAND + ${krb5_config_libs}) + foreach(opt ${krb5_config_libs}) + string(REGEX MATCH "^-l" ok ${opt}) + if(ok) + list(APPEND KRB5_LIBRARIES ${opt}) + continue() + endif() + string(REGEX MATCH "^-L" ok ${opt}) + if(ok) + string(REGEX REPLACE "^-L" "" optval ${opt}) + list(APPEND KRB5_LIBRARY_DIRS ${optval}) + continue() + endif() + list(APPEND KRB5_LDFLAGS ${opt}) + endforeach() + + message(STATUS "Found Kerberos via krb5-config") + set(KRB5_FOUND YES) + endif() + endif() + endif() + + if(KRB5_FOUND) + include_directories(${KRB5_INCLUDE_DIRS}) + link_directories(${KRB5_LIBRARY_DIRS}) + link_libraries(${KRB5_LIBRARIES}) + add_compile_options(${KRB5_CFLAGS}) + add_link_options(${KRB5_LDFLAGS}) + set(STATIC_GSSAPI ON) + else() + message(WARNING + "Could not find krb5 via pkg-config or krb5-config -- \ +cannot provide static GSSAPI support") + set(NO_GSSAPI ON) + endif() +endif() + +if(PUTTY_GSSAPI STREQUAL OFF) + set(NO_GSSAPI ON) +endif() + +if(STRICT AND (CMAKE_C_COMPILER_ID MATCHES "GNU" OR + CMAKE_C_COMPILER_ID MATCHES "Clang")) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror -Wpointer-arith -Wvla") +endif() + +function(installed_program target) + if(CMAKE_VERSION VERSION_LESS 3.14) + # CMake 3.13 and earlier required an explicit install destination. + install(TARGETS ${target} RUNTIME DESTINATION bin) + else() + # 3.14 and above selects a sensible default, which we should avoid + # overriding here so that end users can override it using + # CMAKE_INSTALL_BINDIR. + install(TARGETS ${target}) + endif() + + if(HAVE_MANPAGE_${target}_1) + install(FILES ${CMAKE_BINARY_DIR}/doc/${target}.1 + DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) + else() + message(WARNING "Could not build man page ${target}.1") + endif() +endfunction() diff --git a/cmake/platforms/windows.cmake b/cmake/platforms/windows.cmake new file mode 100644 index 00000000..a7ed7c7c --- /dev/null +++ b/cmake/platforms/windows.cmake @@ -0,0 +1,202 @@ +set(PUTTY_MINEFIELD OFF + CACHE BOOL "Build PuTTY with its built-in memory debugger 'Minefield'") +set(PUTTY_GSSAPI ON + CACHE BOOL "Build PuTTY with GSSAPI support") +set(PUTTY_LINK_MAPS OFF + CACHE BOOL "Attempt to generate link maps") +set(PUTTY_EMBEDDED_CHM_FILE "" + CACHE FILEPATH "Path to a .chm help file to embed in the binaries") + +if(PUTTY_SUBSYSTEM_VERSION) + string(REPLACE + "subsystem:windows" "subsystem:windows,${PUTTY_SUBSYSTEM_VERSION}" + CMAKE_C_CREATE_WIN32_EXE ${CMAKE_C_CREATE_WIN32_EXE}) + string(REPLACE + "subsystem:console" "subsystem:console,${PUTTY_SUBSYSTEM_VERSION}" + CMAKE_C_CREATE_CONSOLE_EXE ${CMAKE_C_CREATE_CONSOLE_EXE}) +endif() + +function(define_negation newvar oldvar) + if(${oldvar}) + set(${newvar} OFF PARENT_SCOPE) + else() + set(${newvar} ON PARENT_SCOPE) + endif() +endfunction() + +include(CheckIncludeFiles) +include(CheckSymbolExists) +include(CheckCSourceCompiles) + +# Still needed for AArch32 Windows builds +set(CMAKE_REQUIRED_DEFINITIONS -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE) + +check_include_files("windows.h;winresrc.h" HAVE_WINRESRC_H) +if(NOT HAVE_WINRESRC_H) + # A couple of fallback names for the header file you can include in + # .rc files. We conditionalise even these checks, to save effort at + # cmake time. + check_include_files("windows.h;winres.h" HAVE_WINRES_H) + if(NOT HAVE_WINRES_H) + check_include_files("windows.h;win.h" HAVE_WIN_H) + endif() +endif() +check_include_files("stdint.h" HAVE_STDINT_H) +define_negation(HAVE_NO_STDINT_H HAVE_STDINT_H) + +check_include_files("windows.h;multimon.h" HAVE_MULTIMON_H) +define_negation(NO_MULTIMON HAVE_MULTIMON_H) + +check_include_files("windows.h;htmlhelp.h" HAVE_HTMLHELP_H) +define_negation(NO_HTMLHELP HAVE_HTMLHELP_H) + +check_include_files("winsock2.h;afunix.h" HAVE_AFUNIX_H) + +check_symbol_exists(strtoumax "inttypes.h" HAVE_STRTOUMAX) +check_symbol_exists(AddDllDirectory "windows.h" HAVE_ADDDLLDIRECTORY) +check_symbol_exists(SetDefaultDllDirectories "windows.h" + HAVE_SETDEFAULTDLLDIRECTORIES) +check_symbol_exists(GetNamedPipeClientProcessId "windows.h" + HAVE_GETNAMEDPIPECLIENTPROCESSID) +check_symbol_exists(CreatePseudoConsole "windows.h" HAVE_CONPTY) + +check_c_source_compiles(" +#include <windows.h> +GCP_RESULTSW gcpw; +int main(void) { return 0; } +" HAVE_GCP_RESULTSW) + +function(dwmapi_test_wrapper) + set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} dwmapi.lib) + check_c_source_compiles(" +#include <windows.h> +#include <dwmapi.h> +volatile HWND hwnd; +int main(void) { + RECT r; + DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &r, sizeof(r)); +} +" HAVE_DWMAPI_H) + set(HAVE_DWMAPI_H ${HAVE_DWMAPI_H} PARENT_SCOPE) +endfunction() +dwmapi_test_wrapper() + +set(NO_SECURITY ${PUTTY_NO_SECURITY}) + +add_compile_definitions( + _WINDOWS + _CRT_SECURE_NO_WARNINGS + _WINSOCK_DEPRECATED_NO_WARNINGS + _ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE) + +if(PUTTY_MINEFIELD) + add_compile_definitions(MINEFIELD) +endif() +if(NOT PUTTY_GSSAPI) + add_compile_definitions(NO_GSSAPI) +endif() +if(PUTTY_EMBEDDED_CHM_FILE) + add_compile_definitions("EMBEDDED_CHM_FILE=\"${PUTTY_EMBEDDED_CHM_FILE}\"") +endif() + +if(WINELIB) + enable_language(RC) + set(LFLAG_MANIFEST_NO "") +elseif(CMAKE_C_COMPILER_ID MATCHES "MSVC" OR + CMAKE_C_COMPILER_FRONTEND_VARIANT MATCHES "MSVC") + set(CMAKE_RC_FLAGS "${CMAKE_RC_FLAGS} /nologo /C1252") + set(LFLAG_MANIFEST_NO "/manifest:no") +else() + set(CMAKE_RC_FLAGS "${CMAKE_RC_FLAGS} -c1252") + set(LFLAG_MANIFEST_NO "") +endif() + +if(STRICT) + if(CMAKE_C_COMPILER_ID MATCHES "GNU") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror -Wpointer-arith -Wvla") + elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -Wpointer-arith -Wvla") + endif() +endif() + +if(CMAKE_C_COMPILER_ID MATCHES "Clang") + # Switch back from MSVC-style error message format + # "file.c(line,col)" to clang's native style "file.c:line:col:". I + # find the latter more convenient because it matches other Unixy + # tools like grep, and I have tooling to parse that format and jump + # to the sites of error messages. + set(CMAKE_C_FLAGS + "${CMAKE_C_FLAGS} -Xclang -fdiagnostics-format -Xclang clang") +endif() + +if(CMAKE_C_COMPILER_ID MATCHES "MSVC") + # Turn off some warnings that I've just found too noisy. + # + # - 4244, 4267: "possible loss of data" when narrowing an integer + # type (separate warning numbers for initialisers and + # assignments). Every time I spot-check instances of this, they + # turn out to be sensible (e.g. something was already checked, or + # was assigned from a previous variable that must have been in + # range). I don't think putting a warning-suppression idiom at + # every one of these sites would improve code legibility. + # + # - 4018: "signed/unsigned mismatch" in integer comparison. Again, + # comes up a lot, and generally my spot checks make it look as if + # it's OK. + # + # - 4146: applying unary '-' to an unsigned type. We do that all + # the time in deliberate bit-twiddling code like mpint.c or + # crypto implementations. + # + # - 4293: warning about undefined behaviour if a shift count is too + # big. We often do this inside a ?: clause which doesn't evaluate + # the overlong shift unless the shift count _isn't_ too big. When + # the shift count is constant, MSVC spots the potential problem + # in one branch of the ?:, but doesn't also spot that that branch + # isn't ever taken, so it complains about a thing that's already + # guarded. + # + # - 4090: different 'const' qualifiers. It's a shame to suppress + # this one, because const mismatches really are a thing I'd + # normally like to be warned about. But MSVC (as of 2017 at + # least) seems to have a bug in which assigning a 'void *' into a + # 'const char **' thinks there's a const-qualifier mismatch. + # There isn't! Both are pointers to modifiable objects. The fact + # that in one case, the modifiable object is a pointer to + # something _else_ const should make no difference. + + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} \ +/wd4244 /wd4267 /wd4018 /wd4146 /wd4293 /wd4090") +endif() + +if(CMAKE_C_COMPILER_FRONTEND_VARIANT MATCHES "MSVC") + set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} /dynamicbase /nxcompat") +endif() + +set(platform_libraries + advapi32.lib comdlg32.lib gdi32.lib imm32.lib + ole32.lib shell32.lib user32.lib ws2_32.lib kernel32.lib) + +# Generate link maps +if(PUTTY_LINK_MAPS) + if(CMAKE_C_COMPILER_ID MATCHES "Clang" AND + "x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC") + set(CMAKE_C_LINK_EXECUTABLE + "${CMAKE_C_LINK_EXECUTABLE} /lldmap:<TARGET>.map") + elseif(CMAKE_C_COMPILER_ID MATCHES "MSVC") + set(CMAKE_C_LINK_EXECUTABLE + "${CMAKE_C_LINK_EXECUTABLE} /map:<TARGET>.map") + else() + message(WARNING + "Don't know how to generate link maps on this toolchain") + endif() +endif() + +# Write out a file in the cmake output directory listing the +# executables that are 'official' enough to want to code-sign and +# ship. +file(WRITE ${CMAKE_BINARY_DIR}/shipped.txt "") +function(installed_program target) + file(APPEND ${CMAKE_BINARY_DIR}/shipped.txt + "${target}${CMAKE_EXECUTABLE_SUFFIX}\n") +endfunction() diff --git a/cmake/setup.cmake b/cmake/setup.cmake new file mode 100644 index 00000000..7a650771 --- /dev/null +++ b/cmake/setup.cmake @@ -0,0 +1,113 @@ +# Forcibly re-enable assertions, even if we're building in release +# mode. This is a security project - assertions may be enforcing +# security-critical constraints. A backstop #ifdef in defs.h should +# give a #error if this manoeuvre doesn't do what it needs to. +string(REPLACE "/DNDEBUG" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") +string(REPLACE "-DNDEBUG" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") +string(REPLACE "/DNDEBUG" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") +string(REPLACE "-DNDEBUG" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") + +set(PUTTY_IPV6 ON + CACHE BOOL "Build PuTTY with IPv6 support if possible") +set(PUTTY_DEBUG OFF + CACHE BOOL "Build PuTTY with debug() statements enabled") +set(PUTTY_FUZZING OFF + CACHE BOOL "Build PuTTY binaries suitable for fuzzing, NOT FOR REAL USE") +set(PUTTY_COVERAGE OFF + CACHE BOOL "Build PuTTY binaries suitable for code coverage analysis") + +set(STRICT OFF + CACHE BOOL "Enable extra compiler warnings and make them errors") + +include(FindGit) + +set(GENERATED_SOURCES_DIR ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}) + +set(GENERATED_LICENCE_H ${GENERATED_SOURCES_DIR}/licence.h) +set(INTERMEDIATE_LICENCE_H ${GENERATED_LICENCE_H}.tmp) +add_custom_command(OUTPUT ${INTERMEDIATE_LICENCE_H} + COMMAND ${CMAKE_COMMAND} + -DLICENCE_FILE=${CMAKE_SOURCE_DIR}/LICENCE + -DOUTPUT_FILE=${INTERMEDIATE_LICENCE_H} + -P ${CMAKE_SOURCE_DIR}/cmake/licence.cmake + DEPENDS ${CMAKE_SOURCE_DIR}/cmake/licence.cmake ${CMAKE_SOURCE_DIR}/LICENCE) +add_custom_target(generated_licence_h + BYPRODUCTS ${GENERATED_LICENCE_H} + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${INTERMEDIATE_LICENCE_H} ${GENERATED_LICENCE_H} + DEPENDS ${INTERMEDIATE_LICENCE_H} + COMMENT "Updating licence.h") + +set(GENERATED_COMMIT_C ${GENERATED_SOURCES_DIR}/cmake_commit.c) +set(INTERMEDIATE_COMMIT_C ${GENERATED_COMMIT_C}.tmp) +add_custom_target(check_git_commit + BYPRODUCTS ${INTERMEDIATE_COMMIT_C} + COMMAND ${CMAKE_COMMAND} + -DGIT_EXECUTABLE=${GIT_EXECUTABLE} + -DOUTPUT_FILE=${INTERMEDIATE_COMMIT_C} + -DOUTPUT_TYPE=header + -P ${CMAKE_SOURCE_DIR}/cmake/gitcommit.cmake + DEPENDS ${CMAKE_SOURCE_DIR}/cmake/gitcommit.cmake + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMENT "Checking current git commit") +add_custom_target(cmake_commit_c + BYPRODUCTS ${GENERATED_COMMIT_C} + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${INTERMEDIATE_COMMIT_C} ${GENERATED_COMMIT_C} + DEPENDS check_git_commit ${INTERMEDIATE_COMMIT_C} + COMMENT "Updating cmake_commit.c") + +if(CMAKE_VERSION VERSION_LESS 3.12) + function(add_compile_definitions) + foreach(i ${ARGN}) + add_compile_options(-D${i}) + endforeach() + endfunction() +endif() + +function(add_sources_from_current_dir target) + set(sources) + foreach(i ${ARGN}) + set(sources ${sources} ${CMAKE_CURRENT_SOURCE_DIR}/${i}) + endforeach() + target_sources(${target} PRIVATE ${sources}) +endfunction() + +set(extra_dirs) +if(CMAKE_SYSTEM_NAME MATCHES "Windows" OR WINELIB) + set(platform windows) +else() + set(platform unix) +endif() + +function(be_list TARGET NAME) + cmake_parse_arguments(OPT "SSH;SERIAL;OTHERBACKENDS" "" "" "${ARGN}") + add_library(${TARGET}-be-list OBJECT ${CMAKE_SOURCE_DIR}/be_list.c) + foreach(setting SSH SERIAL OTHERBACKENDS) + if(OPT_${setting}) + target_compile_definitions(${TARGET}-be-list PRIVATE ${setting}=1) + else() + target_compile_definitions(${TARGET}-be-list PRIVATE ${setting}=0) + endif() + endforeach() + target_compile_definitions(${TARGET}-be-list PRIVATE APPNAME=${NAME}) + target_sources(${TARGET} PRIVATE $<TARGET_OBJECTS:${TARGET}-be-list>) +endfunction() + +include(cmake/platforms/${platform}.cmake) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${GENERATED_SOURCES_DIR} + ${platform} + ${extra_dirs}) + +if(PUTTY_DEBUG) + add_compile_definitions(DEBUG) +endif() +if(PUTTY_FUZZING) + add_compile_definitions(FUZZING) +endif() +if(PUTTY_COVERAGE) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage -g ") +endif() diff --git a/cmake/toolchain-mingw.cmake b/cmake/toolchain-mingw.cmake new file mode 100644 index 00000000..2e0bc669 --- /dev/null +++ b/cmake/toolchain-mingw.cmake @@ -0,0 +1,12 @@ +# Simple toolchain file for cross-building Windows PuTTY on Linux +# using MinGW (tested on Ubuntu). + +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_SYSTEM_PROCESSOR x86_64) + +set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) +set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres) +set(CMAKE_AR x86_64-w64-mingw32-ar) +set(CMAKE_RANLIB x86_64-w64-mingw32-ranlib) + +add_compile_definitions(__USE_MINGW_ANSI_STDIO) diff --git a/cmake/toolchain-winegcc.cmake b/cmake/toolchain-winegcc.cmake new file mode 100644 index 00000000..73a9e53e --- /dev/null +++ b/cmake/toolchain-winegcc.cmake @@ -0,0 +1,33 @@ +# Toolchain file for cross-building a Winelib version of Windows PuTTY +# on Linux, using winegcc (tested on Ubuntu). + +# Winelib is weird because it's basically compiling ordinary Linux +# objects and executables, but we want to pretend to be Windows for +# purposes of (a) having resource files, and (b) selecting the Windows +# platform subdirectory. +# +# So, do we tag this as a weird kind of Windows build, or a weird kind +# of Linux build? Either way we have to do _something_ out of the +# ordinary. +# +# After some experimentation, it seems to make more sense to treat +# Winelib builds as basically Linux, and set a flag WINELIB that +# PuTTY's main build scripts will detect and handle specially. +# Specifically, that flag will cause cmake/setup.cmake to select the +# Windows platform (overriding the usual check of CMAKE_SYSTEM_NAME), +# and also trigger a call to enable_language(RC), which for some kind +# of cmake re-entrancy reason we can't do in this toolchain file +# itself. +set(CMAKE_SYSTEM_NAME Linux) +set(WINELIB ON) + +# We need a wrapper script around winegcc proper, because cmake's link +# command lines will refer to system libraries as "-lkernel32.lib" +# rather than the required "-lkernel32". The winegcc script alongside +# this toolchain file bodges that command-line translation. +set(CMAKE_C_COMPILER ${CMAKE_SOURCE_DIR}/cmake/winegcc) + +set(CMAKE_RC_COMPILER wrc) +set(CMAKE_RC_OUTPUT_EXTENSION .res.o) +set(CMAKE_RC_COMPILE_OBJECT + "<CMAKE_RC_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> <SOURCE>") diff --git a/cmake/winegcc b/cmake/winegcc new file mode 100755 index 00000000..fb298ad1 --- /dev/null +++ b/cmake/winegcc @@ -0,0 +1,29 @@ +#!/bin/sh + +# Wrapper for winegcc that allows it to be used in a build generated +# from PuTTY's CMakeLists.txt, by bodging around the command-line +# options that CMake gets wrong. + +init=true +for arg in init "$@"; do + if $init; then + set -- + init=false + continue + fi + + case "$arg" in + # The Windows build definition for PuTTY specifies all the + # system API libraries by names like kernel32.lib. When CMake + # reads that file and thinks it's compiling for Linux, it will + # generate link options such as -lkernel32.lib. But in fact + # winegcc expects -lkernel32, so we need to strip the ".lib" + # suffix. + -l*.lib) set -- "$@" "${arg%.lib}";; + + # Anything else, we leave unchanged. + *) set -- "$@" "$arg";; + esac +done + +exec winegcc "$@" |