cmake_minimum_required(VERSION 3.6) set(CMAKE_CXX_STANDARD 14) set(CMAKE_C_STANDARD 99) project(Granite LANGUAGES CXX C) if (CMAKE_COMPILER_IS_GNUCXX OR (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")) set(GRANITE_CXX_FLAGS -Wshadow -Wall -Wextra -Wno-comment -Wno-missing-field-initializers -Wno-empty-body) if (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") set(GRANITE_CXX_FLAGS ${GRANITE_CXX_FLAGS} -Wno-backslash-newline-escape) endif() if (NOT (${CMAKE_BUILD_TYPE} MATCHES "Release")) message("Enabling frame pointer for profiling/debug.") set(GRANITE_CXX_FLAGS ${GRANITE_CXX_FLAGS} -fno-omit-frame-pointer) endif() if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)") message("Enabling SSE3 support.") set(GRANITE_CXX_FLAGS ${GRANITE_CXX_FLAGS} -msse3) endif() elseif (MSVC) set(GRANITE_CXX_FLAGS /D_CRT_SECURE_NO_WARNINGS /wd4267 /wd4244 /wd4309 /wd4005 /MP) endif() include(GNUInstallDirs) option(GRANITE_SHARED "Build Granite as a shared library." OFF) option(GRANITE_ISPC_TEXTURE_COMPRESSION "Enable ISPC texture compression" OFF) option(GRANITE_ASTC_ENCODER_COMPRESSION "Enable astc-encoder texture compression" OFF) option(GRANITE_TOOLS "Build Granite tools." ON) option(GRANITE_KHR_DISPLAY_ACQUIRE_XLIB "Try to acquire Xlib display when using VK_KHR_display." OFF) option(GRANITE_ANDROID_APK_FILESYSTEM "Use APK file system for assets and builtin files." ON) option(GRANITE_ANDROID_SWAPPY "Use swappy on Android." OFF) option(GRANITE_SHADER_COMPILER_OPTIMIZE "Optimize SPIR-V." ON) option(GRANITE_VULKAN_SYSTEM_HANDLES "Add system handle support to Vulkan backend." ON) option(GRANITE_RENDERER "Add higher level rendering functionality." ON) option(GRANITE_VULKAN_SPIRV_CROSS "Add reflection support to Vulkan backend." ON) option(GRANITE_VULKAN_SHADER_MANAGER_RUNTIME_COMPILER "Enable Vulkan GLSL runtime compiler." ON) option(GRANITE_VULKAN_FOSSILIZE "Enable support for Fossilize." ON) option(GRANITE_VULKAN_PROFILES "Enable profiles support." OFF) option(GRANITE_VULKAN_DXGI_INTEROP "Enable DXGI interop when running on Windows." ON) option(GRANITE_VULKAN_POST_MORTEM "Add extra support for port-mortem debug." OFF) option(GRANITE_AUDIO "Enable Audio support." OFF) option(GRANITE_PLATFORM "Granite Platform" "SDL") option(GRANITE_HIDDEN "Declare symbols as hidden by default. Useful if you build Granite as a static library and you link to it in your shared library." OFF) option(GRANITE_SANITIZE_ADDRESS "Sanitize address" OFF) option(GRANITE_SANITIZE_THREADS "Sanitize threads" OFF) option(GRANITE_SANITIZE_MEMORY "Sanitize memory" OFF) option(GRANITE_TARGET_NATIVE "Target native arch (-march=native)" OFF) option(GRANITE_BULLET "Enable Bullet support." OFF) option(GRANITE_RENDERDOC_CAPTURE "Enable support for RenderDoc capture from API." ON) option(GRANITE_INSTALL_TARGETS "Add install targets." ON) option(GRANITE_INSTALL_EXE_TARGETS "Add executable install targets." OFF) option(GRANITE_FFMPEG "Enable FFmpeg." OFF) option(GRANITE_FFMPEG_VULKAN "Enable experimental Vulkan HW decode support in FFmpeg." OFF) option(GRANITE_FAST_MATH "Enable fast math." OFF) option(GRANITE_SHIPPING "Disable code paths not related to development." OFF) option(GRANITE_SYSTEM_SDL "Use system SDL3 instead of vendored submodule." OFF) if (GRANITE_FAST_MATH) message("Enabling fast math.") if (CMAKE_COMPILER_IS_GNUCXX OR (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")) set(GRANITE_CXX_FLAGS ${GRANITE_CXX_FLAGS} -ffast-math) elseif (MSVC) set(GRANITE_CXX_FLAGS ${GRANITE_CXX_FLAGS} /fp:fast) endif() else() message("Enabling precise math.") if (MSVC) set(GRANITE_CXX_FLAGS ${GRANITE_CXX_FLAGS} /fp:precise) endif() endif() if (NOT GRANITE_PLATFORM) set(GRANITE_PLATFORM "SDL") endif() if (GRANITE_HIDDEN) if (CMAKE_COMPILER_IS_GNUCXX OR (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden") endif() elseif(${GRANITE_PLATFORM} MATCHES "libretro") if (NOT GRANITE_SHARED) if (CMAKE_COMPILER_IS_GNUCXX OR (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden") endif() endif() endif() if (GRANITE_TARGET_NATIVE) if (CMAKE_COMPILER_IS_GNUCXX OR (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native") endif() endif() set(GRANITE_LINK_FLAGS) if (${CMAKE_VERSION} GREATER "3.13") # Executable targets are not stripped in release mode on Android, do it explicitly. add_link_options($<$,$>:-s>) endif() if (GRANITE_SANITIZE_ADDRESS) set(GRANITE_CXX_FLAGS ${GRANITE_CXX_FLAGS} -fsanitize=address) set(GRANITE_LINK_FLAGS "${GRANITE_LINK_FLAGS} -fsanitize=address") endif() if (GRANITE_SANITIZE_THREADS) set(GRANITE_CXX_FLAGS ${GRANITE_CXX_FLAGS} -fsanitize=thread) set(GRANITE_LINK_FLAGS "${GRANITE_LINK_FLAGS} -fsanitize=thread") endif() if (GRANITE_SANITIZE_MEMORY) set(GRANITE_CXX_FLAGS ${GRANITE_CXX_FLAGS} -fsanitize=memory) set(GRANITE_LINK_FLAGS "${GRANITE_LINK_FLAGS} -fsanitize=memory") endif() if (ANDROID) set(CMAKE_POSITION_INDEPENDENT_CODE ON) endif() if (GRANITE_SHARED) set(CMAKE_POSITION_INDEPENDENT_CODE ON) endif() if (GRANITE_SHARED) set(CMAKE_POSITION_INDEPENDENT_CODE ON) else() if (${GRANITE_PLATFORM} MATCHES "libretro") set(CMAKE_POSITION_INDEPENDENT_CODE ON) elseif (GRANITE_POSITION_INDEPENDENT) set(CMAKE_POSITION_INDEPENDENT_CODE ON) elseif (ANDROID) set(CMAKE_POSITION_INDEPENDENT_CODE ON) else() set(CMAKE_POSITION_INDEPENDENT_CODE OFF) endif() endif() set(GRANITE_VERSION_MAJOR 0) set(GRANITE_VERSION_MINOR 0) set(GRANITE_VERSION_PATCH 0) # Make sure .dlls are placed next to .exe, since there is no RPATH. if (WIN32) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) endif() function(granite_install_executable NAME) install(TARGETS ${NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) if (NOT WIN32) set_target_properties(${NAME} PROPERTIES INSTALL_RPATH "\$ORIGIN/../lib") endif() endfunction() macro(granite_setup_default_link_libraries NAME) if (NOT WIN32) target_link_libraries(${NAME} PRIVATE -pthread dl m) find_library(LIBRT_LIBRARY rt) if (EXISTS ${LIBRT_LIBRARY}) target_link_libraries(${NAME} PUBLIC rt) endif() endif() if (WIN32 AND CMAKE_COMPILER_IS_GNUCXX) target_link_libraries(${NAME} PRIVATE -static gcc stdc++ winpthread) endif() endmacro() function(add_granite_third_party_lib NAME) if (GRANITE_SHARED) add_library(${NAME} SHARED ${ARGN}) if (GRANITE_INSTALL_TARGETS) if (WIN32) install(TARGETS ${NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) else() install(TARGETS ${NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR}) set_target_properties(${NAME} PROPERTIES INSTALL_RPATH "\$ORIGIN/") set_target_properties(${NAME} PROPERTIES VERSION ${GRANITE_VERSION_MAJOR}.${GRANITE_VERSION_MINOR}.${GRANITE_VERSION_PATCH} SOVERSION ${GRANITE_VERSION_MAJOR}) endif() endif() granite_setup_default_link_libraries(${NAME}) if (CMAKE_COMPILER_IS_GNUCXX OR (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")) set_target_properties(${NAME} PROPERTIES LINK_FLAGS "-Wl,--no-undefined") endif() if (MSVC) set_target_properties(${NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON) endif() else() add_library(${NAME} STATIC ${ARGN}) if (MSVC) set_target_properties(${NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS OFF) endif() endif() endfunction() function(add_granite_internal_lib NAME) add_granite_third_party_lib(${NAME} ${ARGN}) target_compile_options(${NAME} PRIVATE ${GRANITE_CXX_FLAGS}) if (GRANITE_SHARED AND MSVC) set_target_properties(${NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON) endif() endfunction() function(add_granite_internal_static_lib NAME) add_library(${NAME} STATIC ${ARGN}) target_compile_options(${NAME} PRIVATE ${GRANITE_CXX_FLAGS}) endfunction() add_subdirectory(third_party) add_subdirectory(util) add_subdirectory(path) add_subdirectory(math) add_subdirectory(threading) add_subdirectory(compiler) add_subdirectory(filesystem) add_subdirectory(vulkan) add_subdirectory(ecs) add_subdirectory(event) if (GRANITE_VULKAN_SYSTEM_HANDLES AND GRANITE_RENDERER) add_subdirectory(renderer) add_subdirectory(ui) add_subdirectory(scene-export) endif() if (GRANITE_FFMPEG) add_subdirectory(video) endif() add_subdirectory(application) if (GRANITE_AUDIO) add_subdirectory(audio) endif() if (GRANITE_BULLET) add_subdirectory(physics) endif() add_library(granite-base INTERFACE) target_link_libraries(granite-base INTERFACE granite-util granite-path granite-application granite-vulkan) if (TARGET granite-renderer) target_link_libraries(granite-base INTERFACE granite-renderer granite-ui) endif() function(add_granite_executable NAME) if (ANDROID) add_library(${NAME} SHARED ${ARGN}) target_link_libraries(${NAME} PRIVATE log android) elseif(${GRANITE_PLATFORM} MATCHES "libretro") add_library(${NAME} SHARED ${ARGN}) if (CMAKE_COMPILER_IS_GNUCXX OR (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")) set_target_properties(${NAME} PROPERTIES LINK_FLAGS "-Wl,--no-undefined") endif() else() add_executable(${NAME} ${ARGN}) endif() # Need this for some reason on OSX. if (APPLE) set_target_properties(${NAME} PROPERTIES LINK_FLAGS "-Wl,-all_load") endif() target_link_libraries(${NAME} PRIVATE granite-base granite-application-global-init) target_compile_options(${NAME} PRIVATE ${GRANITE_CXX_FLAGS}) granite_setup_default_link_libraries(${NAME}) if (GRANITE_SANITIZE_ADDRESS OR GRANITE_SANITIZE_THREADS OR GRANITE_SANITIZE_MEMORY) set_target_properties(${NAME} PROPERTIES LINK_FLAGS "${GRANITE_LINK_FLAGS}") endif() endfunction() function(add_granite_application TARGET_NAME) if (WIN32 AND (NOT ${GRANITE_PLATFORM} MATCHES "libretro")) add_granite_executable(${TARGET_NAME} WIN32 ${ARGN}) else() add_granite_executable(${TARGET_NAME} ${ARGN}) endif() if (ANDROID) target_link_libraries(${TARGET_NAME} PRIVATE granite-base granite-platform) elseif (${GRANITE_PLATFORM} MATCHES "libretro") target_link_libraries(${TARGET_NAME} PRIVATE granite-base granite-platform) else() target_link_libraries(${TARGET_NAME} PRIVATE granite-application-entry) endif() granite_setup_default_link_libraries(${TARGET_NAME}) if (GRANITE_INSTALL_EXE_TARGETS) granite_install_executable(${TARGET_NAME}) endif() endfunction() function(add_granite_headless_application TARGET_NAME) add_executable(${TARGET_NAME} ${ARGN}) target_compile_options(${TARGET_NAME} PRIVATE ${GRANITE_CXX_FLAGS}) if (GRANITE_SANITIZE_ADDRESS OR GRANITE_SANITIZE_THREADS OR GRANITE_SANITIZE_MEMORY) set_target_properties(${TARGET_NAME} PROPERTIES LINK_FLAGS "${GRANITE_LINK_FLAGS}") endif() if (ANDROID) target_link_libraries(${TARGET_NAME} PRIVATE log android) endif() target_link_libraries(${TARGET_NAME} PRIVATE granite-base granite-application-entry-headless) granite_setup_default_link_libraries(${TARGET_NAME}) if (GRANITE_INSTALL_EXE_TARGETS) granite_install_executable(${TARGET_NAME}) endif() endfunction() function(add_granite_offline_tool NAME) add_executable(${NAME} ${ARGN}) target_compile_options(${NAME} PRIVATE ${GRANITE_CXX_FLAGS}) # Need this for some reason on OSX. if (APPLE) set_target_properties(${NAME} PROPERTIES LINK_FLAGS "-Wl,-all_load") endif() target_link_libraries(${NAME} PRIVATE granite-base granite-application-global-init) target_compile_options(${NAME} PRIVATE ${GRANITE_CXX_FLAGS}) if (GRANITE_SANITIZE_ADDRESS OR GRANITE_SANITIZE_THREADS OR GRANITE_SANITIZE_MEMORY) set_target_properties(${NAME} PROPERTIES LINK_FLAGS "${GRANITE_LINK_FLAGS}") endif() granite_setup_default_link_libraries(${NAME}) if (GRANITE_INSTALL_EXE_TARGETS) granite_install_executable(${NAME}) endif() endfunction() if ("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}") set(GRANITE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") else() set(GRANITE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" PARENT_SCOPE) set(GRANITE_CXX_FLAGS ${GRANITE_CXX_FLAGS} PARENT_SCOPE) set(GRANITE_LINK_FLAGS ${GRANITE_LINK_FLAGS} PARENT_SCOPE) endif() function(add_blob_archive_target TARGET_NAME BLOB_NAME) find_package(Python3 REQUIRED) set_source_files_properties( ${CMAKE_BINARY_DIR}/${BLOB_NAME}.h ${CMAKE_BINARY_DIR}/${BLOB_NAME}.c PROPERTIES GENERATED ON) add_library(${TARGET_NAME} STATIC ${CMAKE_BINARY_DIR}/${BLOB_NAME}.h ${CMAKE_BINARY_DIR}/${BLOB_NAME}.c) target_include_directories(${TARGET_NAME} PUBLIC ${CMAKE_BINARY_DIR}) # ... CMake, y u gotta be like this. set(_arg_list) set(_arg_counter 0) foreach(_arg IN LISTS ARGN) math(EXPR _arg_counter_mod "${_arg_counter} % 2") if (NOT ${_arg_counter_mod}) list(APPEND _arg_list --input) endif() list(APPEND _arg_list ${_arg}) math(EXPR _arg_counter "${_arg_counter} + 1") endforeach() add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/${BLOB_NAME}.h ${CMAKE_BINARY_DIR}/${BLOB_NAME}.c COMMAND ${Python3_EXECUTABLE} ${GRANITE_SOURCE_DIR}/tools/blobify.py --output ${CMAKE_BINARY_DIR}/${BLOB_NAME}.blob ${_arg_list} COMMAND ${Python3_EXECUTABLE} ${GRANITE_SOURCE_DIR}/tools/bin_to_text.py --output ${CMAKE_BINARY_DIR}/${BLOB_NAME} --blob-name ${BLOB_NAME} ${CMAKE_BINARY_DIR}/${BLOB_NAME}.blob BYPRODUCTS ${CMAKE_BINARY_DIR}/${BLOB_NAME}.blob) endfunction() if (TARGET granite-renderer) add_subdirectory(tests) add_subdirectory(viewer) if (GRANITE_TOOLS) add_subdirectory(tools) add_subdirectory(renderer/fft/test) endif() endif() if (GRANITE_TOOLS AND GRANITE_VULKAN_SPIRV_CROSS AND GRANITE_VULKAN_SHADER_MANAGER_RUNTIME_COMPILER) add_subdirectory(slangmosh) endif()