Vulkan/CMakeLists.txt
Alexandre 089e7493b6
Some checks failed
Build VulkanEngine / nix (push) Successful in 3m12s
Build VulkanEngine / release (BUNDLE) (push) Failing after 2m13s
Build VulkanEngine / release (PORTABLE) (push) Failing after 2m10s
Build VulkanEngine / notify (push) Successful in 4s
Another attempt
2026-10-09 20:39:35 +02:00

456 lines
15 KiB
CMake

cmake_minimum_required(VERSION 3.25) # Debian 12 ships 3.25
project(VulkanEngine)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake")
include(BuildInfo)
include(FetchContent)
# LTO
include(CheckIPOSupported)
check_ipo_supported(RESULT LTO_SUPPORTED OUTPUT LTO_ERROR)
# ---------------------------------------------------------------------------
# Build modes
# (default) Nix dev build, deps from the Nix shell
# FETCH_DEPS + PORTABLE Single directory, everything static except
# glibc (and the Vulkan loader, loaded via volk)
# FETCH_DEPS + BUNDLE bin/ + lib/, project libs shared in lib/,
# system libstdc++ / libc / loader are used
# ---------------------------------------------------------------------------
option(VULKANENGINE_PORTABLE
"Build a Linux binary without Nix-specific runtime paths (static libs)"
OFF
)
option(VULKANENGINE_BUNDLE
"Build a Linux bundle using libraries from the bundle directory"
OFF
)
option(VULKANENGINE_FETCH_DEPS
"Fetch dependencies with FetchContent instead of using system/Nix packages"
OFF
)
set(VULKANENGINE_PREBUILT_SHADERS "" CACHE PATH
"Directory containing precompiled .spv files (skips glslang/slangc)"
)
if(VULKANENGINE_PORTABLE AND VULKANENGINE_BUNDLE)
message(FATAL_ERROR "VULKANENGINE_PORTABLE and VULKANENGINE_BUNDLE are mutually exclusive")
endif()
if((VULKANENGINE_PORTABLE OR VULKANENGINE_BUNDLE) AND NOT VULKANENGINE_FETCH_DEPS)
message(FATAL_ERROR
"PORTABLE/BUNDLE builds need -DVULKANENGINE_FETCH_DEPS=ON "
"(Nix libraries must not leak into the result)")
endif()
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# RPATH / runtime paths
if(VULKANENGINE_PORTABLE)
message(STATUS "VulkanEngine: PORTABLE build")
set(CMAKE_SKIP_RPATH TRUE)
elseif(VULKANENGINE_BUNDLE)
message(STATUS "VulkanEngine: BUNDLE build")
set(CMAKE_SKIP_BUILD_RPATH FALSE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
# Executables are installed in bin/
# Libraries are installed in lib/
set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib")
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
# Every shared lib we build ends up here, installed as-is into lib/
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
else()
message(STATUS "VulkanEngine: normal build")
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
find_program(GCC_AR NAMES gcc-ar REQUIRED)
find_program(GCC_RANLIB NAMES gcc-ranlib REQUIRED)
set(CMAKE_AR "${GCC_AR}")
set(CMAKE_RANLIB "${GCC_RANLIB}")
endif()
# ---------------------------------------------------------------------------
# Dependencies
# ---------------------------------------------------------------------------
set(ENGINE_EXTRA_DEFINITIONS "")
if(VULKANENGINE_FETCH_DEPS)
# Portable = static libs, bundle = shared libs (in lib/)
if(VULKANENGINE_BUNDLE)
set(BUILD_SHARED_LIBS ON)
else()
set(BUILD_SHARED_LIBS OFF)
endif()
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(VULKAN_HEADERS_ENABLE_MODULE OFF CACHE BOOL "" FORCE)
set(VULKAN_HEADERS_ENABLE_TESTS OFF CACHE BOOL "" FORCE)
set(VULKAN_HEADERS_ENABLE_INSTALL OFF CACHE BOOL "" FORCE)
set(VOLK_PULL_IN_VULKAN OFF CACHE BOOL "" FORCE)
set(VOLK_INSTALL OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE)
set(GLFW_INSTALL OFF CACHE BOOL "" FORCE)
set(FMT_INSTALL OFF CACHE BOOL "" FORCE)
set(FMT_TEST OFF CACHE BOOL "" FORCE)
set(SIMDJSON_DEVELOPER_MODE OFF CACHE BOOL "" FORCE)
set(CLI11_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(CLI11_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
set(GLM_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(GLM_BUILD_LIBRARY OFF CACHE BOOL "" FORCE)
# Keep these versions in sync with your nixpkgs (check the tags exist)
FetchContent_Declare(VulkanHeaders
GIT_REPOSITORY https://github.com/KhronosGroup/Vulkan-Headers.git
GIT_TAG v1.4.309)
FetchContent_Declare(volk
GIT_REPOSITORY https://github.com/zeux/volk.git
GIT_TAG 1.4.304)
FetchContent_Declare(VMA
GIT_REPOSITORY https://github.com/GPUOpen-LibrariesAndPatches/VulkanMemoryAllocator.git
GIT_TAG v3.2.1)
FetchContent_Declare(glfw
GIT_REPOSITORY https://github.com/glfw/glfw.git
GIT_TAG 3.4)
FetchContent_Declare(vk-bootstrap
GIT_REPOSITORY https://github.com/charles-lunarg/vk-bootstrap.git
GIT_TAG v1.4.309)
FetchContent_Declare(fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
GIT_TAG 11.0.2)
FetchContent_Declare(CLI11
GIT_REPOSITORY https://github.com/CLIUtils/CLI11.git
GIT_TAG v2.4.2)
FetchContent_Declare(glm
GIT_REPOSITORY https://github.com/g-truc/glm.git
GIT_TAG 1.0.1)
FetchContent_Declare(simdjson
GIT_REPOSITORY https://github.com/simdjson/simdjson.git
GIT_TAG v3.10.1)
# Vulkan headers first: vk-bootstrap and volk pick up Vulkan::Headers
FetchContent_MakeAvailable(VulkanHeaders)
FetchContent_MakeAvailable(volk VMA glfw vk-bootstrap fmt CLI11 glm simdjson)
target_link_libraries(volk PUBLIC Vulkan::Headers)
# No link-time dependency on libvulkan: functions come from volk
list(APPEND ENGINE_EXTRA_DEFINITIONS
VK_NO_PROTOTYPES
VMA_STATIC_VULKAN_FUNCTIONS=0
VMA_DYNAMIC_VULKAN_FUNCTIONS=1
)
else()
# Nix path (unchanged)
find_package( glfw3 REQUIRED )
find_package( glm REQUIRED )
find_package( VulkanMemoryAllocator CONFIG REQUIRED )
find_package( CLI11 REQUIRED )
find_package( simdjson REQUIRED )
endif()
# fastgltf because it's not in nixpkgs (declared after the switch above so it
# inherits BUILD_SHARED_LIBS)
FetchContent_Declare(
fastgltf
GIT_REPOSITORY https://github.com/spnda/fastgltf.git
GIT_TAG v0.8.0
)
FetchContent_MakeAvailable(fastgltf)
# ---------------------------------------------------------------------------
# Shader compilers (not needed when precompiled shaders are provided)
# ---------------------------------------------------------------------------
if(NOT VULKANENGINE_PREBUILT_SHADERS)
add_executable (glslang::validator IMPORTED)
find_program (
GLSLANG_VALIDATOR
"glslangValidator"
HINTS $ENV{VULKAN_SDK}/bin
REQUIRED
)
set_property (
TARGET glslang::validator
PROPERTY IMPORTED_LOCATION "${GLSLANG_VALIDATOR}"
)
find_program(SLANGC_EXECUTABLE slangc HINTS $ENV{VULKAN_SDK}/bin REQUIRED)
endif()
# Helper functions to build shaders
function(addGlslShader SOURCE OUTPUT_DIR)
get_filename_component(SHADER_NAME ${SOURCE} NAME_WE)
set(SPV_FILE "${OUTPUT_DIR}/${SHADER_NAME}.spv")
add_custom_command(
OUTPUT ${SPV_FILE}
COMMAND ${CMAKE_COMMAND} -E make_directory ${OUTPUT_DIR}
COMMAND glslang::validator
-V
--target-env vulkan1.4 # Change if needed
-o ${SPV_FILE}
${SOURCE}
DEPENDS ${SOURCE}
COMMENT "Compiling GLSL shader: ${SOURCE} -> ${SPV_FILE}"
VERBATIM
)
set(SPV_FILE ${SPV_FILE} PARENT_SCOPE)
endfunction()
function(addSlangShader SOURCES ENTRY_POINTS OUTPUT_DIR)
set(SPV_FILE "${OUTPUT_DIR}/slang.spv")
add_custom_command(
OUTPUT ${SPV_FILE}
COMMAND ${CMAKE_COMMAND} -E make_directory ${OUTPUT_DIR}
COMMAND ${SLANGC_EXECUTABLE}
${SOURCES}
-target spirv
-profile spirv_1_6+spvRayQueryKHR # Change if needed
-emit-spirv-directly
-fvk-use-entrypoint-name
${ENTRY_POINTS}
-o ${SPV_FILE}
DEPENDS ${SOURCES}
COMMENT "Compiling Slang shaders -> ${SPV_FILE}"
VERBATIM
)
set(SPV_FILE ${SPV_FILE} PARENT_SCOPE)
endfunction()
# A function to automate executables aditions
function ( addBinary BINARY_NAME )
cmake_parse_arguments ( BINARY "IMGUI;LICENSE" "SOURCE" "SHADERS;SLANG_SHADERS;SLANG_ENTRIES;LIBS;TEXTURES;MODELS" ${ARGN} )
if (DEFINED BINARY_SOURCE)
add_executable ( ${BINARY_NAME} src/${BINARY_SOURCE}.cpp )
endif()
target_include_directories( ${BINARY_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/src )
# Sets the output dir to have clear separation between binaries
set_target_properties (
${BINARY_NAME}
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/${BINARY_NAME}
CXX_STANDARD
20 # C++ 20
CXX_STANDARD_REQUIRED
ON
CXX_EXTENSIONS
OFF
CXX_SCAN_FOR_MODULES
OFF
)
# Sets per binary LTO
if(LTO_SUPPORTED AND CMAKE_BUILD_TYPE STREQUAL "Release")
set_target_properties(${BINARY_NAME} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
message("Enabled LTO")
endif()
# Portable: libstdc++/libgcc statically linked so the binary does not depend
# on the host's version. NOT done for bundle: the shared libs in lib/ use the
# system libstdc++, and mixing two copies in one process is asking for trouble.
if(VULKANENGINE_PORTABLE)
target_link_options(${BINARY_NAME} PRIVATE -static-libstdc++ -static-libgcc)
endif()
# Define VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS to treat VK_ERROR_OUT_OF_DATE_KHR as a success code
target_compile_definitions (
${BINARY_NAME}
PRIVATE
"VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS"
$<$<CONFIG:Debug>:DEBUG> # So CMAKE expose a #define DEBUG for debug builds
# Exposes versions
BUILD_ID="${ENGINE_VERSION}"
${ENGINE_EXTRA_DEFINITIONS}
)
if(BINARY_IMGUI)
target_include_directories(${BINARY_NAME} PRIVATE
${CMAKE_SOURCE_DIR}/include/imgui
${CMAKE_SOURCE_DIR}/include/imgui/backends
)
target_sources(${BINARY_NAME} PRIVATE
${CMAKE_SOURCE_DIR}/include/imgui/imgui.cpp
${CMAKE_SOURCE_DIR}/include/imgui/imgui_draw.cpp
${CMAKE_SOURCE_DIR}/include/imgui/imgui_tables.cpp
${CMAKE_SOURCE_DIR}/include/imgui/imgui_widgets.cpp
${CMAKE_SOURCE_DIR}/include/imgui/imgui_demo.cpp
#${CMAKE_SOURCE_DIR}/include/imgui/imgui_memory_editor.h
${CMAKE_SOURCE_DIR}/include/imgui/backends/imgui_impl_glfw.cpp
${CMAKE_SOURCE_DIR}/include/imgui/backends/imgui_impl_vulkan.cpp
)
# imgui's Vulkan backend must use volk when there is no linked loader
if(VULKANENGINE_FETCH_DEPS)
target_compile_definitions(${BINARY_NAME} PRIVATE IMGUI_IMPL_VULKAN_USE_VOLK)
endif()
endif()
if(BINARY_LICENSE)
file(COPY ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION ${CMAKE_BINARY_DIR}/${BINARY_NAME})
endif()
if(DEFINED BINARY_SHADERS)
set(SHADER_OUTPUT_DIR ${CMAKE_BINARY_DIR}/${BINARY_NAME}/shaders)
if(VULKANENGINE_PREBUILT_SHADERS)
# Copy the .spv produced by the Nix job instead of compiling them
file(GLOB PREBUILT_SPV CONFIGURE_DEPENDS "${VULKANENGINE_PREBUILT_SHADERS}/*.spv")
if(NOT PREBUILT_SPV)
message(FATAL_ERROR "No .spv found in ${VULKANENGINE_PREBUILT_SHADERS}")
endif()
file(COPY ${PREBUILT_SPV} DESTINATION ${SHADER_OUTPUT_DIR})
else()
set(ALL_SPV_FILES "")
set(EXPANDED_SHADERS "")
foreach(SHADER_PATTERN ${BINARY_SHADERS})
if(SHADER_PATTERN MATCHES "[*?]")
file(GLOB SHADER_FILES CONFIGURE_DEPENDS ${SHADER_PATTERN})
list(APPEND EXPANDED_SHADERS ${SHADER_FILES})
else()
list(APPEND EXPANDED_SHADERS ${SHADER_PATTERN})
endif()
endforeach()
foreach(SHADER_SRC ${EXPANDED_SHADERS})
if(NOT IS_ABSOLUTE ${SHADER_SRC})
set(SHADER_SRC ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER_SRC})
endif()
get_filename_component(EXT ${SHADER_SRC} EXT)
if(EXT STREQUAL ".slang")
addSlangShader(${SHADER_SRC} "${BINARY_SLANG_ENTRIES}" ${SHADER_OUTPUT_DIR})
list(APPEND ALL_SPV_FILES ${SPV_FILE})
else()
addGlslShader(${SHADER_SRC} ${SHADER_OUTPUT_DIR})
list(APPEND ALL_SPV_FILES ${SPV_FILE})
endif()
endforeach()
add_custom_target(shaders_${BINARY_NAME} DEPENDS ${ALL_SPV_FILES})
add_dependencies(${BINARY_NAME} shaders_${BINARY_NAME})
endif()
endif()
if (DEFINED BINARY_LIBS)
target_link_libraries ( ${BINARY_NAME} PRIVATE ${BINARY_LIBS} )
endif()
if (DEFINED BINARY_MODELS) # Adds the 3D models in the binary folder
set(RESOLVED_MODELS "")
foreach(MODEL_PATTERN ${BINARY_MODELS})
file(GLOB MATCHED_MODELS CONFIGURE_DEPENDS
"${CMAKE_SOURCE_DIR}/assets/models/${MODEL_PATTERN}"
)
list(APPEND RESOLVED_MODELS ${MATCHED_MODELS})
endforeach()
if (RESOLVED_MODELS)
file(COPY ${RESOLVED_MODELS} DESTINATION ${CMAKE_BINARY_DIR}/${BINARY_NAME}/models)
endif()
endif()
if (DEFINED BINARY_TEXTURES) # Adds the textures in the binary folder
set(RESOLVED_TEXTURES "")
foreach(TEX_PATTERN ${BINARY_TEXTURES})
file(GLOB MATCHED_TEXTURES CONFIGURE_DEPENDS
"${CMAKE_SOURCE_DIR}/assets/textures/${TEX_PATTERN}"
)
list(APPEND RESOLVED_TEXTURES ${MATCHED_TEXTURES})
endforeach()
if (RESOLVED_TEXTURES)
file(COPY ${RESOLVED_TEXTURES} DESTINATION ${CMAKE_BINARY_DIR}/${BINARY_NAME}/textures)
endif()
endif ()
endfunction()
# ---------------------------------------------------------------------------
# Binaries
# ---------------------------------------------------------------------------
list(
APPEND
lib_list
# Libs used
glfw
fmt
vk-bootstrap
CLI11::CLI11
fastgltf
)
if(VULKANENGINE_FETCH_DEPS)
# No libvulkan at link time: volk loads libvulkan.so.1 at runtime.
# Remove what your code does not use (simdjson, glm...).
list(APPEND lib_list
volk
Vulkan::Headers
GPUOpen::VulkanMemoryAllocator
glm::glm-header-only
simdjson::simdjson
)
else()
list(APPEND lib_list vulkan)
endif()
addBinary (
engine
SOURCE Engine/main
# Flags
IMGUI
LICENSE
SHADERS shaders/*
MODELS *
LIBS ${lib_list}
)
addBinary (
server
SOURCE Server/main
)
# ---------------------------------------------------------------------------
# Install (used for portable / bundle packaging)
# dist/bin/{engine,server,shaders,models,textures}
# dist/lib/*.so* (bundle only)
# dist/LICENSE
# Never bundled: libc, libstdc++, libvulkan, GL, X11, Wayland.
# ---------------------------------------------------------------------------
install(TARGETS engine server RUNTIME DESTINATION bin)
install(DIRECTORY ${CMAKE_BINARY_DIR}/engine/shaders DESTINATION bin OPTIONAL)
install(DIRECTORY ${CMAKE_BINARY_DIR}/engine/models DESTINATION bin OPTIONAL)
install(DIRECTORY ${CMAKE_BINARY_DIR}/engine/textures DESTINATION bin OPTIONAL)
install(FILES ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION .)
if(VULKANENGINE_BUNDLE)
# Every shared lib built from fetched deps (glfw, fmt, fastgltf and its own
# simdjson, ...) with its symlinks. libstdc++ etc. are not built here.
install(DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/
DESTINATION lib
USE_SOURCE_PERMISSIONS
FILES_MATCHING PATTERN "*.so*"
)
endif()