ref: 4a4774d417461522ffb82f189eef2e25dcdecc28
dir: /CMakeLists.txt/
if(APPLE OR WIN32)
cmake_minimum_required(VERSION 3.21)
else()
# Oldest supported Ubuntu is 20.04, which ships with cmake 3.16.
# When we can stop supporting Ubuntu 20.04, bump to CMake 3.21.
cmake_minimum_required(VERSION 3.16)
endif()
if(APPLE OR WIN32)
set(GAME_TARGET "CandyCrisis")
else()
set(GAME_TARGET "candycrisis")
endif()
set(GAME_FRIENDLY_NAME "Candy Crisis")
set(GAME_BUNDLE_ID "io.jor.candycrisis")
set(GAME_DATA_DIR "CandyCrisisResources")
set(GAME_MAC_COPYRIGHT "https://github.com/jorio/CandyCrisis")
# Apply macOS deployment target and architectures to all subprojects
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.11" CACHE STRING "Minimum macOS deployment version")
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "Target macOS architectures")
if (${CMAKE_VERSION} VERSION_LESS "3.21")
set(CMAKE_C_STANDARD 11)
else()
set(CMAKE_C_STANDARD 17)
endif()
project(${GAME_TARGET} LANGUAGES C
VERSION 3.0.1)
# Create an option to switch between a system sdl library and a vendored sdl library
option(BUILD_SDL_FROM_SOURCE "Build SDL from source" OFF)
option(STATIC_SDL "Static link SDL" OFF)
option(SANITIZE "Build with asan/ubsan" OFF)
set(CODE_SIGN_IDENTITY "" CACHE STRING "macOS code signing identity. If omitted, the app won't be signed.")
if(NOT WIN32 AND NOT APPLE)
if(SANITIZE)
message("Sanitizers enabled")
else()
message("Sanitizers disabled (pass -DSANITIZE=1 to enable)")
endif()
endif()
# Set Visual Studio startup project
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${GAME_TARGET})
set(GAME_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
#------------------------------------------------------------------------------
# FIND SDL
#------------------------------------------------------------------------------
# If SDL2_DIR wasn't specified, discover if the user put some prebuilt SDL2 package in the project's root directory
if(NOT DEFINED SDL2_DIR)
if(APPLE)
set(_sdl2_maybe "${CMAKE_SOURCE_DIR}/SDL2.framework/Resources/CMake")
elseif(WIN32)
set(_sdl2_maybe "${CMAKE_SOURCE_DIR}/SDL2/cmake")
endif()
if(DEFINED _sdl2_maybe AND EXISTS "${_sdl2_maybe}")
set(SDL2_DIR "${_sdl2_maybe}")
else()
message("Couldn't find prebuilt SDL2 package in: ${_sdl2_maybe}")
endif()
unset(_sdl2_maybe)
endif()
if(NOT BUILD_SDL_FROM_SOURCE)
# 1. Look for an SDL2 package, 2. look for the SDL2 component and 3. fail if none can be found
find_package(SDL2 CONFIG REQUIRED COMPONENTS SDL2)
# 1. Look for an SDL2 package, 2. Look for the SDL2maincomponent and 3. DO NOT fail when SDL2main is not available
find_package(SDL2 REQUIRED CONFIG COMPONENTS SDL2main)
message("Found pre-built SDL: " ${SDL2_PREFIX})
else()
if(NOT DEFINED SDL2_DIR)
set(SDL2_DIR "${CMAKE_SOURCE_DIR}/SDL")
endif()
message("Building SDL from source: " ${SDL2_DIR})
add_subdirectory("${SDL2_DIR}" EXCLUDE_FROM_ALL)
endif()
#------------------------------------------------------------------------------
# GENERATED FILES
#------------------------------------------------------------------------------
# Write header file containing version info
configure_file(${GAME_SOURCE_DIR}/version.h.in ${GAME_SOURCE_DIR}/version.h)
# Readme file containing version info
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/packaging/ReadMe.txt.in ${CMAKE_CURRENT_BINARY_DIR}/ReadMe.txt)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/packaging/version.txt.in ${CMAKE_CURRENT_BINARY_DIR}/version.txt)
#------------------------------------------------------------------------------
# EXECUTABLE TARGET
#------------------------------------------------------------------------------
file(GLOB_RECURSE GAME_SOURCES CONFIGURE_DEPENDS ${GAME_SOURCE_DIR}/*.c ${GAME_SOURCE_DIR}/*.h)
if(WIN32)
list(APPEND GAME_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/packaging/app.exe.rc)
elseif(APPLE)
list(APPEND GAME_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/packaging/app.icns)
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/packaging/app.icns PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
endif()
# Executable
add_executable(${GAME_TARGET} ${GAME_SOURCES})
target_include_directories(${GAME_TARGET} PRIVATE ${GAME_SOURCE_DIR})
# Create macOS app bundle with friendly name
if(APPLE)
set_target_properties(${GAME_TARGET} PROPERTIES OUTPUT_NAME "${GAME_FRIENDLY_NAME}")
endif()
set_target_properties(${GAME_TARGET} PROPERTIES
#--------------------------------------------------------------------------
# MSVC/WIN32
#--------------------------------------------------------------------------
WIN32_EXECUTABLE TRUE # GUI application instead of console application
VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
VS_DPI_AWARE "PerMonitor"
#--------------------------------------------------------------------------
# APPLE
#--------------------------------------------------------------------------
# Build it as an .app bundle
MACOSX_BUNDLE TRUE
# Set up Info.plist values
MACOSX_BUNDLE_ICON_FILE "app.icns" # CFBundleIconFile
MACOSX_BUNDLE_EXECUTABLE_NAME "${GAME_TARGET}" # CFBundleExecutable - executable name inside the bundle
MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION}" # CFBundleShortVersionString
MACOSX_BUNDLE_COPYRIGHT "${GAME_MAC_COPYRIGHT}" # NSHumanReadableCopyright (supersedes CFBundleGetInfoString (MACOSX_BUNDLE_INFO_STRING))
MACOSX_BUNDLE_BUNDLE_NAME "${GAME_FRIENDLY_NAME}" # CFBundleName - user-visible short name for the bundle
MACOSX_BUNDLE_GUI_IDENTIFIER "${GAME_BUNDLE_ID}" # CFBundleIdentifier - unique bundle ID in reverse-DNS format
# Set framework search path to (App bundle)/Contents/Frameworks so the game can use its embedded SDL2.framework
XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/../Frameworks"
# If CODE_SIGN_IDENTITY is NOT empty: tell Xcode to codesign the app properly
# Otherwise, if it's empty: explicitly turn off code signing, otherwise downloaded app will be quarantined forever
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "${CODE_SIGN_IDENTITY}"
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY[variant=Debug] "" # don't bother signing debug build
# Bundle ID required for code signing - must match CFBundleIdentifier otherwise xcode will complain
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER ${GAME_BUNDLE_ID}
# Don't bother with universal builds when we're working on the debug version
XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH[variant=Debug] "YES"
XCODE_EMBED_FRAMEWORKS "${SDL2_FRAMEWORK_PATH}"
XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY "YES" # frameworks must be signed by the same developer as the binary
XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY "YES" # not strictly necessary, but that's cleaner
XCODE_ATTRIBUTE_COPY_PHASE_STRIP[variant=Debug] "NO" # avoid "skipping copy phase strip" warning while working on Debug config
# The following is to pass notarization requirements
XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME "YES"
XCODE_ATTRIBUTE_CODE_SIGN_INJECT_BASE_ENTITLEMENTS "NO"
XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS "--options=runtime --timestamp"
)
#------------------------------------------------------------------------------
# COMPILER/LINKER OPTIONS
#------------------------------------------------------------------------------
add_compile_definitions(
"$<$<CONFIG:DEBUG>:_DEBUG>"
)
if(NOT MSVC)
target_compile_options(${GAME_TARGET} PRIVATE
-Wall
-Wextra
#-Wshadow # Note: Candy Crisis goes crazy with shadowing
-Werror=return-type
-Wstrict-aliasing=2
-Wno-multichar
)
# Sanitizers in debug mode (Linux only)
# When using a debugger, you should export LSAN_OPTIONS=detect_leaks=0
if(SANITIZE)
list(INSERT GAME_LIBRARIES 0 asan ubsan)
target_compile_options(${GAME_TARGET} PRIVATE
-fsanitize=alignment
-fsanitize=address
-fsanitize=leak
-fsanitize=undefined
-fno-omit-frame-pointer
)
endif()
else()
# On Win32, we need NOGDI and NOUSER to be able to define some Mac functions
# whose names are otherwise taken by Windows APIs.
target_compile_definitions(${GAME_TARGET} PRIVATE
WIN32_LEAN_AND_MEAN
_CRT_SECURE_NO_WARNINGS # quit whining about snprintf_s
)
target_compile_options(${GAME_TARGET} PRIVATE
/W4
/wd5105 # see https://developercommunity.visualstudio.com/t/1249671
/we4013 # treat warning as error: undefined function (assuming extern returning int)
/MP # multiprocessor build
/Zi # output info to PDB
)
# Let executable be debugged with PDB, even in Release builds
target_link_options(${GAME_TARGET} PRIVATE /DEBUG)
# Enable console for debug builds
set_target_properties(${GAME_TARGET} PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE")
set_target_properties(${GAME_TARGET} PROPERTIES COMPILE_DEFINITIONS_DEBUG "_CONSOLE")
endif()
#------------------------------------------------------------------------------
# LINK LIBRARIES
#------------------------------------------------------------------------------
# Explicitly link math lib on Linux
if(NOT APPLE AND NOT WIN32)
target_link_libraries(${GAME_TARGET} PRIVATE m)
endif()
# SDL2::SDL2main may or may not be available. It is e.g. required by Windows GUI applications
if(TARGET SDL2::SDL2main)
# It has an implicit dependency on SDL2 functions, so it MUST be added before SDL2::SDL2 (or SDL2::SDL2-static)
target_link_libraries(${GAME_TARGET} PRIVATE SDL2::SDL2main)
endif()
if(NOT STATIC_SDL)
target_link_libraries(${GAME_TARGET} PRIVATE SDL2::SDL2)
else()
target_link_libraries(${GAME_TARGET} PRIVATE SDL2::SDL2-static)
endif()
#------------------------------------------------------------------------------
# COPY ASSETS
#------------------------------------------------------------------------------
if(APPLE)
set(GAME_DATA_TARGET_LOCATION "$<TARGET_FILE_DIR:${GAME_TARGET}>/../Resources")
else()
set(GAME_DATA_TARGET_LOCATION "$<TARGET_FILE_DIR:${GAME_TARGET}>/${GAME_DATA_DIR}")
endif()
add_custom_command(TARGET ${GAME_TARGET} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/${GAME_DATA_DIR}" "${GAME_DATA_TARGET_LOCATION}")
# Copy SDL2 DLL for convenience (WARNING: TARGET_RUNTIME_DLLS requires CMake 3.21, so this copy command was separated from the command above.)
if(WIN32)
add_custom_command(TARGET ${GAME_TARGET} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_RUNTIME_DLLS:${GAME_TARGET}> $<TARGET_FILE_DIR:${GAME_TARGET}>)
endif()
#------------------------------------------------------------------------------
# INSTALL
#------------------------------------------------------------------------------
# Install Windows-specific libraries (cmake --install): copy Visual Studio redistributable DLLs to install location
if(WIN32)
include(InstallRequiredSystemLibraries)
elseif(APPLE)
# no-op
else()
install(TARGETS ${GAME_TARGET} DESTINATION bin)
install(FILES ${CMAKE_SOURCE_DIR}/packaging/${GAME_TARGET}.desktop DESTINATION share/applications/)
install(FILES ${CMAKE_SOURCE_DIR}/packaging/${GAME_TARGET}.png DESTINATION share/icons/hicolor/128x128/apps/)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/${GAME_DATA_DIR}/ DESTINATION share/${GAME_TARGET}/)
endif()