aboutsummaryrefslogtreecommitdiff
path: root/cmake
diff options
context:
space:
mode:
Diffstat (limited to 'cmake')
-rwxr-xr-xcmake/glob-symlinks.py65
-rw-r--r--cmake/nestedvm-toolchain.cmake10
-rw-r--r--cmake/platforms/emscripten.cmake47
-rw-r--r--cmake/platforms/nestedvm.cmake60
-rw-r--r--cmake/platforms/osx.cmake58
-rw-r--r--cmake/platforms/unix.cmake68
-rw-r--r--cmake/platforms/windows.cmake40
-rw-r--r--cmake/setup.cmake133
-rw-r--r--cmake/testbuild.c23
-rw-r--r--cmake/windows-dummy-toolchain.cmake14
10 files changed, 518 insertions, 0 deletions
diff --git a/cmake/glob-symlinks.py b/cmake/glob-symlinks.py
new file mode 100755
index 0000000..23a869c
--- /dev/null
+++ b/cmake/glob-symlinks.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python3
+
+# Helper script used by the NestedVM cmake build script.
+#
+# Usage: glob-symlinks.py <srcdir> <wildcard> [<srcdir> <wildcard> ...]
+#
+# Each pair of command-line arguments is treated as a source
+# directory, followed by either a single filename or a wildcard.
+#
+# The result is to create symlinks in the program's working directory
+# mirroring all the files matched by the filenames/wildcards, each
+# pointing at the appropriate source directory.
+#
+# For example, this command
+# glob-symlinks.py /foo \*.txt /bar wibble.blah
+# might create symlinks as follows:
+# this.txt -> /foo/this.txt
+# that.txt -> /foo/that.txt
+# wibble.blah -> /bar/wibble.blah
+#
+# CMake could mostly do this itself, except that some of the files
+# that need symlinking during the NestedVM build (to make a tree that
+# we archive up into a .jar file) are Java class files with some
+# '$suffix' in the name, and CMake doesn't escape the $ signs, so that
+# the suffix vanishes during shell expansion.
+
+import sys
+import os
+import glob
+
+def get_arg_pairs():
+ args = iter(sys.argv)
+ next(args) # skip program name
+ while True:
+ try:
+ yield next(args), next(args)
+ except StopIteration:
+ break
+
+def get_globbed_pairs():
+ for srcdir, pattern in get_arg_pairs():
+ if glob.escape(pattern) == pattern:
+ # Assume that unglobbed filenames exist
+ #print("non-glob:", srcdir, pattern)
+ yield srcdir, pattern
+ else:
+ #print("globbing:", srcdir, pattern)
+ prefix = srcdir + "/"
+ for filename in glob.iglob(prefix + pattern):
+ assert filename.startswith(prefix)
+ filename = filename[len(prefix):]
+ #print(" ->", srcdir, filename)
+ yield srcdir, filename
+
+for srcdir, filename in get_globbed_pairs():
+ dirname = os.path.dirname(filename)
+ if len(dirname) > 0:
+ try:
+ os.makedirs(dirname)
+ except FileExistsError:
+ pass
+ try:
+ os.symlink(os.path.join(srcdir, filename), filename)
+ except FileExistsError:
+ pass
diff --git a/cmake/nestedvm-toolchain.cmake b/cmake/nestedvm-toolchain.cmake
new file mode 100644
index 0000000..337410c
--- /dev/null
+++ b/cmake/nestedvm-toolchain.cmake
@@ -0,0 +1,10 @@
+SET(CMAKE_SYSTEM_NAME NestedVM)
+SET(CMAKE_SYSTEM_PROCESSOR mips)
+
+SET(CMAKE_C_COMPILER ${NESTEDVM}/upstream/install/bin/mips-unknown-elf-gcc)
+
+SET(CMAKE_FIND_ROOT_PATH ${NESTEDVM}/upstream/install)
+SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
diff --git a/cmake/platforms/emscripten.cmake b/cmake/platforms/emscripten.cmake
new file mode 100644
index 0000000..d6b5cd2
--- /dev/null
+++ b/cmake/platforms/emscripten.cmake
@@ -0,0 +1,47 @@
+set(platform_common_sources emcc.c)
+set(platform_gui_libs)
+set(platform_libs)
+set(CMAKE_EXECUTABLE_SUFFIX ".js")
+
+set(emcc_export_list
+ # Event handlers for mouse and keyboard input
+ _mouseup
+ _mousedown
+ _mousemove
+ _key
+ # Callback when the program activates timing
+ _timer_callback
+ # Callback from button presses in the UI outside the canvas
+ _command
+ # Game-saving and game-loading functions
+ _get_save_file
+ _free_save_file
+ _load_game
+ # Callbacks to return values from dialog boxes
+ _dlg_return_sval
+ _dlg_return_ival
+ # Callbacks when the resizing controls are used
+ _resize_puzzle
+ _restore_puzzle_size
+ # Main program, run at initialisation time
+ _main)
+
+list(TRANSFORM emcc_export_list PREPEND \")
+list(TRANSFORM emcc_export_list APPEND \")
+string(JOIN "," emcc_export_string ${emcc_export_list})
+set(CMAKE_C_LINK_FLAGS "-s ASM_JS=1 -s EXPORTED_FUNCTIONS='[${emcc_export_string}]'")
+message("link=${CMAKE_C_LINK_EXECUTABLE}")
+
+set(build_cli_programs FALSE)
+
+function(get_platform_puzzle_extra_source_files OUTVAR NAME)
+ set(${OUTVAR} PARENT_SCOPE)
+endfunction()
+
+function(set_platform_puzzle_target_properties NAME TARGET)
+ em_link_pre_js(${TARGET} ${CMAKE_SOURCE_DIR}/emccpre.js)
+ em_link_js_library(${TARGET} ${CMAKE_SOURCE_DIR}/emcclib.js)
+endfunction()
+
+function(build_platform_extras)
+endfunction()
diff --git a/cmake/platforms/nestedvm.cmake b/cmake/platforms/nestedvm.cmake
new file mode 100644
index 0000000..e5de2ee
--- /dev/null
+++ b/cmake/platforms/nestedvm.cmake
@@ -0,0 +1,60 @@
+set(platform_common_sources nestedvm.c printing.c)
+set(platform_libs -lm)
+
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/applet.manifest
+ "Main-Class: PuzzleApplet\n")
+
+include(FindJava)
+add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/PuzzleApplet.class
+ COMMAND ${Java_JAVAC_EXECUTABLE}
+ -source 1.7 -target 1.7 -d . -cp ${NESTEDVM}/build
+ ${CMAKE_SOURCE_DIR}/PuzzleApplet.java
+ DEPENDS ${CMAKE_SOURCE_DIR}/PuzzleApplet.java)
+
+function(get_platform_puzzle_extra_source_files OUTVAR NAME)
+ set(${OUTVAR} PARENT_SCOPE)
+endfunction()
+
+function(set_platform_puzzle_target_properties NAME TARGET)
+ set(build_subdir ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}-tmp)
+
+ add_custom_command(OUTPUT ${build_subdir}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${build_subdir})
+ add_custom_command(OUTPUT ${build_subdir}/PuzzleApplet.class
+ COMMAND ${CMAKE_SOURCE_DIR}/cmake/glob-symlinks.py
+ ${CMAKE_BINARY_DIR} applet.manifest
+ ${CMAKE_BINARY_DIR} PuzzleApplet\\*.class
+ ${NESTEDVM}/build org/ibex/nestedvm/Registers.class
+ ${NESTEDVM}/build org/ibex/nestedvm/UsermodeConstants.class
+ ${NESTEDVM}/build org/ibex/nestedvm/Runtime*.class
+ ${NESTEDVM}/build org/ibex/nestedvm/util/Platform\\*.class
+ ${NESTEDVM}/build org/ibex/nestedvm/util/Seekable\\*.class
+ WORKING_DIRECTORY ${build_subdir}
+ DEPENDS
+ ${build_subdir}
+ ${CMAKE_BINARY_DIR}/PuzzleApplet.class
+ ${CMAKE_SOURCE_DIR}/cmake/glob-symlinks.py)
+
+ add_custom_command(OUTPUT ${build_subdir}/PuzzleEngine.class
+ COMMAND ${Java_JAVA_EXECUTABLE}
+ -cp ${NESTEDVM}/build:${NESTEDVM}/upstream/build/classgen/build
+ org.ibex.nestedvm.Compiler -outformat class -d .
+ PuzzleEngine ${CMAKE_CURRENT_BINARY_DIR}/${EXENAME}
+ DEPENDS
+ ${build_subdir}
+ ${CMAKE_CURRENT_BINARY_DIR}/${EXENAME}
+ WORKING_DIRECTORY ${build_subdir})
+
+ add_custom_target(${TARGET}-jar ALL
+ COMMAND ${Java_JAR_EXECUTABLE}
+ cfm ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}.jar
+ applet.manifest PuzzleEngine.class PuzzleApplet*.class org
+ WORKING_DIRECTORY ${build_subdir}
+ DEPENDS
+ ${CMAKE_BINARY_DIR}/PuzzleApplet.class
+ ${build_subdir}/PuzzleApplet.class
+ ${build_subdir}/PuzzleEngine.class)
+endfunction()
+
+function(build_platform_extras)
+endfunction()
diff --git a/cmake/platforms/osx.cmake b/cmake/platforms/osx.cmake
new file mode 100644
index 0000000..4577a73
--- /dev/null
+++ b/cmake/platforms/osx.cmake
@@ -0,0 +1,58 @@
+set(CMAKE_OSX_DEPLOYMENT_TARGET 10.6)
+find_program(HALIBUT halibut REQUIRED)
+set(CPACK_GENERATOR DragNDrop)
+set(CPACK_PACKAGE_FILE_NAME Puzzles)
+set(CPACK_DMG_VOLUME_NAME "Simon Tatham's Puzzle Collection")
+include(CPack)
+set(build_individual_puzzles FALSE)
+
+function(get_platform_puzzle_extra_source_files OUTVAR NAME)
+ set(${OUTVAR} PARENT_SCOPE)
+endfunction()
+
+function(set_platform_puzzle_target_properties NAME TARGET)
+endfunction()
+
+function(build_platform_extras)
+ write_generated_games_header()
+
+ set(resources
+ ${CMAKE_CURRENT_SOURCE_DIR}/osx/Puzzles.icns)
+ set_source_files_properties(${resources} PROPERTIES
+ MACOSX_PACKAGE_LOCATION Resources)
+
+ add_executable(puzzles MACOSX_BUNDLE
+ osx.m list.c ${puzzle_sources}
+ ${resources})
+
+ set_target_properties(puzzles PROPERTIES
+ OUTPUT_NAME Puzzles
+ MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/osx/Info.plist)
+
+ target_compile_definitions(puzzles PRIVATE COMBINED)
+ target_include_directories(puzzles PRIVATE ${generated_include_dir})
+ target_link_libraries(puzzles common ${platform_gui_libs} ${platform_libs}
+ "-framework Cocoa")
+
+ get_property(bundle_basename TARGET puzzles PROPERTY OUTPUT_NAME)
+ set(help_dir ${CMAKE_CURRENT_BINARY_DIR}/${bundle_basename}.app/Contents/Resources/Help)
+ message(${help_dir})
+ add_custom_command(OUTPUT ${help_dir}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${help_dir}
+ DEPENDS puzzles)
+ add_custom_command(OUTPUT ${help_dir}/index.html
+ COMMAND ${HALIBUT} --html
+ ${CMAKE_CURRENT_SOURCE_DIR}/osx-help.but
+ ${CMAKE_CURRENT_SOURCE_DIR}/puzzles.but
+ DEPENDS
+ ${help_dir}
+ ${CMAKE_CURRENT_SOURCE_DIR}/osx-help.but
+ ${CMAKE_CURRENT_SOURCE_DIR}/puzzles.but
+ WORKING_DIRECTORY ${help_dir})
+ add_custom_target(osx_help ALL
+ DEPENDS ${help_dir}/index.html)
+
+ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/Puzzles.app
+ USE_SOURCE_PERMISSIONS
+ DESTINATION .)
+endfunction()
diff --git a/cmake/platforms/unix.cmake b/cmake/platforms/unix.cmake
new file mode 100644
index 0000000..1bed675
--- /dev/null
+++ b/cmake/platforms/unix.cmake
@@ -0,0 +1,68 @@
+find_package(PkgConfig REQUIRED)
+
+set(PUZZLES_GTK_FOUND FALSE)
+macro(try_gtk_package VER PACKAGENAME)
+ if(NOT PUZZLES_GTK_FOUND AND
+ (NOT DEFINED PUZZLES_GTK_VERSION OR
+ PUZZLES_GTK_VERSION STREQUAL ${VER}))
+ pkg_check_modules(GTK ${PACKAGENAME})
+ if(GTK_FOUND)
+ set(PUZZLES_GTK_FOUND TRUE)
+ endif()
+ endif()
+endmacro()
+
+try_gtk_package(3 gtk+-3.0)
+try_gtk_package(2 gtk+-2.0)
+
+if(NOT PUZZLES_GTK_FOUND)
+ message(FATAL_ERROR "Unable to find any usable version of GTK.")
+endif()
+
+include_directories(${GTK_INCLUDE_DIRS})
+link_directories(${GTK_LIBRARY_DIRS})
+
+set(platform_common_sources gtk.c printing.c)
+set(platform_gui_libs ${GTK_LIBRARIES})
+
+set(platform_libs -lm)
+
+set(build_icons TRUE)
+
+function(try_append_cflag flag)
+ set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${flag}")
+ try_compile(compile_passed ${CMAKE_BINARY_DIR}
+ SOURCES ${CMAKE_SOURCE_DIR}/cmake/testbuild.c
+ OUTPUT_VARIABLE test_compile_output
+ CMAKE_FLAGS "-DINCLUDE_DIRECTORIES=${GTK_INCLUDE_DIRS}")
+ if(compile_passed)
+ set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} PARENT_SCOPE)
+ endif()
+endfunction()
+if (CMAKE_C_COMPILER_ID MATCHES "GNU" OR
+ CMAKE_C_COMPILER_ID MATCHES "Clang")
+ try_append_cflag(-Wall)
+ try_append_cflag(-Werror)
+ try_append_cflag(-std=c89)
+ try_append_cflag(-pedantic)
+ try_append_cflag(-Wwrite-strings)
+endif()
+
+function(get_platform_puzzle_extra_source_files OUTVAR NAME)
+ if(build_icons AND EXISTS ${CMAKE_SOURCE_DIR}/icons/${NAME}.sav)
+ build_icon(${NAME})
+ set(c_icon_file ${CMAKE_BINARY_DIR}/icons/${NAME}-icon.c)
+ else()
+ set(c_icon_file ${CMAKE_SOURCE_DIR}/no-icon.c)
+ endif()
+
+ set(${OUTVAR} ${c_icon_file} PARENT_SCOPE)
+endfunction()
+
+function(set_platform_puzzle_target_properties NAME TARGET)
+ install(TARGETS ${TARGET})
+endfunction()
+
+function(build_platform_extras)
+endfunction()
diff --git a/cmake/platforms/windows.cmake b/cmake/platforms/windows.cmake
new file mode 100644
index 0000000..dd27148
--- /dev/null
+++ b/cmake/platforms/windows.cmake
@@ -0,0 +1,40 @@
+set(platform_common_sources windows.c printing.c)
+
+set(platform_gui_libs
+ user32.lib gdi32.lib comctl32.lib comdlg32.lib winspool.lib)
+
+set(platform_libs)
+
+add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
+
+function(get_platform_puzzle_extra_source_files OUTVAR NAME)
+ set(${OUTVAR} ${CMAKE_SOURCE_DIR}/puzzles.rc PARENT_SCOPE)
+endfunction()
+
+function(set_platform_puzzle_target_properties NAME TARGET)
+ if(DEFINED ICO_DIR AND EXISTS ${ICO_DIR}/${NAME}.ico)
+ target_compile_definitions(${TARGET} PRIVATE ICON_FILE=\"${ICO_DIR}/${NAME}.ico\")
+ endif()
+ set_target_properties(${TARGET} PROPERTIES WIN32_EXECUTABLE ON)
+endfunction()
+
+function(build_platform_extras)
+ write_generated_games_header()
+
+ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/gamedesc.txt "")
+ list(SORT puzzle_names)
+ foreach(name ${puzzle_names})
+ file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/gamedesc.txt "\
+${name}:\
+${exename_${name}}.exe:\
+${displayname_${name}}:\
+${description_${name}}:\
+${objective_${name}}\n")
+ endforeach()
+
+ add_executable(puzzles windows.c list.c ${puzzle_sources})
+ target_compile_definitions(puzzles PRIVATE COMBINED)
+ target_include_directories(puzzles PRIVATE ${generated_include_dir})
+ target_link_libraries(puzzles common ${platform_gui_libs} ${platform_libs})
+ set_target_properties(puzzles PROPERTIES WIN32_EXECUTABLE ON)
+endfunction()
diff --git a/cmake/setup.cmake b/cmake/setup.cmake
new file mode 100644
index 0000000..8afa455
--- /dev/null
+++ b/cmake/setup.cmake
@@ -0,0 +1,133 @@
+set(build_individual_puzzles TRUE)
+set(build_cli_programs TRUE)
+set(build_icons FALSE)
+set(need_c_icons FALSE)
+
+# Include one of platforms/*.cmake to define platform-specific stuff.
+# Each of these is expected to:
+# - define get_platform_puzzle_extra_source_files(), used below
+# - define set_platform_puzzle_target_properties(), used below
+# - define build_platform_extras(), called from the top-level CMakeLists.txt
+# - override the above build_* settings, if necessary
+if(CMAKE_SYSTEM_NAME MATCHES "Windows")
+ include(cmake/platforms/windows.cmake)
+elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin")
+ include(cmake/platforms/osx.cmake)
+elseif(CMAKE_SYSTEM_NAME MATCHES "NestedVM")
+ include(cmake/platforms/nestedvm.cmake)
+elseif(CMAKE_C_COMPILER MATCHES "emcc")
+ include(cmake/platforms/emscripten.cmake)
+else() # assume Unix
+ include(cmake/platforms/unix.cmake)
+endif()
+
+# Accumulate lists of the puzzles' bare names and source file
+# locations, for use in build_platform_extras() implementations when
+# they want to build things based on all the puzzles at once.
+set(puzzle_names)
+set(puzzle_sources)
+
+include(icons/icons.cmake)
+
+# The main function called from the top-level CMakeLists.txt to define
+# each puzzle.
+function(puzzle NAME)
+ cmake_parse_arguments(OPT
+ "" "DISPLAYNAME;DESCRIPTION;OBJECTIVE;WINDOWS_EXE_NAME" "" ${ARGN})
+
+ if(NOT DEFINED OPT_WINDOWS_EXE_NAME)
+ set(OPT_WINDOWS_EXE_NAME ${NAME})
+ endif()
+
+ if (CMAKE_SYSTEM_NAME MATCHES "Windows")
+ set(EXENAME ${OPT_WINDOWS_EXE_NAME})
+ else()
+ set(EXENAME ${NAME})
+ endif()
+
+ set(exename_${NAME} ${EXENAME} PARENT_SCOPE)
+ set(displayname_${NAME} ${OPT_DISPLAYNAME} PARENT_SCOPE)
+ set(description_${NAME} ${OPT_DESCRIPTION} PARENT_SCOPE)
+ set(objective_${NAME} ${OPT_OBJECTIVE} PARENT_SCOPE)
+
+ set(official TRUE)
+ if(NAME STREQUAL nullgame)
+ # nullgame is not a playable puzzle; it has to be built (to prove
+ # it still can build), but not installed, or included in the main
+ # list of puzzles, or compiled into all-in-one binaries, etc. In
+ # other words, it's not "officially" part of the puzzle
+ # collection.
+ set(official FALSE)
+ endif()
+ if(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_SOURCE_DIR}/unfinished)
+ # The same goes for puzzles in the 'unfinished' subdirectory,
+ # although we make an exception if configured to on the command
+ # line.
+ list(FIND PUZZLES_ENABLE_UNFINISHED ${NAME} enable_this_one)
+ if(enable_this_one EQUAL -1)
+ set(official FALSE)
+ endif()
+ endif()
+
+ if (official)
+ set(puzzle_names ${puzzle_names} ${NAME} PARENT_SCOPE)
+ set(puzzle_sources ${puzzle_sources} ${CMAKE_CURRENT_SOURCE_DIR}/${NAME}.c PARENT_SCOPE)
+ endif()
+
+ get_platform_puzzle_extra_source_files(extra_files ${NAME})
+
+ if (build_individual_puzzles)
+ add_executable(${EXENAME} ${NAME}.c ${extra_files})
+ target_link_libraries(${EXENAME}
+ common ${platform_gui_libs} ${platform_libs})
+ set_platform_puzzle_target_properties(${NAME} ${EXENAME})
+ endif()
+endfunction()
+
+# The main function called from the top-level CMakeLists.txt to define
+# a command-line helper tool.
+function(cliprogram NAME)
+ cmake_parse_arguments(OPT
+ "" "COMPILE_DEFINITIONS" "" ${ARGN})
+
+ if(build_cli_programs)
+ add_executable(${NAME} ${CMAKE_SOURCE_DIR}/nullfe.c
+ ${OPT_UNPARSED_ARGUMENTS})
+ target_link_libraries(${NAME} common ${platform_libs})
+ if(OPT_COMPILE_DEFINITIONS)
+ target_compile_definitions(${NAME} PRIVATE ${OPT_COMPILE_DEFINITIONS})
+ endif()
+ endif()
+endfunction()
+
+# A small wrapper around cliprogram, taking advantage of the common
+# formula that puzzle 'foo' often comes with 'foosolver'.
+function(solver NAME)
+ cliprogram(${NAME}solver ${puzzle_src_prefix}${NAME}.c ${ARGN}
+ COMPILE_DEFINITIONS STANDALONE_SOLVER)
+endfunction()
+
+function(write_generated_games_header)
+ set(generated_include_dir ${CMAKE_CURRENT_BINARY_DIR}/include)
+ set(generated_include_dir ${generated_include_dir} PARENT_SCOPE)
+
+ file(MAKE_DIRECTORY ${generated_include_dir})
+ file(WRITE ${generated_include_dir}/generated-games.h "")
+ list(SORT puzzle_names)
+ foreach(name ${puzzle_names})
+ file(APPEND ${generated_include_dir}/generated-games.h "GAME(${name})\n")
+ endforeach()
+endfunction()
+
+# This has to be run from the unfinished subdirectory, so that the
+# updates to puzzle_names etc will be propagated to the top-level scope.
+macro(export_variables_to_parent_scope)
+ set(puzzle_names ${puzzle_names} PARENT_SCOPE)
+ set(puzzle_sources ${puzzle_sources} PARENT_SCOPE)
+ foreach(name ${puzzle_names})
+ set(exename_${name} ${exename_${name}} PARENT_SCOPE)
+ set(displayname_${name} ${displayname_${name}} PARENT_SCOPE)
+ set(description_${name} ${description_${name}} PARENT_SCOPE)
+ set(objective_${name} ${objective_${name}} PARENT_SCOPE)
+ endforeach()
+endmacro()
diff --git a/cmake/testbuild.c b/cmake/testbuild.c
new file mode 100644
index 0000000..67a6879
--- /dev/null
+++ b/cmake/testbuild.c
@@ -0,0 +1,23 @@
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <time.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include <gdk/gdkx.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+
+int dummy;
diff --git a/cmake/windows-dummy-toolchain.cmake b/cmake/windows-dummy-toolchain.cmake
new file mode 100644
index 0000000..493652b
--- /dev/null
+++ b/cmake/windows-dummy-toolchain.cmake
@@ -0,0 +1,14 @@
+# Fake CMake toolchain file, good enough to make cmake's initial
+# configuration think it's going to build for Windows, but not good
+# enough to actually do any building. The purpose is so that I can run
+# Puzzles's CMakeLists.txt in Windows mode as far as making
+# gamedesc.txt.
+
+set(CMAKE_SYSTEM_NAME Windows)
+
+set(CMAKE_C_COMPILER /bin/false)
+set(CMAKE_LINKER /bin/false)
+set(CMAKE_MT /bin/false)
+set(CMAKE_RC_COMPILER /bin/false)
+
+set(CMAKE_C_COMPILER_WORKS ON)