From de378f9dfd64e76dbc115a31ad2aaf61a4fc946f Mon Sep 17 00:00:00 2001 From: Andrii Date: Thu, 18 Apr 2024 23:02:24 +0300 Subject: [PATCH] Project setup (#2) * Added git submodules * Added basic project setup * Added cmake configurations * Added scripts for presets generation * Added dummy example to `flux-playground` module --- .clang-format | 30 ++ .gitignore | 125 ++++++ .gitmodules | 23 + CMakeLists.txt | 35 ++ cmake/bootstrap.cmake | 382 ++++++++++++++++ cmake/modules/FindCatch2.cmake | 17 + cmake/modules/Findentt.cmake | 9 + cmake/modules/Findfast_io.cmake | 9 + cmake/modules/Findglad.cmake | 18 + cmake/modules/Findglfw.cmake | 22 + cmake/modules/Findglm.cmake | 8 + cmake/modules/Findimgui.cmake | 26 ++ cmake/project_settings.cmake | 687 +++++++++++++++++++++++++++++ external/Catch2 | 1 + external/entt | 1 + external/fast_io | 1 + external/glad | 1 + external/glfw | 1 + external/glm | 1 + external/imgui | 1 + flux-playground/CMakeLists.txt | 19 + flux-playground/playground.cpp | 108 +++++ scripts/common.sh | 71 +++ scripts/generate-cmake-presets.ps1 | 99 +++++ scripts/generate-cmake-presets.sh | 217 +++++++++ 25 files changed, 1912 insertions(+) create mode 100644 .clang-format create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 CMakeLists.txt create mode 100644 cmake/bootstrap.cmake create mode 100644 cmake/modules/FindCatch2.cmake create mode 100644 cmake/modules/Findentt.cmake create mode 100644 cmake/modules/Findfast_io.cmake create mode 100644 cmake/modules/Findglad.cmake create mode 100644 cmake/modules/Findglfw.cmake create mode 100644 cmake/modules/Findglm.cmake create mode 100644 cmake/modules/Findimgui.cmake create mode 100644 cmake/project_settings.cmake create mode 160000 external/Catch2 create mode 160000 external/entt create mode 160000 external/fast_io create mode 160000 external/glad create mode 160000 external/glfw create mode 160000 external/glm create mode 160000 external/imgui create mode 100644 flux-playground/CMakeLists.txt create mode 100644 flux-playground/playground.cpp create mode 100644 scripts/common.sh create mode 100644 scripts/generate-cmake-presets.ps1 create mode 100644 scripts/generate-cmake-presets.sh diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..170f7c8 --- /dev/null +++ b/.clang-format @@ -0,0 +1,30 @@ + +--- +BasedOnStyle: LLVM +AccessModifierOffset: -4 +ColumnLimit: 100 +ConstructorInitializerIndentWidth: 8 +ContinuationIndentWidth: 8 +IndentPPDirectives: AfterHash +IndentWidth: 4 +PointerAlignment: Left +ReflowComments: true +Standard: c++20 +UseTab: Never +AlignConsecutiveAssignments: Consecutive +AlignConsecutiveBitFields: true +AlignConsecutiveDeclarations: true +AlignConsecutiveMacros: true +AllowShortBlocksOnASingleLine: Empty +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: Empty +AllowShortLoopsOnASingleLine: false +BreakConstructorInitializers: BeforeColon +FixNamespaceComments: true +--- +Language: Cpp +--- +Language: ObjC +ObjCSpaceBeforeProtocolList: false \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a0a4ef6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,125 @@ +#======================================================================================================================= + +# The clangd compilation database. This is a soft link, it's generated automatically during the build. +compile_commands.json + +# The build options used by VSCode (aka CMake Variants). This file is generated by scripts/generate-cmake-variants.sh. +cmake-variants.yaml + +# The build options used by VSCode (aka CMake Presets). This file is generated by scripts/generate-cmake-presets.sh. +CMakePresets.json + +# Build folder used by CI/CD tools. +build/ +build-linux/ +build-windows/ +build-macos/ + +# The cache used by clangd. +.cache/ + +# NOTE: don't commit anything JetBrains IDE-related. We may revisit this in the future. +.idea/ + +# NOTE: not sure which library does this, but something creates the 'deps' folder in our project's root folder. +deps/ + +#======================================================================================================================= +# Visual Studio Code +#======================================================================================================================= + +.vscode/* +# !.vscode/settings.json +# !.vscode/tasks.json +# !.vscode/launch.json +# !.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +#======================================================================================================================= +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 +#======================================================================================================================= + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# CMake +cmake-build-*/ + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +# ImGui files +imgui.ini \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..7a8b0a0 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,23 @@ +[submodule "external/Catch2"] + path = external/Catch2 + url = https://github.com/catchorg/Catch2 + branch = v2.x +[submodule "external/imgui"] + path = external/imgui + url = https://github.com/ocornut/imgui.git + branch = docking +[submodule "external/glfw"] + path = external/glfw + url = https://github.com/glfw/glfw.git +[submodule "external/glad"] + path = external/glad + url = https://github.com/Dav1dde/glad.git +[submodule "external/glm"] + path = external/glm + url = https://github.com/g-truc/glm +[submodule "external/entt"] + path = external/entt + url = https://github.com/skypjack/entt.git +[submodule "external/fast_io"] + path = external/fast_io + url = https://github.com/cppfastio/fast_io.git diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..15caba6 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,35 @@ +cmake_minimum_required(VERSION 3.23) + +project(flux LANGUAGES CXX) + +include("cmake/project_settings.cmake") +include("cmake/bootstrap.cmake") + +#----------------------------------------------------------------------------------------------------------------------- +# Enable code coverage. +#----------------------------------------------------------------------------------------------------------------------- + +option(FLUX_ENABLE_COVERAGE "Enable code coverage" OFF) + +if(FLUX_ENABLE_COVERAGE) + if(CMAKE_CXX_COMPILER_ID MATCHES "^(Apple)?(C|c)?lang$") + string(APPEND CMAKE_C_FLAGS " -O0 -g -fprofile-instr-generate -fcoverage-mapping") + string(APPEND CMAKE_CXX_FLAGS " -O0 -g -fprofile-instr-generate -fcoverage-mapping") + + message(STATUS "Code coverage: ON") + else() + message(ERROR "Code coverage for compiler ${CMAKE_CXX_COMPILER_ID} is unsupported") + endif() +endif() + +#----------------------------------------------------------------------------------------------------------------------- +# Libraries. +#----------------------------------------------------------------------------------------------------------------------- + +#----------------------------------------------------------------------------------------------------------------------- +# Applications. +#----------------------------------------------------------------------------------------------------------------------- + +add_subdirectory("flux-playground") + +# code: language="CMake" insertSpaces=true tabSize=4 \ No newline at end of file diff --git a/cmake/bootstrap.cmake b/cmake/bootstrap.cmake new file mode 100644 index 0000000..6fa077f --- /dev/null +++ b/cmake/bootstrap.cmake @@ -0,0 +1,382 @@ +if($CACHE{FLUX_BOOTSTRAP_DONE}) + return() +endif() + +find_package(Git REQUIRED) + +######################################################################################################################## +# Update submodules. +######################################################################################################################## + +message(" ==============================================================================\n" + " Updating Git submodules, please wait...\n" + " ==============================================================================") +execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + RESULT_VARIABLE COMMAND_RESULT) +if(NOT COMMAND_RESULT EQUAL "0") + message(FATAL_ERROR "Failed to update Git submodules.") +else() + message(STATUS "Git submodules are already up-to-date.") +endif() + +######################################################################################################################## +# CMake arguments that are used to configure thirdparty libraries. +######################################################################################################################## + +set(FLUX_CONFIG_ARGUMENTS + -DCMAKE_GENERATOR=${CMAKE_GENERATOR} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME} + -DCMAKE_SYSTEM_PROCESSOR=${CMAKE_SYSTEM_PROCESSOR} + + -DCMAKE_CXX_STANDARD=23 + + -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} + -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} + + -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} + -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} + + -DCMAKE_C_LINKER_FLAGS=${CMAKE_C_LINKER_FLAGS} + -DCMAKE_CXX_LINKER_FLAGS=${CMAKE_CXX_LINKER_FLAGS} + + -DCMAKE_C_FLAGS_${FLUX_BUILD_TYPE}=${CMAKE_C_FLAGS_${FLUX_BUILD_TYPE}} + -DCMAKE_CXX_FLAGS_${FLUX_BUILD_TYPE}=${CMAKE_CXX_FLAGS_${FLUX_BUILD_TYPE}} +) + +if(FLUX_TARGET_OS STREQUAL "MacOSX") + list(APPEND FLUX_CONFIG_ARGUMENTS "-DCMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES}") + list(APPEND FLUX_CONFIG_ARGUMENTS "-DCMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}") + list(APPEND FLUX_CONFIG_ARGUMENTS "-DCMAKE_OSX_SYSROOT=${CMAKE_OSX_SYSROOT}") + + list(APPEND FLUX_CONFIG_ARGUMENTS "-DCMAKE_OBJC_COMPILER=${CMAKE_OBJC_COMPILER}") + list(APPEND FLUX_CONFIG_ARGUMENTS "-DCMAKE_OBJCXX_COMPILER=${CMAKE_OBJCXX_COMPILER}") + + list(APPEND FLUX_CONFIG_ARGUMENTS "-DCMAKE_OBJC_FLAGS=${CMAKE_OBJC_FLAGS}") + list(APPEND FLUX_CONFIG_ARGUMENTS "-DCMAKE_OBJCXX_FLAGS=${CMAKE_OBJCXX_FLAGS}") + + list(APPEND FLUX_CONFIG_ARGUMENTS "-DCMAKE_OBJC_LINKER_FLAGS=${CMAKE_OBJC_LINKER_FLAGS}") + list(APPEND FLUX_CONFIG_ARGUMENTS "-DCMAKE_OBJCXX_LINKER_FLAGS=${CMAKE_OBJCXX_LINKER_FLAGS}") +endif() + +######################################################################################################################## +# Configure, build, and install Catch2. +######################################################################################################################## + +string(CONCAT FLUX_CATCH2_CONFIG_CONSOLE_WIDTH "${CMAKE_CXX_FLAGS} -DCATCH_CONFIG_CONSOLE_WIDTH=300") + +message(" ==============================================================================\n" + " Configuring Catch2, please wait...\n" + " ==============================================================================") +execute_process(COMMAND ${CMAKE_COMMAND} + -B${CMAKE_BINARY_DIR}/external/Catch2 + -S${CMAKE_SOURCE_DIR}/external/Catch2 + -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/output/external/Catch2 + -DCATCH_BUILD_STATIC_LIBRARY=ON + -DCATCH_BUILD_TESTING=OFF + -DCATCH_INSTALL_DOCS=OFF + -DCATCH_INSTALL_HELPERS=OFF + ${FLUX_CONFIG_ARGUMENTS} + -DCMAKE_CXX_FLAGS=${FLUX_CATCH2_CONFIG_CONSOLE_WIDTH} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + RESULT_VARIABLE COMMAND_RESULT + COMMAND_ECHO STDOUT) +if(NOT COMMAND_RESULT STREQUAL "0") + message(FATAL_ERROR "Failed to configure Catch2.") +endif() + +message(" ==============================================================================\n" + " Building and installing Catch2, please wait...\n" + " ==============================================================================") +execute_process(COMMAND ${CMAKE_COMMAND} + --build ${CMAKE_BINARY_DIR}/external/Catch2 + --target install + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + RESULT_VARIABLE COMMAND_RESULT + COMMAND_ECHO STDOUT) +if(NOT COMMAND_RESULT STREQUAL "0") + message(FATAL_ERROR "Failed to install Catch2.") +endif() + +######################################################################################################################## +# Configure, build, and install fast_io. +######################################################################################################################## + +message(" ==============================================================================\n" + " Configuring fast_io, please wait...\n" + " ==============================================================================") +execute_process(COMMAND ${CMAKE_COMMAND} + -B${CMAKE_BINARY_DIR}/external/fast_io + -S${CMAKE_SOURCE_DIR}/external/fast_io + -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/output/external/fast_io + -DUSE_MSVC_RUNTIME_LIBRARY_DLL=OFF + -DCMAKE_MSVC_RUNTIME_LIBRARY=${FLUX_MSVC_RUNTIME_LIBRARY} + ${FLUX_CONFIG_ARGUMENTS} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + RESULT_VARIABLE COMMAND_RESULT + COMMAND_ECHO STDOUT) +if(NOT COMMAND_RESULT STREQUAL "0") + message(FATAL_ERROR "Failed to configure fast_io.") +endif() + +message(" ==============================================================================\n" + " Building and installing fast_io, please wait...\n" + " ==============================================================================") +execute_process(COMMAND ${CMAKE_COMMAND} + --build ${CMAKE_BINARY_DIR}/external/fast_io + --target install + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + RESULT_VARIABLE COMMAND_RESULT + COMMAND_ECHO STDOUT) +if(NOT COMMAND_RESULT STREQUAL "0") + message(FATAL_ERROR "Failed to install fast_io.") +endif() + +######################################################################################################################## +# Configure, build, and install GLFW. +######################################################################################################################## + +message(" ==============================================================================\n" + " Configuring GLFW, please wait...\n" + " ==============================================================================") +execute_process(COMMAND ${CMAKE_COMMAND} + -B${CMAKE_BINARY_DIR}/external/glfw + -S${CMAKE_SOURCE_DIR}/external/glfw + -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/output/external/glfw + -DENKITS_BUILD_EXAMPLES=OFF + -DGLFW_BUILD_EXAMPLES=OFF + -DGLFW_BUILD_TESTS=OFF + -DGLFW_BUILD_DOCS=OFF + -DGLFW_BUILD_INSTALL=OFF + ${FLUX_CONFIG_ARGUMENTS} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + RESULT_VARIABLE COMMAND_RESULT + COMMAND_ECHO STDOUT) +if(NOT COMMAND_RESULT STREQUAL "0") + message(FATAL_ERROR "Failed to configure GLFW.") +endif() + +message(" ==============================================================================\n" + " Building and installing GLFW, please wait...\n" + " ==============================================================================") +execute_process(COMMAND ${CMAKE_COMMAND} + --build ${CMAKE_BINARY_DIR}/external/glfw + --target install + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + RESULT_VARIABLE COMMAND_RESULT + COMMAND_ECHO STDOUT) +if(NOT COMMAND_RESULT STREQUAL "0") + message(FATAL_ERROR "Failed to install GLFW.") +endif() + +######################################################################################################################## +# Configure, build, and install glad. +######################################################################################################################## + +message(" ==============================================================================\n" + " Generating a project for glad, please wait...\n" + " ==============================================================================") +file(WRITE "${CMAKE_BINARY_DIR}/generated/external/glad2/CMakeLists.txt" +[[cmake_minimum_required(VERSION 3.20) +project(glad2 CXX C) + +set(GLAD_SOURCES_DIR "${GLAD_ROOT}") +add_subdirectory("${GLAD_SOURCES_DIR}/cmake" cmake) + +# This target is OpenGL-specific. +if(FLUX_TARGET_GRAPHICS STREQUAL "OpenGL") + set(GLAD_SPEC gl) + set(GLAD_PROFILE core) + set(GLAD_ARGS MX API ${GLAD_SPEC}:${GLAD_PROFILE}=${FLUX_API_VERSION_MAJOR}.${FLUX_API_VERSION_MINOR}) +# This target is Vulkan-specific. +elseif(FLUX_TARGET_GRAPHICS STREQUAL "Vulkan") + set(GLAD_SPEC vulkan) + set(GLAD_PROFILE core) + set(GLAD_ARGS API ${GLAD_SPEC}=${FLUX_API_VERSION_MAJOR}.${FLUX_API_VERSION_MINOR}) +endif() + +if(FLUX_TARGET_GRAPHICS STREQUAL "Metal") + message(STATUS "Glad2 with Metal backend is not supported. Skipping...") +else() + glad_add_library(glad STATIC REPRODUCIBLE LOCATION ${CMAKE_INSTALL_PREFIX} ${GLAD_ARGS}) + install(TARGETS glad) +endif() +]]) +message(STATUS "GLAD project generation successfully finished.") + +message(" ==============================================================================\n" + " Configuring glad, please wait...\n" + " ==============================================================================") +execute_process(COMMAND ${CMAKE_COMMAND} + -B${CMAKE_BINARY_DIR}/external/glad + -S${CMAKE_BINARY_DIR}/generated/external/glad2 + -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/output/external/glad + -DGLAD_ROOT=${CMAKE_SOURCE_DIR}/external/glad + -DFLUX_TARGET_GRAPHICS=${FLUX_TARGET_GRAPHICS} + -DFLUX_API_VERSION_MAJOR=${FLUX_API_VERSION_MAJOR} + -DFLUX_API_VERSION_MINOR=${FLUX_API_VERSION_MINOR} + ${FLUX_CONFIG_ARGUMENTS} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + RESULT_VARIABLE COMMAND_RESULT + COMMAND_ECHO STDOUT) +if(NOT COMMAND_RESULT STREQUAL "0") + message(FATAL_ERROR "Failed to configure glad.") +endif() + +message(" ==============================================================================\n" + " Building and installing glad, please wait...\n" + " ==============================================================================") +execute_process(COMMAND ${CMAKE_COMMAND} + --build ${CMAKE_BINARY_DIR}/external/glad + --target install + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + RESULT_VARIABLE COMMAND_RESULT + COMMAND_ECHO STDOUT) +if(NOT COMMAND_RESULT STREQUAL "0") + message(FATAL_ERROR "Failed to install glad.") +endif() + +######################################################################################################################## +# Configure, build, and install Dear ImGui library. +######################################################################################################################## + +message(" ==============================================================================\n" + " Generating a project for Dear ImGui, please wait...\n" + " ==============================================================================") +file(WRITE "${CMAKE_BINARY_DIR}/generated/external/imgui/CMakeLists.txt" +[[cmake_minimum_required(VERSION 3.20) +project(imgui CXX) + +add_library(imgui STATIC) +target_include_directories(imgui PRIVATE "${IMGUI_ROOT}") +target_sources(imgui PRIVATE + "${IMGUI_ROOT}/imgui.cpp" + "${IMGUI_ROOT}/imgui_demo.cpp" + "${IMGUI_ROOT}/imgui_draw.cpp" + "${IMGUI_ROOT}/imgui_tables.cpp" + "${IMGUI_ROOT}/imgui_widgets.cpp" + "${IMGUI_ROOT}/misc/cpp/imgui_stdlib.cpp") +set(IMGUI_PUBLIC_HEADERS + "${IMGUI_ROOT}/imgui.h" + "${IMGUI_ROOT}/misc/cpp/imgui_stdlib.h") +set(IMGUI_PRIVATE_HEADERS + "${IMGUI_ROOT}/imconfig.h" + "${IMGUI_ROOT}/imstb_rectpack.h" + "${IMGUI_ROOT}/imstb_textedit.h" + "${IMGUI_ROOT}/imstb_truetype.h") +set_target_properties(imgui PROPERTIES + PUBLIC_HEADER "${IMGUI_PUBLIC_HEADERS}" + PRIVATE_HEADER "${IMGUI_PRIVATE_HEADERS}") +install(TARGETS imgui) + +# This target is OpenGL-specific. +if(FLUX_TARGET_GRAPHICS STREQUAL "OpenGL") + add_library(imgui_opengl STATIC) + target_include_directories(imgui_opengl PRIVATE "${IMGUI_ROOT}" "${GLFW_ROOT}/include") + target_sources(imgui_opengl PRIVATE + "${IMGUI_ROOT}/backends/imgui_impl_glfw.cpp" + "${IMGUI_ROOT}/backends/imgui_impl_opengl3.cpp") + set(IMGUI_OPENGL_PRIVATE_HEADERS + "${IMGUI_ROOT}/backends/imgui_impl_glfw.h" + "${IMGUI_ROOT}/backends/imgui_impl_opengl3.h") + set_target_properties(imgui_opengl PROPERTIES + PRIVATE_HEADER "${IMGUI_OPENGL_PRIVATE_HEADERS}") + install(TARGETS imgui_opengl) +# This target is Metal-specific. +elseif(FLUX_TARGET_GRAPHICS STREQUAL "Metal") + enable_language(OBJCXX) + + add_library(imgui_metal STATIC) + target_include_directories(imgui_metal PRIVATE "${IMGUI_ROOT}") + target_compile_options(imgui_metal PRIVATE -fobjc-arc) + target_sources(imgui_metal PRIVATE + "${IMGUI_ROOT}/backends/imgui_impl_metal.mm" + "${IMGUI_ROOT}/backends/imgui_impl_osx.mm") + set(IMGUI_METAL_PRIVATE_HEADERS + "${IMGUI_ROOT}/backends/imgui_impl_metal.h" + "${IMGUI_ROOT}/backends/imgui_impl_osx.h") + set_target_properties(imgui_metal PROPERTIES + PRIVATE_HEADER "${IMGUI_METAL_PRIVATE_HEADERS}") + target_link_libraries(imgui_metal PRIVATE "-framework Metal" "-framework AppKit") + install(TARGETS imgui_metal) +# This target is Vulkan-specific. +elseif(FLUX_TARGET_GRAPHICS STREQUAL "Vulkan") + message(FATAL_ERROR "ImGui with Vulkan backend is not currently supported.") +endif() +]]) +message(STATUS "Dear ImGui project generation successfully finished.") + +message(" ==============================================================================\n" + " Configuring Dear ImGui, please wait...\n" + " ==============================================================================") +execute_process(COMMAND ${CMAKE_COMMAND} + -B${CMAKE_BINARY_DIR}/external/imgui + -S${CMAKE_BINARY_DIR}/generated/external/imgui + -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/output/external/imgui + -DIMGUI_ROOT=${CMAKE_SOURCE_DIR}/external/imgui + -DGLFW_ROOT=${CMAKE_SOURCE_DIR}/external/glfw + -DFLUX_TARGET_GRAPHICS=${FLUX_TARGET_GRAPHICS} + -DUSE_MSVC_RUNTIME_LIBRARY_DLL=OFF + -DCMAKE_MSVC_RUNTIME_LIBRARY=${FLUX_MSVC_RUNTIME_LIBRARY} + ${FLUX_CONFIG_ARGUMENTS} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + RESULT_VARIABLE COMMAND_RESULT + COMMAND_ECHO STDOUT) +if(NOT COMMAND_RESULT STREQUAL "0") + message(FATAL_ERROR "Failed to configure Dear ImGui.") +endif() + +message(" ==============================================================================\n" + " Building and installing Dear ImGui, please wait...\n" + " ==============================================================================") +execute_process(COMMAND ${CMAKE_COMMAND} + --build ${CMAKE_BINARY_DIR}/external/imgui + --target install + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + RESULT_VARIABLE COMMAND_RESULT + COMMAND_ECHO STDOUT) +if(NOT COMMAND_RESULT STREQUAL "0") + message(FATAL_ERROR "Failed to install Dear ImGui.") +endif() + + +######################################################################################################################## +# Configure, build, and install entt. +######################################################################################################################## + +message(" ==============================================================================\n" + " Configuring entt, please wait...\n" + " ==============================================================================") +execute_process(COMMAND ${CMAKE_COMMAND} + -B${CMAKE_BINARY_DIR}/external/entt + -S${CMAKE_SOURCE_DIR}/external/entt + -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/output/external/entt + ${FLUX_CONFIG_ARGUMENTS} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + RESULT_VARIABLE COMMAND_RESULT + COMMAND_ECHO STDOUT) +if(NOT COMMAND_RESULT STREQUAL "0") + message(FATAL_ERROR "Failed to configure entt.") +endif() + +message(" ==============================================================================\n" + " Building and installing entt, please wait...\n" + " ==============================================================================") +execute_process(COMMAND ${CMAKE_COMMAND} + --build ${CMAKE_BINARY_DIR}/external/entt + --target install + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + RESULT_VARIABLE COMMAND_RESULT + COMMAND_ECHO STDOUT) +if(NOT COMMAND_RESULT STREQUAL "0") + message(FATAL_ERROR "Failed to install entt.") +endif() + +######################################################################################################################## +# Update CMakeCache.txt +######################################################################################################################## + +set(FLUX_BOOTSTRAP_DONE TRUE CACHE BOOL "Whether the bootstrapping has been done." FORCE) + +# code: language='CMake' insertSpaces=true tabSize=4 \ No newline at end of file diff --git a/cmake/modules/FindCatch2.cmake b/cmake/modules/FindCatch2.cmake new file mode 100644 index 0000000..4041aa9 --- /dev/null +++ b/cmake/modules/FindCatch2.cmake @@ -0,0 +1,17 @@ +if(TARGET Catch2::Catch2) + return() +endif() +add_library(Catch2::Catch2 INTERFACE IMPORTED) + +if(FLUX_TARGET_OS STREQUAL "Windows") + target_link_libraries(Catch2::Catch2 + INTERFACE "${CMAKE_BINARY_DIR}/output/external/Catch2/lib/Catch2WithMain.lib") +elseif(FLUX_TARGET_OS STREQUAL "MacOSX" OR FLUX_TARGET_OS STREQUAL "Linux") + target_link_libraries(Catch2::Catch2 + INTERFACE "${CMAKE_BINARY_DIR}/output/external/Catch2/lib/libCatch2WithMain.a") +endif() + +target_include_directories(Catch2::Catch2 + INTERFACE "${CMAKE_BINARY_DIR}/output/external/Catch2/include") + +# code: language="CMake" insertSpaces=true tabSize=4 \ No newline at end of file diff --git a/cmake/modules/Findentt.cmake b/cmake/modules/Findentt.cmake new file mode 100644 index 0000000..9b0aa2b --- /dev/null +++ b/cmake/modules/Findentt.cmake @@ -0,0 +1,9 @@ +if(TARGET entt::entt) + return() +endif() +add_library(entt::entt INTERFACE IMPORTED) + +target_include_directories(entt::entt + INTERFACE "${CMAKE_BINARY_DIR}/output/external/entt/include") + +# code: language="CMake" insertSpaces=true tabSize=4 \ No newline at end of file diff --git a/cmake/modules/Findfast_io.cmake b/cmake/modules/Findfast_io.cmake new file mode 100644 index 0000000..cc322ef --- /dev/null +++ b/cmake/modules/Findfast_io.cmake @@ -0,0 +1,9 @@ +if(TARGET fast_io::fast_io) + return() +endif() +add_library(fast_io::fast_io INTERFACE IMPORTED) + +target_include_directories(fast_io::fast_io + INTERFACE "${CMAKE_BINARY_DIR}/output/external/fast_io/include") + +# code: language="CMake" insertSpaces=true tabSize=4 \ No newline at end of file diff --git a/cmake/modules/Findglad.cmake b/cmake/modules/Findglad.cmake new file mode 100644 index 0000000..8d4770f --- /dev/null +++ b/cmake/modules/Findglad.cmake @@ -0,0 +1,18 @@ +if(TARGET glad::glad) + return() +endif() + +if(FLUX_TARGET_GRAPHICS STREQUAL "OpenGL") + add_library(glad::glad INTERFACE IMPORTED) + if(FLUX_TARGET_OS STREQUAL "Windows") + target_link_libraries(glad::glad + INTERFACE "${CMAKE_BINARY_DIR}/output/external/glad/lib/glad.lib") + elseif(FLUX_TARGET_OS STREQUAL "MacOSX" OR FLUX_TARGET_OS STREQUAL "Linux") + target_link_libraries(glad::glad + INTERFACE "${CMAKE_BINARY_DIR}/output/external/glad/lib/libglad.a") + endif() + target_include_directories(glad::glad + INTERFACE "${CMAKE_BINARY_DIR}/output/external/glad/include") +endif() + +# code: language="CMake" insertSpaces=true tabSize=4 \ No newline at end of file diff --git a/cmake/modules/Findglfw.cmake b/cmake/modules/Findglfw.cmake new file mode 100644 index 0000000..8cddc3e --- /dev/null +++ b/cmake/modules/Findglfw.cmake @@ -0,0 +1,22 @@ +if(TARGET glfw::glfw) + return() +endif() + +if(FLUX_TARGET_GRAPHICS STREQUAL "OpenGL") + add_library(glfw::glfw INTERFACE IMPORTED) + if(FLUX_TARGET_OS STREQUAL "Windows") + target_link_libraries(glfw::glfw + INTERFACE "${CMAKE_BINARY_DIR}/output/external/glfw/lib/glfw3.lib") + elseif(FLUX_TARGET_OS STREQUAL "MacOSX") + target_link_libraries(glfw::glfw INTERFACE "-framework Cocoa" "-framework IOKit") + target_link_libraries(glfw::glfw + INTERFACE "${CMAKE_BINARY_DIR}/output/external/glfw/lib/libglfw3.a") + elseif(FLUX_TARGET_OS STREQUAL "Linux") + target_link_libraries(glfw::glfw + INTERFACE "${CMAKE_BINARY_DIR}/output/external/glfw/lib/libglfw3.a") + endif() + target_link_libraries(glfw::glfw INTERFACE ${GLFW_LIBRARIES}) + target_include_directories(glfw::glfw INTERFACE "${CMAKE_BINARY_DIR}/output/external/glfw/include") +endif() + +# code: language="CMake" insertSpaces=true tabSize=4 \ No newline at end of file diff --git a/cmake/modules/Findglm.cmake b/cmake/modules/Findglm.cmake new file mode 100644 index 0000000..b45ce7e --- /dev/null +++ b/cmake/modules/Findglm.cmake @@ -0,0 +1,8 @@ +if(TARGET glm::glm) + return() +endif() +add_library(glm::glm INTERFACE IMPORTED) +target_include_directories(glm::glm + INTERFACE "${CMAKE_SOURCE_DIR}/external/glm") + +# code: language="CMake" insertSpaces=true tabSize=4 \ No newline at end of file diff --git a/cmake/modules/Findimgui.cmake b/cmake/modules/Findimgui.cmake new file mode 100644 index 0000000..b46f548 --- /dev/null +++ b/cmake/modules/Findimgui.cmake @@ -0,0 +1,26 @@ +if(TARGET imgui::imgui) + return() +endif() +add_library(imgui::imgui INTERFACE IMPORTED) +if(FLUX_TARGET_GRAPHICS STREQUAL "OpenGL") + if(FLUX_TARGET_OS STREQUAL "Windows") + target_link_libraries(imgui::imgui + INTERFACE "${CMAKE_BINARY_DIR}/output/external/imgui/lib/imgui.lib" + "${CMAKE_BINARY_DIR}/output/external/imgui/lib/imgui_opengl.lib") + elseif(FLUX_TARGET_OS STREQUAL "MacOSX" OR FLUX_TARGET_OS STREQUAL "Linux") + target_link_libraries(imgui::imgui + INTERFACE "${CMAKE_BINARY_DIR}/output/external/imgui/lib/libimgui.a" + "${CMAKE_BINARY_DIR}/output/external/imgui/lib/libimgui_opengl.a") + endif() +elseif(FLUX_TARGET_GRAPHICS STREQUAL "Metal") + if(FLUX_TARGET_OS STREQUAL "MacOSX") + target_compile_options(imgui::imgui INTERFACE "-fobjc-arc") + target_link_libraries(imgui::imgui INTERFACE "-framework Metal" "-framework AppKit") + target_link_libraries(imgui::imgui + INTERFACE "${CMAKE_BINARY_DIR}/output/external/imgui/lib/libimgui.a" + "${CMAKE_BINARY_DIR}/output/external/imgui/lib/libimgui_metal.a") + endif() +endif() +target_include_directories(imgui::imgui INTERFACE "${CMAKE_BINARY_DIR}/output/external/imgui/include") + +# code: language="CMake" insertSpaces=true tabSize=4 \ No newline at end of file diff --git a/cmake/project_settings.cmake b/cmake/project_settings.cmake new file mode 100644 index 0000000..04bb1bd --- /dev/null +++ b/cmake/project_settings.cmake @@ -0,0 +1,687 @@ +include(CTest) +include(CheckLanguage) + +check_language(OBJC) +if(CMAKE_OBJC_COMPILER) + enable_language(OBJC) + string(APPEND CMAKE_OBJC_FLAGS " -fobjc-arc -std=gnu11") +endif() + +check_language(OBJCXX) +if(CMAKE_OBJCXX_COMPILER) + enable_language(OBJCXX) + string(APPEND CMAKE_OBJCXX_FLAGS " -fobjc-arc -std=gnu++23") +endif() + +add_library(flux::project_settings INTERFACE IMPORTED) + +target_compile_features(flux::project_settings INTERFACE cxx_std_23) + +# Enable output of compile commands during generation. This file will be used by clangd. +if(NOT DEFINED CMAKE_EXPORT_COMPILE_COMMANDS AND NOT DEFINED ENV{CMAKE_EXPORT_COMPILE_COMMANDS}) + set(CMAKE_EXPORT_COMPILE_COMMANDS "ON" CACHE BOOL "Enable/Disable output of compile commands during generation.") + mark_as_advanced(CMAKE_EXPORT_COMPILE_COMMANDS) + + message(STATUS "CMAKE_EXPORT_COMPILE_COMMANDS: ${CMAKE_EXPORT_COMPILE_COMMANDS}") +endif() + +# Let CMake know where to find custom modules. +list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules) + +#----------------------------------------------------------------------------------------------------------------------- +# Detect and initialize the target platform. +#----------------------------------------------------------------------------------------------------------------------- + +# This function is required to get the correct target architecture because the CMAKE_SYSTEM_PROCESSOR +# variable does not always guarantee that it will correspond to the target architecture for the build. +# See: https://cmake.org/cmake/help/latest/variable/CMAKE_SYSTEM_PROCESSOR.html +function(flux_set_target_architecture _OUT) + # On MacOSX we use `CMAKE_OSX_ARCHITECTURES` *if* it was set. + if(APPLE AND CMAKE_OSX_ARCHITECTURES) + list(LENGTH CMAKE_OSX_ARCHITECTURES _ARCH_COUNT) + if(_ARCH_COUNT STREQUAL "1") + if(CMAKE_OSX_ARCHITECTURES STREQUAL "x86_64") + set(_FLUX_TARGET_ARCH "x86_64" CACHE STRING "The target architecture." FORCE) + elseif(CMAKE_OSX_ARCHITECTURES STREQUAL "arm64") + set(_FLUX_TARGET_ARCH "arm64" CACHE STRING "The target architecture." FORCE) + else() + message(FATAL_ERROR "Invalid target architecture. Flux Engine only supports 64-bit architecture.") + endif() + else() + message(FATAL_ERROR "Incorrectly initialized CMAKE_OSX_ARCHITECTURES variable.\n" + "Do not target multiple architectures at once.") + endif() + else() + file(WRITE "${CMAKE_BINARY_DIR}/generated/arch/detect_arch.c" + [[#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64) + # error TARGET_ARCH x86_64 + #if defined(__arm64) || defined(_M_ARM64) || defined(__aarch64__) || defined(__AARCH64EL__) + # error TARGET_ARCH arm64 + #endif + #error TARGET_ARCH unsupported + ]]) + + enable_language(C) + + # Detect the architecture in a rather creative way... + # This compiles a small C program which is a series of `#ifdefs` that selects a particular `#error` + # preprocessor directive whose message string contains the target architecture. The program will + # always fail to compile (both because the file is not a valid C program, and obviously because of the + # presence of the `#error` preprocessor directives... but by exploiting the preprocessor in this way, + # we can detect the correct target architecture even when cross-compiling, since the program itself + # never needs to be run (only the compiler/preprocessor). + try_run( + run_result_unused + compile_result_unused + "${CMAKE_BINARY_DIR}" + "${CMAKE_BINARY_DIR}/generated/arch/detect_arch.c" + COMPILE_OUTPUT_VARIABLE _FLUX_TARGET_ARCH + ) + # Parse the architecture name from the compiler output. + string(REGEX MATCH "TARGET_ARCH ([a-zA-Z0-9_]+)" _FLUX_TARGET_ARCH "${_FLUX_TARGET_ARCH}") + + # Get rid of the value marker leaving just the architecture name. + string(REPLACE "TARGET_ARCH " "" _FLUX_TARGET_ARCH "${_FLUX_TARGET_ARCH}") + + if (_FLUX_TARGET_ARCH STREQUAL "unsupported") + message(FATAL_ERROR "Invalid target architecture. Flux Engine only supports 64-bit architecture.") + endif() + endif() + + set(${_OUT} "${_FLUX_TARGET_ARCH}" PARENT_SCOPE) +endfunction(flux_set_target_architecture) + +function(flux_add_graphics_definitions _TARGET_GRAPHICS) + string(TOUPPER ${_TARGET_GRAPHICS} GRAPHICS) + string(CONCAT FLUX_TARGET "-DFLUX_TARGET_" ${GRAPHICS}) + add_definitions(${FLUX_TARGET}) +endfunction(flux_add_graphics_definitions) + +if(NOT (DEFINED CACHE{FLUX_TARGET_CPU} AND + DEFINED CACHE{FLUX_TARGET_OS} AND + DEFINED CACHE{FLUX_TARGET_VENDOR} AND + DEFINED CACHE{FLUX_TARGET_GRAPHICS})) + if(WIN32) + if(NOT CMAKE_SYSTEM_VERSION) + set(CMAKE_SYSTEM_VERSION ${CMAKE_HOST_SYSTEM_VERSION} CACHE STRING "The version of the target platform." FORCE) + endif() + + if(NOT CMAKE_SYSTEM_PROCESSOR) + set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_HOST_SYSTEM_PROCESSOR} CACHE STRING "The target architecture." FORCE) + endif() + # Get the correct target architecture. + flux_set_target_architecture(FLUX_TARGET_CPU) + + set(FLUX_TARGET_VENDOR Microsoft CACHE STRING "[READONLY] The target vendor." FORCE) + set(FLUX_TARGET_OS Windows CACHE STRING "[READONLY] The current platform." FORCE) + set(FLUX_TARGET_GRAPHICS ${FLUX_GRAPHICS} CACHE STRING "[READONLY] The target graphics api." FORCE) + + flux_add_graphics_definitions(${FLUX_TARGET_GRAPHICS}) + + if(FLUX_TARGET_GRAPHICS STREQUAL "OpenGL") + set(FLUX_API_VERSION_MAJOR 4 CACHE STRING "[READONLY] The target graphics api version major." FORCE) + set(FLUX_API_VERSION_MINOR 6 CACHE STRING "[READONLY] The target graphics api version minor." FORCE) + add_definitions("-DFLUX_OPENGL_VERSION_MAJOR=${FLUX_API_VERSION_MAJOR}") + add_definitions("-DFLUX_OPENGL_VERSION_MINOR=${FLUX_API_VERSION_MINOR}") + endif() + elseif(APPLE) + if(NOT DEFINED CMAKE_OSX_SYSROOT) + message(FATAL_ERROR "The required variable CMAKE_OSX_SYSROOT does not exist in CMake cache.\n" + "CMAKE_OSX_SYSROOT holds the path to the SDK.") + endif() + + list(LENGTH CMAKE_OSX_ARCHITECTURES _ARCH_COUNT) + if(_ARCH_COUNT STREQUAL "1") + set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_OSX_ARCHITECTURES} CACHE STRING "The target architecture." FORCE) + endif() + + if(CMAKE_OSX_SYSROOT MATCHES ".*/MacOSX.platform/*") + if(NOT CMAKE_SYSTEM_VERSION) + set(CMAKE_SYSTEM_VERSION 11.3 CACHE STRING "The version of the target platform." FORCE) + endif() + # Get the correct target architecture. + flux_set_target_architecture(FLUX_TARGET_CPU) + + set(FLUX_TARGET_VENDOR Apple CACHE STRING "[READONLY] The target vendor." FORCE) + set(FLUX_TARGET_OS MacOSX CACHE STRING "[READONLY] The current platform." FORCE) + set(FLUX_TARGET_GRAPHICS ${FLUX_GRAPHICS} CACHE STRING "[READONLY] The target graphics api." FORCE) + + flux_add_graphics_definitions(${FLUX_TARGET_GRAPHICS}) + + if(FLUX_TARGET_GRAPHICS STREQUAL "OpenGL") + set(FLUX_API_VERSION_MAJOR 4 CACHE STRING "[READONLY] The target graphics api version major." FORCE) + set(FLUX_APIL_VERSION_MINOR 1 CACHE STRING "[READONLY] The target graphics api version minor." FORCE) + add_definitions("-DFLUX_OPENGL_VERSION_MAJOR=${FLUX_API_VERSION_MAJOR}") + add_definitions("-DFLUX_OPENGL_VERSION_MINOR=${FLUX_API_VERSION_MINOR}") + endif() + endif() + elseif(UNIX) + if(NOT CMAKE_SYSTEM_VERSION) + set(CMAKE_SYSTEM_VERSION ${CMAKE_HOST_SYSTEM_VERSION} CACHE STRING "The version of the target platform." FORCE) + endif() + + if(NOT CMAKE_SYSTEM_PROCESSOR) + set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_HOST_SYSTEM_PROCESSOR} CACHE STRING "The target architecture." FORCE) + endif() + # Get the correct target architecture. + flux_set_target_architecture(FLUX_TARGET_CPU) + + set(FLUX_TARGET_VENDOR "Linus Torvalds" CACHE STRING "[READONLY] The target vendor." FORCE) + set(FLUX_TARGET_OS Linux CACHE STRING "[READONLY] The current platform." FORCE) + set(FLUX_TARGET_GRAPHICS ${FLUX_GRAPHICS} CACHE STRING "[READONLY] The target graphics api." FORCE) + + flux_add_graphics_definitions(${FLUX_TARGET_GRAPHICS}) + + if(FLUX_TARGET_GRAPHICS STREQUAL "OpenGL") + set(FLUX_API_VERSION_MAJOR 4 CACHE STRING "[READONLY] The target graphics api version major." FORCE) + set(FLUX_API_VERSION_MINOR 6 CACHE STRING "[READONLY] The target graphics api version minor." FORCE) + add_definitions("-DFLUX_OPENGL_VERSION_MAJOR=${FLUX_API_VERSION_MAJOR}") + add_definitions("-DFLUX_OPENGL_VERSION_MINOR=${FLUX_API_VERSION_MINOR}") + endif() + endif() +endif() + +#----------------------------------------------------------------------------------------------------------------------- +# Helper macros for imposing vendor/OS requirements on the built modules. +#----------------------------------------------------------------------------------------------------------------------- + +macro(flux_requires_vendor _ARG_VENDOR) + if(NOT FLUX_TARGET_VENDOR STREQUAL ${_ARG_VENDOR}) + get_filename_component(_TMP_BASENAME ${CMAKE_CURRENT_LIST_DIR} NAME) + message("The subdirectory '${_TMP_BASENAME}' is ignored because the target OS vendor is set to " + "'${FLUX_TARGET_VENDOR}'") + unset(_TMP_BASENAME) + return() + endif() +endmacro(flux_requires_vendor) + +#----------------------------------------------------------------------------------------------------------------------- +# Installation. +#----------------------------------------------------------------------------------------------------------------------- + +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + # Defines the directory where the build artifacts will be placed. + set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/output" CACHE PATH "" FORCE) +endif() + +#----------------------------------------------------------------------------------------------------------------------- +# Helper functions. +#----------------------------------------------------------------------------------------------------------------------- + +function(flux_common_app _NAME) + if(NOT (FLUX_TARGET_OS STREQUAL "Windows" OR FLUX_TARGET_OS STREQUAL "Linux")) + message("Target '${_NAME}' is ignored because the target OS is set to '${FLUX_TARGET_OS}'.") + return() + endif() + cmake_parse_arguments(PARSE_ARGV 1 # start at the 1st argument + _FLUX_COMMON_APP + "" # options + "" # one value keywords + "SOURCE;LINK") # multi value keywords + if(NOT _FLUX_COMMON_APP_SOURCE) + message(FATAL_ERROR "Target '${_NAME}' has no sources.\n" + "Perhaps you have forgotten to provide the 'SOURCE' argument?") + endif() + add_executable(flux_${_NAME}) + target_sources(flux_${_NAME} PRIVATE "${_FLUX_COMMON_APP_SOURCE}") + target_link_libraries(flux_${_NAME} PRIVATE flux::project_settings) + if(_FLUX_COMMON_APP_LINK) + target_link_libraries(flux_${_NAME} PRIVATE "${_FLUX_COMMON_APP_LINK}") + endif() + install(TARGETS flux_${_NAME} + RUNTIME DESTINATION flux-${_NAME}) +endfunction(flux_common_app) + +function(flux_macosx_app _NAME) + if(NOT FLUX_TARGET_OS STREQUAL "MacOSX") + message("Target '${_NAME}' is ignored because the target OS is set to '${FLUX_TARGET_OS}'.") + return() + endif() + cmake_parse_arguments(PARSE_ARGV 1 # start at the 1st argument + _FLUX_MACOSX_APP + "" # options + "BUNDLE_NAME" # one value keywords + "SOURCE;LINK") # multi value keywords + if(NOT _FLUX_MACOSX_APP_SOURCE) + message(FATAL_ERROR "Target '${_NAME}' has no sources.\n" + "Perhaps you have forgotten to provide the 'SOURCE' argument?") + endif() + if(NOT _FLUX_MACOSX_BUNDLE_NAME) + set(_FLUX_MACOSX_BUNDLE_NAME "${_NAME}") + endif() + add_executable(flux_${_NAME} MACOSX_BUNDLE) + set_target_properties(flux_${_NAME} PROPERTIES + BUNDLE True + MACOSX_BUNDLE_GUI_IDENTIFIER "com.arcsine-project.${_FLUX_MACOSX_BUNDLE_NAME}" + MACOSX_BUNDLE_BUNDLE_VERSION "0.1" + MACOSX_BUNDLE_SHORT_VERSION_STRING "0.1" + MACOSX_BUNDLE_BUNDLE_NAME "${_FLUX_MACOSX_BUNDLE_NAME}" + XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "iPhone Developer" + XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf-with-dsym") + target_sources(flux_${_NAME} PRIVATE "${_FLUX_MACOSX_APP_SOURCE}") + target_link_libraries(flux_${_NAME} PRIVATE flux::project_settings) + target_link_libraries(flux_${_NAME} PRIVATE " -framework AppKit") + if(_FLUX_MACOSX_APP_LINK) + target_link_libraries(flux_${_NAME} PRIVATE "${_FLUX_MACOSX_APP_LINK}") + endif() + install(TARGETS flux_${_NAME} + BUNDLE DESTINATION flux-${_NAME}) +endfunction(flux_macosx_app) + +# flux_executable( +# +# items... +# [ items...]... +# [ +# items... +# [ items...]...]...) +function(flux_executable _ARG_NAME) + cmake_parse_arguments(PARSE_ARGV 1 # start at the 1st argument + _ARG # variable prefix + "" # options + "" # one value keywords + "WINDOWS;MACOSX;LINUX;COMMON") # multi value keywords + if (FLUX_TARGET_OS STREQUAL "MacOSX") + if (DEFINED _ARG_MACOSX OR DEFINED _ARG_COMMON) + flux_macosx_app(${_ARG_NAME} ${_ARG_MACOSX} ${_ARG_COMMON}) + else() + message("Ignoring flux::${_ARG_NAME}, this target is not supported on MacOSX.") + endif() + elseif(FLUX_TARGET_OS STREQUAL "Windows") + if (DEFINED _ARG_WINDOWS OR DEFINED _ARG_COMMON) + flux_common_app(${_ARG_NAME} ${_ARG_WINDOWS} ${_ARG_COMMON}) + else() + message("Ignoring flux::${_ARG_NAME}, this target is not supported on Windows.") + endif() + elseif(FLUX_TARGET_OS STREQUAL "Linux") + if (DEFINED _ARG_LINUX OR DEFINED _ARG_COMMON) + flux_common_app(${_ARG_NAME} ${_ARG_LINUX} ${_ARG_COMMON}) + else() + message("Ignoring flux::${_ARG_NAME}, this target is not supported on Linux.") + endif() + endif() +endfunction(flux_executable) + +# This macro is used by `flux_static_library` and `flux_interface_library` functions. Don't call +# it unless you know what you are doing. +macro(_flux_unit_tests _ARG_NAME _TESTS_SOURCE) + if(NOT "${_TESTS_SOURCE}" STREQUAL "" AND "${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + find_package(Catch2 REQUIRED) + set(_TESTS flux_${_ARG_NAME}_tests) + add_executable(${_TESTS}) + target_sources(${_TESTS} PRIVATE "${_TESTS_SOURCE}") + target_link_libraries(${_TESTS} + PRIVATE Catch2::Catch2 + flux::${_ARG_NAME}) + install(TARGETS ${_TESTS} + RUNTIME DESTINATION flux-${_ARG_NAME}/bin) + add_test(NAME ${_ARG_NAME} COMMAND ${_TESTS}) + endif() +endmacro(_flux_unit_tests) + +# This macro is used by `flux_static_library` and `flux_interface_library` functions. Don't call +# it unless you know what you are doing. +macro(_flux_install_headers _ARG_NAME _ARG_DIRS) + foreach(DIR IN ITEMS ${_ARG_DIRS}) + install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/flux/ + DESTINATION flux-${_ARG_NAME}/include + FILES_MATCHING + PATTERN "*.hpp" + PATTERN "*.h") + endforeach() +endmacro(_flux_install_headers) + +# flux_metal_library( +# TARGET +# SOURCE ...) +function(flux_metal_library _ARG_NAME) + cmake_parse_arguments(PARSE_ARGV 1 # start at the 1st argument + _ARG # variable prefix + "" # options + "TARGET" # one value keywords + "SOURCE") # multi value keywords + if (FLUX_TARGET_VENDOR STREQUAL "Apple") + if(NOT _ARG_TARGET) + message(FATAL_ERROR "The required argument TARGET is missing.") + endif() + + get_target_property(_TARGET "${_ARG_TARGET}" ALIASED_TARGET) + + add_custom_command(TARGET "${_TARGET}" POST_BUILD + COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT} metal + -o ${CMAKE_CURRENT_BINARY_DIR}/${_ARG_NAME}.air + -c ${_ARG_SOURCE} + COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT} metallib + ${CMAKE_CURRENT_BINARY_DIR}/${_ARG_NAME}.air + -o ${CMAKE_CURRENT_BINARY_DIR}/${_ARG_NAME}.metallib + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + endif() +endfunction(flux_metal_library) + +# flux_static_library( +# +# items... +# [ items...]... +# [ +# items... +# [ items...]...]...) +function(_flux_static_library _ARG_NAME) + cmake_parse_arguments(PARSE_ARGV 1 # start at the 1st argument + _ARG # variable prefix + "" # options + "" # one value keywords + "SOURCE;TEST;LINK;INCLUDE_DIR") # multi value keywords + set(_TARGET "flux_${_ARG_NAME}") + add_library(${_TARGET} STATIC) + add_library("flux::${_ARG_NAME}" ALIAS ${_TARGET}) + target_include_directories(${_TARGET} PUBLIC "${CMAKE_CURRENT_LIST_DIR}" "${_ARG_INCLUDE_DIR}") + target_link_libraries(${_TARGET} + PUBLIC flux::project_settings + "${_ARG_LINK}") + target_sources(${_TARGET} PRIVATE "${_ARG_SOURCE}") + install(TARGETS ${_TARGET} + ARCHIVE DESTINATION flux-${_ARG_NAME}/lib) + _flux_install_headers("${_ARG_NAME}" ".;${_ARG_INCLUDE_DIR}") + _flux_unit_tests("${_ARG_NAME}" "${_ARG_TEST}") +endfunction(_flux_static_library) + +function(flux_static_library _ARG_NAME) + cmake_parse_arguments(PARSE_ARGV 1 # start at the 1st argument + _ARG # variable prefix + "" # options + "" # one value keywords + "WINDOWS;MACOSX;LINUX;COMMON") # multi value keywords + if (FLUX_TARGET_OS STREQUAL "MacOSX") + if (DEFINED _ARG_MACOSX OR DEFINED _ARG_COMMON) + _flux_static_library(${_ARG_NAME} ${_ARG_MACOSX} ${_ARG_COMMON}) + else() + message("Ignoring flux::${_ARG_NAME}, this target is not supported on MacOSX.") + endif() + elseif(FLUX_TARGET_OS STREQUAL "Windows") + if (DEFINED _ARG_WINDOWS OR DEFINED _ARG_COMMON) + _flux_static_library(${_ARG_NAME} ${_ARG_WINDOWS} ${_ARG_COMMON}) + else() + message("Ignoring flux::${_ARG_NAME}, this target is not supported on Windows.") + endif() + elseif(FLUX_TARGET_OS STREQUAL "Linux") + if (DEFINED _ARG_LINUX OR DEFINED _ARG_COMMON) + _flux_static_library(${_ARG_NAME} ${_ARG_LINUX} ${_ARG_COMMON}) + else() + message("Ignoring flux::${_ARG_NAME}, this target is not supported on Linux.") + endif() + endif() +endfunction(flux_static_library) + +# flux_interface_library( +# +# items... +# [ items...]... +# [ +# items... +# [ items...]...]...) +function(_flux_interface_library _ARG_NAME) + cmake_parse_arguments(PARSE_ARGV 1 # start at the 1st argument + _ARG # variable prefix + "" # options + "" # one value keywords + "TEST;LINK") # multi value keywords + set(_TARGET "flux_${_ARG_NAME}") + add_library(${_TARGET} INTERFACE) + add_library("flux::${_ARG_NAME}" ALIAS ${_TARGET}) + target_include_directories(${_TARGET} INTERFACE "${CMAKE_CURRENT_LIST_DIR}") + target_link_libraries(${_TARGET} + INTERFACE flux::project_settings + "${_ARG_LINK}") + _flux_install_headers("${_ARG_NAME}" ".") + _flux_unit_tests("${_ARG_NAME}" "${_ARG_TEST}") +endfunction(_flux_interface_library) + +function(flux_interface_library _ARG_NAME) + cmake_parse_arguments(PARSE_ARGV 1 # start at the 1st argument + _ARG # variable prefix + "" # options + "" # one value keywords + "WINDOWS;MACOSX;LINUX;COMMON") # multi value keywords + if (FLUX_TARGET_OS STREQUAL "MacOSX") + if (DEFINED _ARG_MACOSX OR DEFINED _ARG_COMMON) + _flux_interface_library(${_ARG_NAME} ${_ARG_MACOSX} ${_ARG_COMMON}) + else() + message("Ignoring flux::${_ARG_NAME}, this target is not supported on MacOSX.") + endif() + elseif(FLUX_TARGET_OS STREQUAL "Windows") + if (DEFINED _ARG_WINDOWS OR DEFINED _ARG_COMMON) + _flux_interface_library(${_ARG_NAME} ${_ARG_WINDOWS} ${_ARG_COMMON}) + else() + message("Ignoring flux::${_ARG_NAME}, this target is not supported on Windows.") + endif() + elseif(FLUX_TARGET_OS STREQUAL "Linux") + if (DEFINED _ARG_LINUX OR DEFINED _ARG_COMMON) + _flux_interface_library(${_ARG_NAME} ${_ARG_LINUX} ${_ARG_COMMON}) + else() + message("Ignoring flux::${_ARG_NAME}, this target is not supported on Linux.") + endif() + endif() +endfunction(flux_interface_library) + +#----------------------------------------------------------------------------------------------------------------------- +# Build type. +#----------------------------------------------------------------------------------------------------------------------- + +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE) +endif() + +# Possible values of build type for cmake-gui and ccmake. +set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +string(TOUPPER ${CMAKE_BUILD_TYPE} FLUX_BUILD_TYPE) + +#----------------------------------------------------------------------------------------------------------------------- +# Setting a properly used compiler. +#----------------------------------------------------------------------------------------------------------------------- + +if(CMAKE_CXX_COMPILER_ID MATCHES "^(Apple)?(C|c)?lang$") + target_compile_definitions(flux::project_settings INTERFACE FLUX_CLANG) +endif() + +#----------------------------------------------------------------------------------------------------------------------- +# Setting the correct CMAKE__FLAGS_ variables for the Clang-Windows bundle. +#----------------------------------------------------------------------------------------------------------------------- + +# The code below changes the CMAKE__FLAGS_ variables. It does this for a good reason. +# Don't do this in normal code. Instead add the necessary compile/linker flags to flux::project_settings. +if(FLUX_TARGET_OS STREQUAL "Windows" AND CMAKE_CXX_COMPILER_ID MATCHES "(C|c)lang") + set(USE_MSVC_RUNTIME_LIBRARY_DLL OFF) + if(FLUX_BUILD_TYPE STREQUAL "DEBUG") + string(APPEND CMAKE_C_FLAGS_${FLUX_BUILD_TYPE} " -D_DEBUG -D_MT -Xclang --dependent-lib=msvcrtd") + string(APPEND CMAKE_CXX_FLAGS_${FLUX_BUILD_TYPE} " -D_DEBUG -D_MT -Xclang --dependent-lib=msvcrtd") + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + set(FLUX_MSVC_RUNTIME_LIBRARY "MultiThreadedDebug") + else() + string(APPEND CMAKE_C_FLAGS_${FLUX_BUILD_TYPE} " -D_MT -Xclang --dependent-lib=msvcrt") + string(APPEND CMAKE_CXX_FLAGS_${FLUX_BUILD_TYPE} " -D_MT -Xclang --dependent-lib=msvcrt") + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded") + set(FLUX_MSVC_RUNTIME_LIBRARY "MultiThreaded") + endif() +endif() + +#----------------------------------------------------------------------------------------------------------------------- +# Getting LLVM Bitcode. +#----------------------------------------------------------------------------------------------------------------------- + +# The code below changes the CMAKE__FLAGS and CMAKE__LINK_FLAGS variables. It does this for a good reason. +# Don't do this in normal code. Instead add the necessary compile/linker flags to flux::project_settings. +if (FLUX_TARGET_OS STREQUAL "MacOSX") + option(FLUX_ENABLE_BITCODE "Enable Bitcode generation." YES) + + if(FLUX_ENABLE_BITCODE) + string(APPEND CMAKE_C_FLAGS " -fembed-bitcode") + string(APPEND CMAKE_CXX_FLAGS " -fembed-bitcode") + string(APPEND CMAKE_OBJC_FLAGS " -fembed-bitcode") + string(APPEND CMAKE_OBJCXX_FLAGS " -fembed-bitcode") + + # The flag '-headerpad_max_install_names' should not be used with '-fembed-bitcode'. CMake always adds + # '-headerpad_max_install_names' flag. There's no appernt way to disable this flag otherwise. + # See: https://github.com/Kitware/CMake/blob/master/Modules/Platform/Darwin.cmake + string(REPLACE "-Wl,-headerpad_max_install_names" "" CMAKE_C_LINK_FLAGS ${CMAKE_C_LINK_FLAGS}) + string(REPLACE "-Wl,-headerpad_max_install_names" "" CMAKE_CXX_LINK_FLAGS ${CMAKE_CXX_LINK_FLAGS}) + string(REPLACE "-Wl,-headerpad_max_install_names" "" CMAKE_OBJC_LINK_FLAGS ${CMAKE_C_LINK_FLAGS}) + string(REPLACE "-Wl,-headerpad_max_install_names" "" CMAKE_OBJCXX_LINK_FLAGS ${CMAKE_CXX_LINK_FLAGS}) + endif() +endif() + +#----------------------------------------------------------------------------------------------------------------------- +# Link time optimization. +#----------------------------------------------------------------------------------------------------------------------- + +if(CMAKE_BUILD_TYPE MATCHES "Release") + option(FLUX_ENABLE_LTO "Enable link time optimization. This is only valid for Release builds." YES) +endif() + +if(FLUX_ENABLE_LTO) + # The code below changes the CMAKE__FLAGS and CMAKE__LINK_FLAGS variables. It does this for a good + # reason. Don't do this in normal code. Instead add the necessary compile/linker flags to flux::project_settings. + + # For LTO to work, we have to pass `-flto` flag to the compiler both at compile... + string(APPEND CMAKE_C_FLAGS " -flto") + string(APPEND CMAKE_CXX_FLAGS " -flto") + + # and link time. + string(APPEND CMAKE_C_LINKER_FLAGS " -flto") + string(APPEND CMAKE_CXX_LINKER_FLAGS " -flto") + + if(FLUX_TARGET_OS STREQUAL "MacOSX") + # And the same thing for Obj-C/CXX compiler... + string(APPEND CMAKE_OBJC_FLAGS " -flto") + string(APPEND CMAKE_OBJCXX_FLAGS " -flto") + + # and linker. + string(APPEND CMAKE_OBJC_LINKER_FLAGS " -flto") + string(APPEND CMAKE_OBJCXX_LINKER_FLAGS " -flto") + endif() +endif() + +#----------------------------------------------------------------------------------------------------------------------- +# Enable colored diagnostics. +#----------------------------------------------------------------------------------------------------------------------- + +if(CMAKE_CXX_COMPILER_ID MATCHES "^(Apple)?(C|c)?lang$") + target_compile_options(flux::project_settings INTERFACE -fcolor-diagnostics) +endif() + +#----------------------------------------------------------------------------------------------------------------------- +# Compiler cache. +#----------------------------------------------------------------------------------------------------------------------- + +find_program(FLUX_CCACHE_COMMAND ccache) + +if(FLUX_CCACHE_COMMAND) + set(CMAKE_CXX_COMPILER_LAUNCHER ${FLUX_CCACHE_COMMAND}) +else() + message(WARNING "Cannot find ccache. Incremental builds may get slower.") +endif() + +#----------------------------------------------------------------------------------------------------------------------- +# Warnings. +#----------------------------------------------------------------------------------------------------------------------- + +target_compile_options(flux::project_settings INTERFACE + # Enable all the warnings about constructions that some users consider questionable, and that are easy to avoid. + -Wall + # Enable some extra warnings that are not enabled by -Wall. + -Wextra + # Warn whenever a local variable or type shadows another one. + -Wshadow + # Warn whenever a class has virtual functions and an accessible non-virtual destructor. + -Wnon-virtual-dtor + # Warn if old-style (C-style) cast to a non-void type is used within a C++ program. + -Wold-style-cast + # Warn whenever a pointer is cast such that the required alignment of the target is increased. For example, warn if + # a char* is cast to an int* on machines where integers can only be accessed at two- or four-byte boundaries. + -Wcast-align + # Warn on anything being unused. + -Wunused + # Warn when a function declaration hides virtual functions from a base class. + -Woverloaded-virtual + # Warn whenever non-standard C++ is used. + -Wpedantic + # Warn on implicit conversions that may alter a value. This includes conversions between real and integer, + # like abs(x) when x is double. + -Wconversion + # Warn for implicit conversions that may change the sign of an integer value, like assigning a signed integer + # expression to an unsigned integer variable. + -Wsign-conversion + # Warn if the compiler detects paths that trigger erroneous or undefined behaviour due to dereferencing a null + # pointer. + -Wnull-dereference + # Warn whenever a value of type float is implicitly promoted to double. + -Wdouble-promotion + # Check calls to printf and scanf, etc., to make sure that the arguments supplied have types appropriate to the + # format string. + -Wformat=2) + +option(FLUX_WARNINGS_AS_ERRORS "Treat compiler warnings as errors." YES) + +if(FLUX_WARNINGS_AS_ERRORS) + target_compile_options(flux::project_settings INTERFACE + # Make all warnings into errors. + -Werror) +endif() + +#----------------------------------------------------------------------------------------------------------------------- +# C++ Options. +#----------------------------------------------------------------------------------------------------------------------- + +target_compile_options(flux::project_settings INTERFACE + # Disable exceptions support and use the variant of C++ libraries without exceptions. + -fno-exceptions + # Disable generation of information about every class with virtual functions for use by the C++ runtime type + # identification features (`dynamic_cast' and `typeid'). + -fno-rtti) + +#----------------------------------------------------------------------------------------------------------------------- +# Sanitizers. +#----------------------------------------------------------------------------------------------------------------------- + +option(FLUX_ENABLE_SANITIZER_ADDRESS "Enable address sanitizer." YES) +option(FLUX_ENABLE_SANITIZER_THREAD "Enable thread sanitizer." NO ) +option(FLUX_ENABLE_SANITIZER_UNDEFINED "Enable undefined behavior sanitizer." YES) +option(FLUX_ENABLE_SANITIZER_LEAK "Enable leak sanitizer." NO ) + +if(FLUX_TARGET_OS STREQUAL "Windows") + message(WARNING "Address Sanitizer is not currently supported on Windows. Turning it off...") + set(FLUX_ENABLE_SANITIZER_ADDRESS NO) + set(FLUX_ENABLE_SANITIZER_THREAD NO) + set(FLUX_ENABLE_SANITIZER_UNDEFINED NO) + set(FLUX_ENABLE_SANITIZER_LEAK NO) +endif() + +if((FLUX_ENABLE_SANITIZER_LEAK OR FLUX_ENABLE_SANITIZER_ADDRESS) AND FLUX_ENABLE_SANITIZER_THREAD) + message(WARNING "Thread sanitizer does not work with Address or Leak sanitizer enabled.") +endif() + +set(FLUX_SANITIZERS "") + +if(FLUX_ENABLE_SANITIZER_ADDRESS) + list(APPEND FLUX_SANITIZERS "address") +endif() + +if(FLUX_ENABLE_SANITIZER_THREAD) + list(APPEND FLUX_SANITIZERS "thread") +endif() + +if(FLUX_ENABLE_SANITIZER_UNDEFINED) + list(APPEND FLUX_SANITIZERS "undefined") +endif() + +if(FLUX_ENABLE_SANITIZER_LEAK) + list(APPEND FLUX_SANITIZERS "leak") +endif() + +list(JOIN FLUX_SANITIZERS "," FLUX_ENABLED_SANITIZERS) + +if(FLUX_BUILD_TYPE STREQUAL "DEBUG") + target_compile_options(flux::project_settings INTERFACE -fsanitize=${FLUX_ENABLED_SANITIZERS}) + target_link_options (flux::project_settings INTERFACE -fsanitize=${FLUX_ENABLED_SANITIZERS}) +endif() + +# code: language="CMake" insertSpaces=true tabSize=4 \ No newline at end of file diff --git a/external/Catch2 b/external/Catch2 new file mode 160000 index 0000000..a7782d1 --- /dev/null +++ b/external/Catch2 @@ -0,0 +1 @@ +Subproject commit a7782d1d7ca84b9cc4c0f3fc4abdec0951d722b2 diff --git a/external/entt b/external/entt new file mode 160000 index 0000000..48c953d --- /dev/null +++ b/external/entt @@ -0,0 +1 @@ +Subproject commit 48c953d23e506ebc04a66e21713cfcb219cd17fd diff --git a/external/fast_io b/external/fast_io new file mode 160000 index 0000000..a13c3ed --- /dev/null +++ b/external/fast_io @@ -0,0 +1 @@ +Subproject commit a13c3ed1cd6da64b381322f3466f3b4fc9a80ff2 diff --git a/external/glad b/external/glad new file mode 160000 index 0000000..5dd44f1 --- /dev/null +++ b/external/glad @@ -0,0 +1 @@ +Subproject commit 5dd44f1f6980d9e890d36a16e55f11819319e08e diff --git a/external/glfw b/external/glfw new file mode 160000 index 0000000..b35641f --- /dev/null +++ b/external/glfw @@ -0,0 +1 @@ +Subproject commit b35641f4a3c62aa86a0b3c983d163bc0fe36026d diff --git a/external/glm b/external/glm new file mode 160000 index 0000000..a2844ee --- /dev/null +++ b/external/glm @@ -0,0 +1 @@ +Subproject commit a2844eede81f92b7dfb327f831c0bc0dbb273078 diff --git a/external/imgui b/external/imgui new file mode 160000 index 0000000..4cb0fe3 --- /dev/null +++ b/external/imgui @@ -0,0 +1 @@ +Subproject commit 4cb0fe3c7dda31a033ce6f55d76aedd1c5893012 diff --git a/flux-playground/CMakeLists.txt b/flux-playground/CMakeLists.txt new file mode 100644 index 0000000..b0c7cde --- /dev/null +++ b/flux-playground/CMakeLists.txt @@ -0,0 +1,19 @@ +find_package(imgui REQUIRED) +find_package(glfw REQUIRED) +find_package(glad REQUIRED) + +flux_executable(playground + COMMON + LINK + glfw::glfw + glad::glad + imgui::imgui + WINDOWS + SOURCE + "playground.cpp" + LINUX + SOURCE + "playground.cpp" +) + +# code: language="CMake" insertSpaces=true tabSize=4 \ No newline at end of file diff --git a/flux-playground/playground.cpp b/flux-playground/playground.cpp new file mode 100644 index 0000000..01b42eb --- /dev/null +++ b/flux-playground/playground.cpp @@ -0,0 +1,108 @@ +// TODO: +// Remove this dummy example asap. + +// GLAD +#include + +// GLFW (include after glad) +#include + +#include +#include + + + +GLFWwindow* create_window(const char* name, int major, int minor) { + std::cout << "Creating Window, OpenGL " << major << "." << minor << ": " << name << std::endl; + + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, major); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, minor); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); + + GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, name, NULL, NULL); + return window; +} + +GladGLContext* create_context(GLFWwindow* window) { + glfwMakeContextCurrent(window); + + GladGLContext* context = reinterpret_cast(std::calloc(1, sizeof(GladGLContext))); + if (!context) + return NULL; + + int version = gladLoadGLContext(context, glfwGetProcAddress); + std::cout << "Loaded OpenGL " << GLAD_VERSION_MAJOR(version) << "." + << GLAD_VERSION_MINOR(version) << std::endl; + + return context; +} + +void free_context(GladGLContext* context) { + free(context); +} + +void draw(GLFWwindow* window, GladGLContext* gl, float r, float g, float b) { + glfwMakeContextCurrent(window); + + gl->ClearColor(r, g, b, 1.0f); + gl->Clear(GL_COLOR_BUFFER_BIT); + + glfwSwapBuffers(window); +} + +// Is called whenever a key is pressed/released via GLFW +void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) { + (void)scancode; + (void)mode; + if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) + glfwSetWindowShouldClose(window, GL_TRUE); +} + +// Window dimensions +const GLuint WIDTH = 400, HEIGHT = 300; + +int main() { + glfwInit(); + + GLFWwindow* window1 = create_window("Window 1", 3, 3); + GLFWwindow* window2 = create_window("Window 2", 3, 2); + + if (!window1 || !window2) { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + + glfwSetKeyCallback(window1, key_callback); + glfwSetKeyCallback(window2, key_callback); + + GladGLContext* context1 = create_context(window1); + GladGLContext* context2 = create_context(window2); + + if (!context1 || !context2) { + std::cout << "Failed to initialize GL contexts" << std::endl; + free_context(context1); + free_context(context2); + } + + glfwMakeContextCurrent(window1); + context1->Viewport(0, 0, WIDTH, HEIGHT); + + glfwMakeContextCurrent(window2); + context2->Viewport(0, 0, WIDTH, HEIGHT); + + while (!glfwWindowShouldClose(window1) && !glfwWindowShouldClose(window2)) { + glfwPollEvents(); + + draw(window1, context1, 0.5f, 0.2f, 0.6f); + draw(window2, context2, 0.0f, 0.1f, 0.8f); + } + + free_context(context1); + free_context(context2); + + glfwTerminate(); + + return 0; +} \ No newline at end of file diff --git a/scripts/common.sh b/scripts/common.sh new file mode 100644 index 0000000..2b7ed4f --- /dev/null +++ b/scripts/common.sh @@ -0,0 +1,71 @@ +# This script contains the variables and functions that are common to the other scripts. + +# PROJECT_ROOT holds the absolute path to the root directory of the project. +readonly PROJECT_ROOT=$(_() { + local readonly SCRIPT_DIR=`dirname ${BASH_SOURCE[0]}` + if [[ ${SCRIPT_DIR} == /* ]]; then + echo ${SCRIPT_DIR}/.. + else + echo `pwd`/${SCRIPT_DIR}/.. + fi +}; _) + +readonly EXIT_FAILURE=1 +readonly EXIT_SUCCESS=0 + +# fail prints the description of the failure and terminates the script. +fail() { + echo "Failed to build the project. $*" + exit ${EXIT_FAILURE} +} + +check_build_type() { + case $1 in + Debug|Release|RelWithDebInfo) + ;; + *) + echo "Unknown build type: '$1'" + if [ -z $2 ]; then + fail + else + $2 + fi + ;; + esac +} + +# lo converts the given string to lower case. +lo() { echo "$*" | tr '[:upper:]' '[:lower:]'; } +# up converts the given string to upper case. +up() { echo "$*" | tr '[:lower:]' '[:upper:]'; } + +print_build_title() { + local readonly MSG="$*" + local readonly MSG_EXT=$((${#MSG} / 2)) + echo "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" + printf "%%%%%*s%*s%%%%\n" $((38+${MSG_EXT})) "${MSG}" $((38-${MSG_EXT})) "" + echo "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" +} + +any_key() { + read -rsp $'Press any key to continue...\n' -n1 key +} + +# Moves cursor to beginning of next line, $1 lines down. +# If $1 is not given, moves the cursor 1 line down. +next_line() { + printf "\033[${1:-1}E" +} + +####################################################################################################################### +# Check platform-independent prerequisites. + +if [ "x$(which cmake)" == "x" ]; then + fail "Cannot find CMake. Please make sure it is available in your PATH." +fi + +if [ "x$(which git)" == "x" ]; then + fail "Cannot find Git. Please make sure it is available in your PATH." +fi + +# code: language='Shell Script' insertSpaces=true tabSize=4 \ No newline at end of file diff --git a/scripts/generate-cmake-presets.ps1 b/scripts/generate-cmake-presets.ps1 new file mode 100644 index 0000000..393c92d --- /dev/null +++ b/scripts/generate-cmake-presets.ps1 @@ -0,0 +1,99 @@ +Set-StrictMode -Version 2.0 + +function detect_clang() { + if ([string]::IsNullOrEmpty($env:llvm)) { + throw @" + Cannot find a path to the 'Clang' compiler, it looks like it is not set in the `$env` + environment variable. Please add the path to the compiler by adding a new environment + variable 'LLVM'. For example 'LLVM=C:/Program Files/LLVM/bin'. +"@ + } + + $clang_version_major = Write-Output '__clang_major__' | clang -E -x c - | Select-Object -Last 1 + $clang_version_minor = Write-Output '__clang_minor__' | clang -E -x c - | Select-Object -Last 1 + $clang_version_patch = Write-Output '__clang_patchlevel__ ' | clang -E -x c - | Select-Object -Last 1 + + if ([int]$clang_version_major -lt 16) { + throw @" + The minimum supported version of Clang is 16 or higher. Please update Clang to the minimum supported version. +"@ + } + + Write-Output "Detected clang version: $clang_version_major.$clang_version_minor.$clang_version_patch" +} + +function generate_cmake_presets($os, $arch, $graphics) { + $description = "" + if ($graphics -ne "OpenGL") { + $description = "This configuration is temporarily unsupported." + } + $presets = @" + { + "name": "$os-$arch-$($graphics.ToLower())-debug", + "displayName": "$os-$arch-$($graphics.ToLower())-debug", + "description": "$description", + "inherits": "base", + "architecture": { + "value": "$arch", + "strategy": "external" + }, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "CMAKE_C_COMPILER": "$env:llvm/clang.exe", + "CMAKE_CXX_COMPILER": "$env:llvm/clang++.exe", + "CMAKE_RC_COMPILER": "$env:llvm/clang++.exe", + "FLUX_GRAPHICS": "$graphics" + } + }, + { + "name": "$os-$arch-$($graphics.ToLower())-release", + "displayName": "$os-$arch-$($graphics.ToLower())-release", + "description": "$description", + "inherits": "base", + "architecture": { + "value": "$arch", + "strategy": "external" + }, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "RelWithDebInfo", + "CMAKE_C_COMPILER": "$env:llvm/clang.exe", + "CMAKE_CXX_COMPILER": "$env:llvm/clang++.exe", + "CMAKE_RC_COMPILER": "$env:llvm/clang++.exe", + "FLUX_GRAPHICS": "$graphics" + } + }, +"@ + return $presets +} + +$(detect_clang) + +$project_root = split-path $MyInvocation.MyCommand.Definition | split-path -parent +$cmake_presets = "$project_root\CMakePresets.json" + +if (Test-Path $cmake_presets) { + Remove-Item $cmake_presets +} + +Write-Output "Generating presets.." + +Add-Content -Path $cmake_presets -Value @" +{ + "version": 3, + "configurePresets": [ +$(generate_cmake_presets "windows" "x86_64" "OpenGL") +$(generate_cmake_presets "windows" "x86_64" "Vulkan") +$(generate_cmake_presets "windows" "x86_64" "DirectX") + { + "name": "base", + "description": "For more information: http://aka.ms/cmakepresetsvs", + "hidden": true, + "generator": "Ninja", + "binaryDir": "`${sourceDir}/build/`${presetName}", + "installDir": "`${sourceDir}/build/`${presetName}/output/" + } + ] +} +"@ + +Write-Output "Successfully generated presets in $cmake_presets" \ No newline at end of file diff --git a/scripts/generate-cmake-presets.sh b/scripts/generate-cmake-presets.sh new file mode 100644 index 0000000..c9a542f --- /dev/null +++ b/scripts/generate-cmake-presets.sh @@ -0,0 +1,217 @@ +#!/usr/bin/env bash +source ${BASH_SOURCE[0]%/*}/common.sh + +####################################################################################################################### +# Detect target OS and Clang version. + +detect_os() { + case "$OSTYPE" in + darwin*) echo "MacOSX";; + linux*) echo "Linux";; + *) echo "Unsupported";; + esac +} + +detect_clang() { + readonly CLANG=$(which clang) + if [ "x${CLANG}" == "x" ]; then + fail "Cannot find Clang. Please make sure it is available in your PATH." + fi + + readonly CLANGXX=$(which clang++) + if [ "x${CLANGXX}" == "x" ]; then + fail "Cannot find Clang++. Please make sure it is available in your PATH." + fi + + readonly CLANG_MAJOR=$(echo __clang_major__ | clang -E -x c - | tail -n 1) + readonly CLANG_MINOR=$(echo __clang_minor__ | clang -E -x c - | tail -n 1) + readonly CLANG_PATCH=$(echo __clang_patchlevel__ | clang -E -x c - | tail -n 1) + + if [[ "${CLANG_MAJOR}" -lt 16 ]]; then + fail "The minimum supported version of Clang is 16 or higher. Please update Clang to the minimum supported version." + fi + + echo "Detected clang version: ${CLANG_MAJOR}.${CLANG_MINOR}.${CLANG_PATCH}" +} + +if [ "$(detect_os)" == "Unsupported" ]; then + fail "Unsupported OS: $OSTYPE." +elif [ "$(detect_os)" == "Linux" ]; then + detect_clang # For MacOS, the detection method will probably need to be revised. +fi + +####################################################################################################################### +readonly NINJA=$(which ninja) + +if [ "x${NINJA}" == "x" ]; then + fail "Cannot find Ninja. Please make sure it is available in your PATH." +fi + +####################################################################################################################### +# Generate the CMakePresets.json + +# apple_min_os_version returns the minimum supported version of the given OS/SDK. +apple_min_os_version() { + case $1 in + macosx) echo 11;; + iphoneos) echo 13;; + iphonesimulator) echo 13;; + esac +} + +# generate_apple_cmake_presets generates a portion of cmake-variants.yaml for the given OS and architectures. +generate_apple_cmake_presets() { + local readonly OS=$1 + local readonly GRAPHICS=$2 + local readonly DESCRIPTION=$3 + + for ARCH in "${@:4}"; do +cat </dev/null)", + "CMAKE_C_COMPILER": "$(xcrun --sdk ${OS} --find clang 2>/dev/null)", + "CMAKE_OBJCXX_COMPILER": "$(xcrun --sdk ${OS} --find clang++ 2>/dev/null)", + "CMAKE_OBJC_COMPILER": "$(xcrun --sdk ${OS} --find clang 2>/dev/null)", + "CMAKE_OSX_ARCHITECTURES": "${ARCH}", + "CMAKE_OSX_DEPLOYMENT_TARGET": "$(apple_min_os_version ${OS})", + "CMAKE_OSX_SYSROOT": "$(xcrun --sdk ${OS} --show-sdk-path 2>/dev/null)", + "FLUX_GRAPHICS": "${GRAPHICS}" + } + }, + { + "name": "${OS}-${ARCH}-$(lo ${GRAPHICS})-release", + "displayName": "${OS}-${ARCH}-$(lo ${GRAPHICS})-release", + "description": "${DESCRIPTION}", + "inherits": "base", + "architecture": { + "value": "${ARCH}", + "strategy": "external" + }, + "cacheVariables": { + "CMAKE_MAKE_PROGRAM": "${NINJA}", + "CMAKE_BUILD_TYPE": "RelWithDebInfo", + "CMAKE_CXX_COMPILER": "$(xcrun --sdk ${OS} --find clang++ 2>/dev/null)", + "CMAKE_C_COMPILER": "$(xcrun --sdk ${OS} --find clang 2>/dev/null)", + "CMAKE_OBJCXX_COMPILER": "$(xcrun --sdk ${OS} --find clang++ 2>/dev/null)", + "CMAKE_OBJC_COMPILER": "$(xcrun --sdk ${OS} --find clang 2>/dev/null)", + "CMAKE_OSX_ARCHITECTURES": "${ARCH}", + "CMAKE_OSX_DEPLOYMENT_TARGET": "$(apple_min_os_version ${OS})", + "CMAKE_OSX_SYSROOT": "$(xcrun --sdk ${OS} --show-sdk-path 2>/dev/null)", + "FLUX_GRAPHICS": "${GRAPHICS}" + } + }, +EOF + done +} + +# generate_linux_cmake_presets generates a portion of cmake-variants.yaml for the given OS and architectures. +generate_linux_cmake_presets() { + local readonly OS=$1 + local readonly GRAPHICS=$2 + local readonly DESCRIPTION=$3 + + for ARCH in "${@:4}"; do + # TODO: + # It will be necessary to check the arm64 build for Linux. Let's skip that for now. + if [[ "${ARCH}" == "arm64" ]]; then + continue + fi +cat <${PROJECT_ROOT}/CMakePresets.json +{ + "version": 3, + "configurePresets": [ +$(generate_cmake_presets $(detect_os) OpenGL arm64 x86_64) +$(generate_cmake_presets $(detect_os) Vulkan arm64 x86_64) +$(generate_cmake_presets $(detect_os) Metal arm64 x86_64) + { + "name": "base", + "description": "For more information: http://aka.ms/cmakepresetsvs", + "hidden": true, + "generator": "Ninja", + "binaryDir": "\${sourceDir}/build/\${presetName}", + "installDir": "\${sourceDir}/build/\${presetName}/output/" + } + ] +} +EOF + +echo "Successfully generated presets in ${PROJECT_ROOT}/CMakePresets.json" + +# code: language='Shell Script' insertSpaces=true tabSize=4 \ No newline at end of file