cmake_minimum_required(VERSION 3.21) project(townengine LANGUAGES C) list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # dependencies find_package(SDL2 REQUIRED GLOBAL) find_package(SDL2_image REQUIRED GLOBAL) find_package(SDL2_ttf REQUIRED GLOBAL) if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Debug) endif () set(TOWNENGINE_TARGET townengine CACHE INTERNAL "") set(TOWNENGINE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "") option(TOWNENGINE_HOT_RELOAD "Enable hot reloading support" TRUE) add_compile_options($<$:-fPIC>) set(PHYSFS_BUILD_SHARED FALSE) set(PHYSFS_DISABLE_INSTALL TRUE) set(PHYSFS_TARGETNAME_UNINSTALL "physfs_uninstall") set(PHYSFS_ARCHIVE_GRP OFF) set(PHYSFS_ARCHIVE_WAD OFF) set(PHYSFS_ARCHIVE_HOG OFF) set(PHYSFS_ARCHIVE_MVL OFF) set(PHYSFS_ARCHIVE_QPAK OFF) set(PHYSFS_ARCHIVE_SLB OFF) set(PHYSFS_ARCHIVE_ISO9660 OFF) set(PHYSFS_ARCHIVE_VDF OFF) add_subdirectory(third-party/physfs) add_subdirectory(third-party/libxm) if(UNIX) set(SYSTEM_SOURCE_FILES townengine/system/linux/elf.c) else() set(SYSTEM_SOURCE_FILES) endif() set(TOWNENGINE_SOURCE_FILES third-party/physfs/extras/physfsrwops.c third-party/stb/stb_vorbis.c third-party/glad/src/glad.c townengine/main.c townengine/config.h townengine/context/context.c townengine/context.h townengine/audio/audio.c townengine/audio.h townengine/util.c townengine/util.h townengine/rendering.c townengine/rendering.h townengine/input/input.c townengine/input.h townengine/text.c townengine/text.h townengine/camera.c townengine/camera.h townengine/textures/textures.c ${SYSTEM_SOURCE_FILES}) list(TRANSFORM TOWNENGINE_SOURCE_FILES PREPEND ${TOWNENGINE_DIR}/) # base engine code, reused for games and tools if (TOWNENGINE_HOT_RELOAD) add_library(${TOWNENGINE_TARGET} SHARED ${TOWNENGINE_SOURCE_FILES}) else () add_library(${TOWNENGINE_TARGET} STATIC ${TOWNENGINE_SOURCE_FILES}) endif () source_group(TREE ${TOWNENGINE_DIR} FILES ${TOWNENGINE_SOURCE_FILES}) set_target_properties(${TOWNENGINE_TARGET} PROPERTIES C_STANDARD 11 C_STANDARD_REQUIRED ON C_EXTENSIONS ON) # extensions are required by stb_ds.h target_precompile_headers(${TOWNENGINE_TARGET} PRIVATE third-party/glad/include/glad/glad.h third-party/stb/stb_ds.h) # distribution definitions set(ORGANIZATION_NAME "wanp" CACHE STRING "App developer/publisher's identifier") set(APP_NAME "townengine" CACHE STRING "App identifier") set(PACKAGE_EXTENSION "btw" CACHE STRING "File extension used to look for data archives") function(give_options target) if(MSVC) # close enough i say target_compile_options(${target} PRIVATE /W4 $<$:/GL>) target_link_options(${target} PRIVATE $<$:/LTCG>) else() set(WARNING_FLAGS_CLANG -Weverything -Wno-padded -Wno-declaration-after-statement -Wno-unsafe-buffer-usage -Wno-unused-command-line-argument) set(WARNING_FLAGS -Wall -Wextra -Wpedantic -Wshadow -Wdouble-promotion -Wconversion -Wno-sign-conversion -Werror=vla $<$:-Wcast-align=strict> $<$:${WARNING_FLAGS_CLANG}>) set(BUILD_FLAGS # these SHOULDN'T break anything... -fno-math-errno -ffp-contract=fast -fno-signed-zeros -fno-trapping-math -freciprocal-math -Wl,$<$:-rpath ./>) set(BUILD_FLAGS_RELEASE -O3 -flto -mavx -mavx2 -Wl,--gc-sections -fdata-sections -ffunction-sections -funroll-loops -fomit-frame-pointer $<$:-fallow-store-data-races>) set(BUILD_FLAGS_DEBUG -O0 -g3 -gdwarf -fno-omit-frame-pointer -fstack-protector-all -fsanitize=undefined -fsanitize=address) target_compile_options(${target} PRIVATE ${WARNING_FLAGS} ${BUILD_FLAGS} $<$:${BUILD_FLAGS_RELEASE}> $<$:${BUILD_FLAGS_DEBUG}>) target_link_options(${target} PRIVATE ${BUILD_FLAGS} $<$:${BUILD_FLAGS_RELEASE}> $<$:${BUILD_FLAGS_DEBUG}>) endif() target_compile_definitions(${target} PRIVATE ORGANIZATION_NAME="${ORGANIZATION_NAME}" APP_NAME="${APP_NAME}" PACKAGE_EXTENSION="${PACKAGE_EXTENSION}" $<$:HOT_RELOAD_SUPPORT>) endfunction() function(include_deps target) # header-only libraries should be marked as "system includes" # to suppress compiler warnings in their code (it's not my problem after all) set(THIRD_PARTY_INCLUDES third-party/physfs/src third-party/physfs/extras third-party/libxm/include third-party/glad/include third-party/stb third-party/x-watcher) list(TRANSFORM THIRD_PARTY_INCLUDES PREPEND ${TOWNENGINE_DIR}/) target_include_directories(${target} SYSTEM PRIVATE ${THIRD_PARTY_INCLUDES}) # allow access to headers from any point in source tree target_include_directories(${target} PRIVATE ${TOWNENGINE_DIR}) endfunction() function(link_deps target) target_link_libraries(${target} PUBLIC SDL2::SDL2 SDL2::SDL2main SDL2_image::SDL2_image SDL2_ttf::SDL2_ttf physfs-static xms) endfunction() function(use_townengine target sources output_directory data_dir) if (TOWNENGINE_HOT_RELOAD) # game shared library, for reloading add_library(${target}_game SHARED ${sources}) set_target_properties(${target}_game PROPERTIES OUTPUT_NAME game LIBRARY_OUTPUT_DIRECTORY ${output_directory}) give_options(${target}_game) include_deps(${target}_game) target_link_libraries(${target}_game PUBLIC SDL2::SDL2) # launcher binary, loads game and engine shared library add_executable(${target}_app ${TOWNENGINE_DIR}/townengine/null.c) set_target_properties(${target}_app PROPERTIES OUTPUT_NAME launcher LIBRARY_OUTPUT_DIRECTORY ${output_directory}) # put libtownengine.so alongside the binary set_target_properties(${TOWNENGINE_TARGET} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${output_directory}) else () add_executable(${target}_app ${sources}) endif () # system libraries find_library(MATH_LIBRARY m) if (MATH_LIBRARY) target_link_libraries(${target}_app PUBLIC ${MATH_LIBRARY}) endif () give_options(${target}_app) include_deps(${target}_app) link_deps(${target}_app) target_link_libraries(${target}_app PUBLIC ${TOWNENGINE_TARGET}) set_target_properties(${target}_app PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${output_directory}) # copy dlls for baby windows add_custom_command(TARGET ${target}_app POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy -t $ $ COMMAND_EXPAND_LISTS) if (UNIX) # create a bootstrapping script string(JOIN "\n" TOWNENGINE_BOOTSTRAP "#!/bin/env sh" "cd \"$(dirname \"$0\")\"" "./launcher --data-dir ${data_dir}" "") FILE(GENERATE OUTPUT ${output_directory}/${target} CONTENT "${TOWNENGINE_BOOTSTRAP}" FILE_PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ) endif () endfunction() give_options(${TOWNENGINE_TARGET}) include_deps(${TOWNENGINE_TARGET}) link_deps(${TOWNENGINE_TARGET}) # build the testgame if this cmake list is built directly if (${CMAKE_PROJECT_NAME} MATCHES townengine) add_subdirectory(apps/testgame) endif () # zip up assets # currently, you must run cmake from the project root dir for this to work correctly #file(ARCHIVE_CREATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/data.${PACKAGE_EXTENSION} # PATHS ${PROJECT_SOURCE_DIR}/assets # FORMAT zip #)