setup.cmake 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. set(PUZZLES_ENABLE_UNFINISHED ""
  2. CACHE STRING "List of puzzles in the 'unfinished' subdirectory \
  3. to build as if official (separated by ';')")
  4. set(build_individual_puzzles TRUE)
  5. set(build_cli_programs TRUE)
  6. set(build_gui_programs TRUE)
  7. set(build_icons FALSE)
  8. set(need_c_icons FALSE)
  9. # Don't disable assertions, even in release mode. Our assertions
  10. # generally aren't expensive and protect against more annoying crashes
  11. # and memory corruption.
  12. string(REPLACE "/DNDEBUG" "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}")
  13. string(REPLACE "-DNDEBUG" "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}")
  14. string(REPLACE "/DNDEBUG" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
  15. string(REPLACE "-DNDEBUG" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
  16. string(REPLACE "/DNDEBUG" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
  17. string(REPLACE "-DNDEBUG" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
  18. # Include one of platforms/*.cmake to define platform-specific stuff.
  19. # Each of these is expected to:
  20. # - define get_platform_puzzle_extra_source_files(), used below
  21. # - define set_platform_puzzle_target_properties(), used below
  22. # - define build_platform_extras(), called from the top-level CMakeLists.txt
  23. # - override the above build_* settings, if necessary
  24. if(CMAKE_SYSTEM_NAME MATCHES "Windows")
  25. include(cmake/platforms/windows.cmake)
  26. elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin")
  27. include(cmake/platforms/osx.cmake)
  28. elseif(CMAKE_SYSTEM_NAME MATCHES "NestedVM")
  29. include(cmake/platforms/nestedvm.cmake)
  30. elseif(CMAKE_C_COMPILER MATCHES "emcc")
  31. include(cmake/platforms/emscripten.cmake)
  32. else() # assume Unix
  33. include(cmake/platforms/unix.cmake)
  34. endif()
  35. # Accumulate lists of the puzzles' bare names and source file
  36. # locations, for use in build_platform_extras() implementations when
  37. # they want to build things based on all the puzzles at once.
  38. set(puzzle_names)
  39. set(puzzle_sources)
  40. include(CheckIncludeFile)
  41. check_include_file(stdint.h HAVE_STDINT_H)
  42. if(NOT HAVE_STDINT_H)
  43. add_compile_definitions(NO_STDINT_H)
  44. endif()
  45. check_include_file(tgmath.h HAVE_TGMATH_H)
  46. if(NOT HAVE_TGMATH_H)
  47. add_compile_definitions(NO_TGMATH_H)
  48. endif()
  49. # Try to normalise source file pathnames as seen in __FILE__ (e.g.
  50. # assertion failure messages). Partly to avoid bloating the binaries
  51. # with file prefixes like /home/simon/stuff/things/tmp-7x6c5d54/, but
  52. # also to make the builds more deterministic - building from the same
  53. # source should give the same binary even if you do it in a
  54. # differently named temp directory.
  55. function(map_pathname src dst)
  56. if(CMAKE_SYSTEM_NAME MATCHES "NestedVM")
  57. # Do nothing: the NestedVM gcc is unfortunately too old to support
  58. # this option.
  59. elseif(CMAKE_C_COMPILER_ID MATCHES "Clang" AND
  60. CMAKE_C_COMPILER_FRONTEND_VARIANT MATCHES "MSVC")
  61. # -fmacro-prefix-map isn't available as a clang-cl option, so we
  62. # prefix it with -Xclang to pass it straight through to the
  63. # underlying clang -cc1 invocation, which spells the option the
  64. # same way.
  65. set(CMAKE_C_FLAGS
  66. "${CMAKE_C_FLAGS} -Xclang -fmacro-prefix-map=${src}=${dst}"
  67. PARENT_SCOPE)
  68. elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR
  69. CMAKE_C_COMPILER_ID MATCHES "Clang")
  70. set(CMAKE_C_FLAGS
  71. "${CMAKE_C_FLAGS} -fmacro-prefix-map=${src}=${dst}"
  72. PARENT_SCOPE)
  73. endif()
  74. endfunction()
  75. map_pathname(${CMAKE_SOURCE_DIR} /puzzles)
  76. map_pathname(${CMAKE_BINARY_DIR} /build)
  77. include(icons/icons.cmake)
  78. # The main function called from the top-level CMakeLists.txt to define
  79. # each puzzle.
  80. function(puzzle NAME)
  81. cmake_parse_arguments(OPT
  82. "" "DISPLAYNAME;DESCRIPTION;OBJECTIVE;WINDOWS_EXE_NAME" "" ${ARGN})
  83. if(NOT DEFINED OPT_WINDOWS_EXE_NAME)
  84. set(OPT_WINDOWS_EXE_NAME ${NAME})
  85. endif()
  86. if (CMAKE_SYSTEM_NAME MATCHES "Windows")
  87. set(EXENAME ${OPT_WINDOWS_EXE_NAME})
  88. else()
  89. set(EXENAME ${NAME})
  90. endif()
  91. set(exename_${NAME} ${EXENAME} PARENT_SCOPE)
  92. set(displayname_${NAME} ${OPT_DISPLAYNAME} PARENT_SCOPE)
  93. set(description_${NAME} ${OPT_DESCRIPTION} PARENT_SCOPE)
  94. set(objective_${NAME} ${OPT_OBJECTIVE} PARENT_SCOPE)
  95. set(official TRUE)
  96. if(NAME STREQUAL nullgame)
  97. # nullgame is not a playable puzzle; it has to be built (to prove
  98. # it still can build), but not installed, or included in the main
  99. # list of puzzles, or compiled into all-in-one binaries, etc. In
  100. # other words, it's not "officially" part of the puzzle
  101. # collection.
  102. set(official FALSE)
  103. endif()
  104. if(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_SOURCE_DIR}/unfinished)
  105. # The same goes for puzzles in the 'unfinished' subdirectory,
  106. # although we make an exception if configured to on the command
  107. # line.
  108. list(FIND PUZZLES_ENABLE_UNFINISHED ${NAME} enable_this_one)
  109. if(enable_this_one EQUAL -1)
  110. set(official FALSE)
  111. endif()
  112. endif()
  113. if (official)
  114. set(puzzle_names ${puzzle_names} ${NAME} PARENT_SCOPE)
  115. set(puzzle_sources ${puzzle_sources} ${CMAKE_CURRENT_SOURCE_DIR}/${NAME}.c PARENT_SCOPE)
  116. endif()
  117. get_platform_puzzle_extra_source_files(extra_files ${NAME})
  118. if (build_individual_puzzles)
  119. add_executable(${EXENAME} ${NAME}.c ${extra_files})
  120. target_link_libraries(${EXENAME}
  121. common ${platform_gui_libs} ${platform_libs})
  122. set_property(TARGET ${EXENAME} PROPERTY exename ${EXENAME})
  123. set_property(TARGET ${EXENAME} PROPERTY displayname ${OPT_DISPLAYNAME})
  124. set_property(TARGET ${EXENAME} PROPERTY description ${OPT_DESCRIPTION})
  125. set_property(TARGET ${EXENAME} PROPERTY objective ${OPT_OBJECTIVE})
  126. set_property(TARGET ${EXENAME} PROPERTY official ${official})
  127. set_platform_puzzle_target_properties(${NAME} ${EXENAME})
  128. set_platform_gui_target_properties(${EXENAME})
  129. endif()
  130. endfunction()
  131. # The main function called from the top-level CMakeLists.txt to define
  132. # a command-line helper tool.
  133. function(cliprogram NAME)
  134. cmake_parse_arguments(OPT
  135. "CORE_LIB" "" "COMPILE_DEFINITIONS" ${ARGN})
  136. if(OPT_CORE_LIB)
  137. set(lib core)
  138. else()
  139. set(lib common)
  140. endif()
  141. if(build_cli_programs)
  142. add_executable(${NAME} ${CMAKE_SOURCE_DIR}/nullfe.c
  143. ${OPT_UNPARSED_ARGUMENTS})
  144. target_link_libraries(${NAME} ${lib} ${platform_libs})
  145. if(OPT_COMPILE_DEFINITIONS)
  146. target_compile_definitions(${NAME} PRIVATE ${OPT_COMPILE_DEFINITIONS})
  147. endif()
  148. endif()
  149. endfunction()
  150. # Similar to cliprogram, but builds a GUI helper tool, linked against
  151. # the normal puzzle frontend.
  152. function(guiprogram NAME)
  153. cmake_parse_arguments(OPT
  154. "" "" "COMPILE_DEFINITIONS" ${ARGN})
  155. if(build_gui_programs)
  156. get_platform_puzzle_extra_source_files(extra_files ${NAME})
  157. add_executable(${NAME} ${OPT_UNPARSED_ARGUMENTS} ${extra_files})
  158. target_link_libraries(${NAME}
  159. common ${platform_gui_libs} ${platform_libs})
  160. if(OPT_COMPILE_DEFINITIONS)
  161. target_compile_definitions(${NAME} PRIVATE ${OPT_COMPILE_DEFINITIONS})
  162. endif()
  163. set_platform_gui_target_properties(${NAME})
  164. endif()
  165. endfunction()
  166. # A small wrapper around cliprogram, taking advantage of the common
  167. # formula that puzzle 'foo' often comes with 'foosolver'.
  168. function(solver NAME)
  169. cliprogram(${NAME}solver ${puzzle_src_prefix}${NAME}.c ${ARGN}
  170. COMPILE_DEFINITIONS STANDALONE_SOLVER)
  171. endfunction()
  172. function(write_generated_games_header)
  173. set(generated_include_dir ${CMAKE_CURRENT_BINARY_DIR}/include)
  174. set(generated_include_dir ${generated_include_dir} PARENT_SCOPE)
  175. set(header_pre ${generated_include_dir}/generated-games.h.pre)
  176. set(header ${generated_include_dir}/generated-games.h)
  177. file(MAKE_DIRECTORY ${generated_include_dir})
  178. file(WRITE ${header_pre} "")
  179. list(SORT puzzle_names)
  180. foreach(name ${puzzle_names})
  181. file(APPEND ${header_pre} "GAME(${name})\n")
  182. endforeach()
  183. configure_file(${header_pre} ${header} COPYONLY)
  184. endfunction()
  185. # This has to be run from the unfinished subdirectory, so that the
  186. # updates to puzzle_names etc will be propagated to the top-level scope.
  187. macro(export_variables_to_parent_scope)
  188. set(puzzle_names ${puzzle_names} PARENT_SCOPE)
  189. set(puzzle_sources ${puzzle_sources} PARENT_SCOPE)
  190. foreach(name ${puzzle_names})
  191. set(exename_${name} ${exename_${name}} PARENT_SCOPE)
  192. set(displayname_${name} ${displayname_${name}} PARENT_SCOPE)
  193. set(description_${name} ${description_${name}} PARENT_SCOPE)
  194. set(objective_${name} ${objective_${name}} PARENT_SCOPE)
  195. endforeach()
  196. endmacro()
  197. macro(build_extras)
  198. # Write out a list of the game names, for benchmark.sh to use.
  199. file(WRITE ${CMAKE_BINARY_DIR}/gamelist.txt "")
  200. list(SORT puzzle_names)
  201. foreach(name ${puzzle_names})
  202. file(APPEND ${CMAKE_BINARY_DIR}/gamelist.txt "${name}\n")
  203. endforeach()
  204. # Further extra stuff specific to particular platforms.
  205. build_platform_extras()
  206. endmacro()