diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..8ff9591 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,214 @@ +* text=auto + +###### Git +.gitattributes text +.gitignore text +.gitconfig text +.gitmodules text + +##### Windows +*.bat text eol=crlf +*.exe binary +*.dll binary + +##### Linux +*.sh text eol=lf +*.so binary + +##### Global +# Documents +*.sql text +*.md text +*.adoc text +*.textile text +*.mustache text +*.csv text +*.tab text +*.tsv text +*.coffee text +*.css text +*.htm text +*.html text +*.xhtml text +*.inc text +*.js text +*.jsx text +*.less text +*.od text +*.onlydata text +*.sass text +*.scm text +*.log text +*.properties text +*.scss text +*.styl text +*.tag text +*.ts text +*.tsx text +*.dockerignore text +Dockerfile text +*.markdown text +*.mdwn text +*.mdown text +*.mkd text +*.mkdn text +*.mdtxt text +*.mdtext text +*.txt text +AUTHORS text +CHANGELOG text +CHANGES text +CONTRIBUTING text +COPYING text +copyright text +*COPYRIGHT* text +INSTALL text +license text +LICENSE text +NEWS text +readme text +*README* text +TODO text +# Configuration +*.cnf text +*.cfg text +*.conf text +*.config text +*.ini text +*.json text +*.xml text +*.bowerrc text +.browserslistrc text +.editorconfig text +*.npmignore text +*.yaml text +*.yml text +browserslist text +Makefile text +makefile text +Procfile text +.slugignore text +# Linters +.csslintrc text +.eslintrc text +.htmlhintrc text +.jscsrc text +.jshintrc text +.jshintignore text +.stylelintrc text +# Video +*.3gpp binary +*.3gp binary +*.as binary +*.asf binary +*.asx binary +*.fla binary +*.flv binary +*.m4v binary +*.mng binary +*.mov binary +*.mp4 binary +*.mpeg binary +*.mpg binary +*.ogv binary +*.swc binary +*.swf binary +*.webm binary +# Audio +*.kar binary +*.m4a binary +*.mid binary +*.midi binary +*.mp3 binary +*.ogg binary +*.ra binary +# Graphics +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.tif binary +*.tiff binary +*.ico binary +*.eps binary +*.ai binary +*.bmp binary +*.jng binary +*.jp2 binary +*.jpx binary +*.jxr binary +*.pdf binary +*.psb binary +*.psd binary +*.svg text +*.svgz binary +*.wbmp binary +*.webp binary +# Archives +*.7z binary +*.gz binary +*.jar binary +*.rar binary +*.tar binary +*.zip binary +# Fonts +*.ttf binary +*.eot binary +*.otf binary +*.woff binary +*.woff2 binary +# Executables +*.pyc binary +# Objects +*.o binary + +##### IDE/Editor +# Visual Studio +*.sln text eol=crlf +*.csproj text eol=crlf +*.vbproj text eol=crlf +*.vcxproj text eol=crlf +*.vcproj text eol=crlf +*.dbproj text eol=crlf +*.fsproj text eol=crlf +*.lsproj text eol=crlf +*.wixproj text eol=crlf +*.modelproj text eol=crlf +*.sqlproj text eol=crlf +*.wmaproj text eol=crlf +*.xproj text eol=crlf +*.props text eol=crlf +*.filters text eol=crlf +*.vcxitems text eol=crlf +# Eclipse +*.project text +*.classpath text +*.prefs + +##### Language +# C/C++ +*.c text +*.cc text +*.cxx text +*.cpp text +*.c++ text +*.hpp text +*.h text +*.h++ text +*.hh text +*.slo binary +*.lo binary +*.o binary +*.obj binary +*.gch binary +*.pch binary +*.so binary +*.dylib binary +*.dll binary +*.lai binary +*.la binary +*.a binary +*.lib binary +*.exe binary +*.out binary +*.app binary \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c7fe547..ad51300 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,15 +1,8 @@ name: build -on: - push: - # Sequence of patterns matched against refs/heads - branches: - # Push events on main branch - - main +on: [push, pull_request] env: - CTEST_OUTPUT_ON_FAILURE: 1 - # Vulkan version UNIX_VULKAN_VERSION: 1.2.148 WINDOWS_VULKAN_VERSION: 1.2.148.0 @@ -25,121 +18,76 @@ env: CPM_SOURCE_CACHE: "${{ github.workspace }}/cpm_modules" jobs: - build: - name: ${{ matrix.config.name }} - runs-on: ${{ matrix.config.os }} + linux: strategy: - fail-fast: true + fail-fast: false matrix: - config: - - { - name: "Windows Latest MSVC", - os: windows-latest, - artifact: "windows_msvc", - build_type: "Release", - enable_doc: "OFF", - cc: "cl", - cxx: "cl", - generators: "Visual Studio 16 2019" - } - # - { - # name: "Windows Latest MinGW", - # os: windows-latest, - # artifact: "windows_mingw", - # build_type: "Release", - # cc: "gcc", - # cxx: "g++", - # generators: "Ninja" - # } - - { - name: "Ubuntu 20.04 GCC", - os: ubuntu-20.04, - artifact: "ubuntu_gcc", - build_type: "Release", - enable_doc: "ON", - cc: "gcc", - cxx: "g++", - generators: "Ninja" - } - - { - name: "Ubuntu 20.04 Clang", - os: ubuntu-20.04, - artifact: "ubuntu_clang", - build_type: "Release", - enabled_doc: "ON", - cc: "clang", - cxx: "clang++", - generators: "Ninja" - } + compiler: [ + g++-7, g++-8, g++-9, g++, + clang++-8, clang++-9, clang++ + ] + + runs-on: ubuntu-latest steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - uses: actions/checkout@v2 - name: Cache uses: actions/cache@v2 env: - cache-name: cache-conan-pip⁻chocolatey-modules + cache-name: cache-conan-pip-chocolatey-modules with: path: | ${{ env.CONAN_USER_HOME }} ${{ env.PIP_CACHE_DIR }} ${{ env.CHOCO_CACHE_DIR }} ${{ env.CPM_SOURCE_CACHE }} - key: ${{ matrix.config.os }}-${{ hashFiles('conanfile.txt') }} }} + key: ubuntu-${{ hashFiles('conanfile.txt') }} }} - ###### Windows ###### - - - name: Install Build Dependencies - if: startsWith(matrix.config.os, 'windows') + - name: Install g++-7 + if: ${{ matrix.compiler == 'g++-7' }} run: | - choco config set cacheLocation ${{ env.CHOCO_CACHE_DIR }} - choco install ninja cmake - ninja --version - cmake --version + sudo apt-get update + sudo apt-get install g++-7 -y - - name: Install Conan - if: startsWith(matrix.config.os, 'windows') + - name: Install g++-8 + if: ${{ matrix.compiler == 'g++-8' }} run: | - python -c "import sys; print(sys.version)" - python -m pip install --upgrade pip - pip install conan - - - name: Download Vulkan SDK - if: startsWith(matrix.config.os, 'windows') - run: Invoke-WebRequest "https://sdk.lunarg.com/sdk/download/$Env:WINDOWS_VULKAN_VERSION/windows/VulkanSDK-$Env:WINDOWS_VULKAN_VERSION-Installer.exe" -OutFile VulkanSDK.exe -v + sudo apt-get update + sudo apt-get install g++-8 -y - - name: Install Vulkan SDK - if: startsWith(matrix.config.os, 'windows') - run: .\VulkanSDK.exe /S - shell: cmd + - name: Install clang-8 + if: ${{ matrix.compiler == 'clang++-8' }} + run: | + sudo apt-get update + sudo apt-get install clang-8 -y - ###### Ubuntu ###### + - name: Install clang-9 + if: ${{ matrix.compiler == 'clang++-9' }} + run: | + sudo apt-get update + sudo apt-get install clang-9 -y - name: Setup Python - if: startsWith(matrix.config.os, 'ubuntu') uses: actions/setup-python@v2 with: python-version: 3.6 - name: Install Build Dependencies - if: startsWith(matrix.config.os, 'ubuntu') run: | sudo apt-get update sudo apt-get install ninja-build cmake doxygen ninja --version cmake --version gcc --version - doxygen --version + clang --version - name: Install Conan - if: startsWith(matrix.config.os, 'ubuntu') run: | pip -VV pip install --upgrade pip setuptools wheel conan - name: Install Ubuntu Dependencies - if: startsWith(matrix.config.os, 'ubuntu') run: | sudo apt-get update sudo apt-get install freeglut3-dev \ @@ -149,15 +97,12 @@ jobs: libxcb-sync-dev libxcb-xfixes0-dev libx11-xcb-dev libxcb-dri3-dev libxcb-util-dev - name: Install Vulkan SDK - if: startsWith(matrix.config.os, 'ubuntu') run: | wget -qO - https://packages.lunarg.com/lunarg-signing-key-pub.asc | sudo apt-key add - sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-$UNIX_VULKAN_VERSION-focal.list https://packages.lunarg.com/vulkan/$UNIX_VULKAN_VERSION/lunarg-vulkan-$UNIX_VULKAN_VERSION-focal.list sudo apt update sudo apt install -f vulkan-sdk - ###### General ###### - - name: Create Build Environment # Some projects don't allow in-source building, so create a separate build directory # We'll use this as our working directory for all subsequent commands @@ -167,38 +112,125 @@ jobs: # Use a bash shell so we can use the same syntax for environment variable # access regardless of the host operating system shell: bash - working-directory: ${{runner.workspace}}/build - # Note the current convention is to use the -S and -B options here to specify source - # and build directories, but this is only available with CMake 3.13 and higher. + working-directory: ${{ runner.workspace }}/build + env: + CXX: ${{ matrix.compiler }} + # Note the current convention is to use the -S and -B options here to specify source + # and build directories, but this is only available with CMake 3.13 and higher. # The CMake binaries on the Github Actions machines are (as of this writing) 3.12 run: | cmake \ $GITHUB_WORKSPACE \ - -DCMAKE_BUILD_TYPE="${{ matrix.config.build_type }}" \ - -G "${{ matrix.config.generators }}" \ - -DCMAKE_INSTALL_PREFIX="${{ runner.workspace }}/instdir" \ - -DENABLE_DOC=${{ matrix.config.enable_doc }} + -DBUILD_TESTING=ON -DBUILD_DOCS=ON -DINSTALL_APPS=ON \ + -DCMAKE_INSTALL_PREFIX="${{ runner.workspace }}/instdir" + + - name: Build + working-directory: ${{ runner.workspace }}/build + shell: bash + # Execute the build. You can specify a specific target with "--target " + run: cmake --build . --config Release + + - name: Run tests + working-directory: ${{ runner.workspace }}/build env: + CTEST_OUTPUT_ON_FAILURE: 1 + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + run: ctest --timeout 10 -C Release -j4 + + - name: Install Strip + working-directory: ${{ runner.workspace }}/build + shell: bash + run: cmake --install . --strip + + - name: Upload + uses: actions/upload-artifact@v1 + with: + path: ${{ runner.workspace }}/instdir + name: ubuntu-${{ matrix.compiler }} + + windows: + strategy: + fail-fast: false + matrix: + os: [windows-latest, windows-2016] + toolset: [clang-cl, default, v141] + include: + - toolset: clang-cl + toolset_option: -T"ClangCl" + - toolset: v141 + toolset_option: -T"v141" + exclude: + - os: windows-2016 + toolset: clang-cl + - os: windows-2016 + toolset: v141 + + runs-on: windows-latest + + steps: + - uses: actions/checkout@v2 + + - name: Cache + uses: actions/cache@v2 + env: + cache-name: cache-conan-pip-chocolatey-modules + with: + path: | + ${{ env.CONAN_USER_HOME }} + ${{ env.PIP_CACHE_DIR }} + ${{ env.CHOCO_CACHE_DIR }} + ${{ env.CPM_SOURCE_CACHE }} + key: windows-${{ hashFiles('conanfile.txt') }} }} + + - name: Install Build Dependencies + run: | + choco config set cacheLocation ${{ env.CHOCO_CACHE_DIR }} + choco install ninja cmake + ninja --version + cmake --version + + - name: Install Conan + run: | + python -c "import sys; print(sys.version)" + python -m pip install --upgrade pip + pip install conan + + - name: Download Vulkan SDK + run: Invoke-WebRequest "https://sdk.lunarg.com/sdk/download/$Env:WINDOWS_VULKAN_VERSION/windows/VulkanSDK-$Env:WINDOWS_VULKAN_VERSION-Installer.exe" -OutFile VulkanSDK.exe -v + + - name: Install Vulkan SDK + run: .\VulkanSDK.exe /S + shell: cmd + + - name: Create Build Environment + run: cmake -E make_directory ${{ runner.workspace }}/build ${{ runner.workspace }}/instdir + + - name: Configure CMake + shell: bash + working-directory: ${{runner.workspace}}/build + env: + CXX: ${{ matrix.compiler }} VULKAN_SDK: "C:\\VulkanSDK\\${{ env.WINDOWS_VULKAN_VERSION }}" - CC: ${{ matrix.config.cc }} - CXX: ${{ matrix.config.cxx }} + run: | + cmake \ + $GITHUB_WORKSPACE \ + -DBUILD_TESTING=ON -DBUILD_DOCS=ON -DINSTALL_APPS=ON \ + -DCMAKE_INSTALL_PREFIX="${{ runner.workspace }}/instdir" - name: Build working-directory: ${{ runner.workspace }}/build shell: bash - # Execute the build. You can specify a specific target with "--target " - run: cmake --build . --config ${{ matrix.config.build_type }} + run: cmake --build . --config Release env: VULKAN_SDK: "C:\\VulkanSDK\\${{ env.WINDOWS_VULKAN_VERSION }}" - - name: Test + - name: Run tests working-directory: ${{ runner.workspace }}/build - shell: bash - # Execute tests defined by the CMake configuration. - # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail - run: ctest -C ${{ matrix.config.build_type }} env: + CTEST_OUTPUT_ON_FAILURE: 1 VULKAN_SDK: "C:\\VulkanSDK\\${{ env.WINDOWS_VULKAN_VERSION }}" + run: ctest --timeout 10 -C Release -j4 - name: Install Strip working-directory: ${{ runner.workspace }}/build @@ -211,23 +243,27 @@ jobs: uses: actions/upload-artifact@v1 with: path: ${{ runner.workspace }}/instdir - name: ${{ matrix.config.artifact }} + name: windows-${{ matrix.toolset }} docs: name: Publish documentation runs-on: macos-latest - needs: build + needs: linux steps: - uses: actions/checkout@v2 - - uses: actions/download-artifact@master + - uses: actions/download-artifact@v2 with: - name: ubuntu_gcc - path: ${{ runner.workspace }}/instdir + name: ubuntu-g++ + path: ${{ runner.workspace }} + + - name: Display structure of downloaded files + working-directory: ${{ runner.workspace }} + run: ls -R - name: Publish uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ${{ runner.workspace }}/instdir/docs/doxygen/html \ No newline at end of file + publish_dir: ${{ runner.workspace }}/docs/doxygen/html \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index c0a2bf3..d33693b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,34 +1,42 @@ -cmake_minimum_required(VERSION 3.8) +# +# VulkanStarter +# -# ---- Project ---- +cmake_minimum_required(VERSION 3.12) -project(VulkanStarterStandalone VERSION 1.2.3.4 LANGUAGES CXX) +include(cmake/tools/guards.cmake) -set(LIBRARY_NAME VulkanStarter) -set(PROJECT_CXX_STANDARD 17) # for +# +# Project configuration +# +project( + VulkanStarter + DESCRIPTION "A template for Vulkan C++ projects with GLFW, GLM and ImGUI using CMake, CI, Conan and doctest" + HOMEPAGE_URL "https://github.com/florianvazelle/VulkanStarter" + LANGUAGES CXX +) + +set(CMAKE_CXX_STANDARD 17) + +# Vulkan is a required dependency. include(FindVulkan) if(NOT VULKAN_FOUND) - message(FATAL_ERROR "Vulkan SDK not installed.") + message(FATAL_ERROR "Vulkan SDK not installed.") endif() +include(cmake/tools/compile-shader.cmake) + # ---- Options ---- -option(ENABLE_TESTING "Whether to generate unit test program and test" ON) -option(ENABLE_DOC "Whether to generate documentation" OFF) +option(ENABLE_WARNINGS_SETTINGS "Allow target_set_warnings to add flags and defines." OFF) -# ---- Add source files ---- +# +# Define library target +# file(GLOB_RECURSE PROJECT_SOURCES "${CMAKE_SOURCE_DIR}/src/*.cpp") file(GLOB_RECURSE PROJECT_HEADERS "${CMAKE_SOURCE_DIR}/include/*.hpp") -file(GLOB_RECURSE PROJECT_ALL_FILES "include/*.hpp" "src/*.cpp" "app/*.cpp") - -# ---- Tool ---- - -file(GLOB_RECURSE PROJECT_MODULES "${CMAKE_SOURCE_DIR}/cmake/*.cmake") -foreach(ARG ${PROJECT_MODULES}) - include(${ARG}) -endforeach() # ---- Conan package ---- @@ -36,88 +44,74 @@ if(CONAN_EXPORTED) include(${CMAKE_CURRENT_BINARY_DIR}/conanbuildinfo.cmake) conan_basic_setup() else() - include("${CMAKE_SOURCE_DIR}/cmake/manual/conan.cmake") + include("${CMAKE_SOURCE_DIR}/cmake/conan.cmake") conan_cmake_run(CONANFILE conanfile.txt BASIC_SETUP BUILD missing) endif() file(GLOB_RECURSE EXTERNALS "${CMAKE_CURRENT_BINARY_DIR}/external/*") -# ---- Shaders ---- -file(GLOB_RECURSE SHADERS "${CMAKE_SOURCE_DIR}/assets/shader/*.vert" "${CMAKE_SOURCE_DIR}/assets/shader/*.frag") # ---- Create library ---- -add_library(${LIBRARY_NAME} OBJECT ${PROJECT_SOURCES} ${PROJECT_HEADERS} ${EXTERNALS}) +add_library(${PROJECT_NAME} OBJECT ${PROJECT_SOURCES} ${PROJECT_HEADERS} ${EXTERNALS}) -# Lib needs its header files, and users of the library must also see these (PUBLIC). -target_include_directories(${LIBRARY_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/include) -target_include_directories(${LIBRARY_NAME} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/external) +target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/include) +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/external) -target_link_libraries(${LIBRARY_NAME} PUBLIC ${CONAN_LIBS} Vulkan::Vulkan) -target_compile_definitions(${LIBRARY_NAME} PUBLIC IMGUI_IMPL_VULKAN) +target_link_libraries(${PROJECT_NAME} PUBLIC ${CONAN_LIBS} Vulkan::Vulkan) +target_compile_definitions(${PROJECT_NAME} PUBLIC IMGUI_IMPL_VULKAN) -# ---- Create Entry Point ---- +# target_set_warnings(${PROJECT_NAME} ENABLE ALL AS_ERROR ALL DISABLE Annoying) -# Add an executable for the file app/main.cc. -# If you add more executables, copy these lines accordingly. -add_executable(${PROJECT_NAME} app/main.cpp) +# ---- Compile shader into SPIR-V ---- -# Link the executable to library. -target_link_libraries(${PROJECT_NAME} PRIVATE ${LIBRARY_NAME}) +file(GLOB_RECURSE SHADERS "${CMAKE_SOURCE_DIR}/assets/shaders/*.vert" "${CMAKE_SOURCE_DIR}/assets/shaders/*.frag") -# Set the properties you require, e.g. what C++ standard to use. Here applied to library and main. -set_target_properties( - ${PROJECT_NAME} ${LIBRARY_NAME} - PROPERTIES - CXX_STANDARD ${PROJECT_CXX_STANDARD} - CXX_STANDARD_REQUIRED YES - CXX_EXTENSIONS NO -) +compile_shaders(TARGETS ${SHADERS}) -add_compile_definitions(ENGINE_NAME="No Engine") -add_compile_definitions(APP_NAME="${PROJECT_NAME}") +# +# Entry points +# -# Set up tests (see test/CMakeLists.txt). -if(ENABLE_TESTING) - enable_testing() - add_subdirectory("${CMAKE_SOURCE_DIR}/test") -endif() +option(BUILD_APPS "Enable building with entry points." ON) -# ---- Auto-generated docs ---- +if(BUILD_APPS) + # Add an executable for the file app/main.cpp + add_executable(${PROJECT_NAME}Standalone app/main.cpp) -if(ENABLE_DOC) - add_subdirectory("${CMAKE_SOURCE_DIR}/docs") -endif() + # Link the executable to library + target_link_libraries(${PROJECT_NAME}Standalone PRIVATE ${PROJECT_NAME}) -# ---- Compile shader into SPIR-V ---- + option(INSTALL_APPS "Enable installation of the entry points." OFF) -if (WIN32) - set(glslCompiler "glslangValidator.exe") -else() - set(glslCompiler "glslangValidator") + if (INSTALL_APPS) + install(DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} DESTINATION .) + endif() endif() -foreach(SHADER ${SHADERS}) - # Prepare a header and a global variable for this shader - get_filename_component(SHADER_NAME ${SHADER} NAME) - string(REPLACE "." "_" HEADER_NAME ${SHADER_NAME}) - string(TOUPPER ${HEADER_NAME} GLOBAL_SHADER_VAR) - set(SHADER_HEADER "${PROJECT_SOURCE_DIR}/include/${HEADER_NAME}") +# +# Tests +# + +option(BUILD_TESTING "Enable building tests." OFF) - add_custom_target( - ${HEADER_NAME} - COMMAND ${PROJECT_BINARY_DIR}/bin/${glslCompiler} -V ${SHADER} -o ${SHADER}.spv - COMMAND ${CMAKE_COMMAND} -DPATH="${SHADER}.spv" -DHEADER="${SHADER_HEADER}" -DGLOBAL="${GLOBAL_SHADER_VAR}" -P "${CMAKE_SOURCE_DIR}/cmake/scripts/EmbedData.cmake" - DEPENDS ${SHADER} - COMMENT "Building ${SHADER}.spv and embedding it into ${SHADER_HEADER}.h" - ) +if(BUILD_TESTING) + include(CTest) + enable_testing() + add_subdirectory(test) +endif() - add_dependencies(${LIBRARY_NAME} ${HEADER_NAME}) +# +# Documentation +# - message(STATUS "Generating build commands for ${SHADER}") -endforeach() +option(BUILD_DOCS "Enable building with documentation." OFF) -# ---- Install ---- +if(BUILD_DOCS) + find_package(Doxygen 1.8) -install(TARGETS ${PROJECT_NAME} DESTINATION bin) \ No newline at end of file + if(DOXYGEN_FOUND) + add_subdirectory(docs) + endif() +endif() \ No newline at end of file diff --git a/README.md b/README.md index 3642500..42466d8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -# VulkanStarter ![Actions Status](https://github.com/florianvazelle/VulkanStarter/workflows/build/badge.svg) +![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/florianvazelle/VulkanStarter/build/main?label=Windows%20%7C%20Linux&logo=github) +# VulkanStarter This is a template to setting up a new Vulkan C++ project. @@ -36,10 +37,11 @@ cmake --build build ## Dependencies - C++17 compiler : - - Visual Studio 2017 or 2019 - - GCC 7+ or Clang 5+ -- [CMake](https://cmake.org/) for build system creation (>= 3.8) -- [Conan](https://conan.io/) for install packages (>= 1.0) + - Visual Studio 2016 + - GCC 7+ or Clang 8+ +- [Conan](https://conan.io/) for install packages +- [Git](https://git-scm.com/) for cmake automatic dependencies +- [CMake](https://cmake.org/) for build system creation (>= 3.12) - [Doxygen](https://doxygen.org/) for generate documentation (>= 1.8, optional) ## References diff --git a/assets/shader/.gitignore b/assets/shaders/.gitignore similarity index 100% rename from assets/shader/.gitignore rename to assets/shaders/.gitignore diff --git a/assets/shader/base.frag b/assets/shaders/base.frag similarity index 100% rename from assets/shader/base.frag rename to assets/shaders/base.frag diff --git a/assets/shader/base.vert b/assets/shaders/base.vert similarity index 100% rename from assets/shader/base.vert rename to assets/shaders/base.vert diff --git a/cmake/manual/conan.cmake b/cmake/conan.cmake similarity index 100% rename from cmake/manual/conan.cmake rename to cmake/conan.cmake diff --git a/cmake/external/doctest.cmake b/cmake/external/doctest.cmake new file mode 100644 index 0000000..ae0da41 --- /dev/null +++ b/cmake/external/doctest.cmake @@ -0,0 +1,21 @@ +# https://github.com/onqtam/doctest/blob/master/doc/markdown/build-systems.md +include(ExternalProject) +find_package(Git REQUIRED) + +ExternalProject_Add( + doctest + PREFIX ${CMAKE_BINARY_DIR}/doctest + GIT_REPOSITORY https://github.com/onqtam/doctest.git + TIMEOUT 10 + UPDATE_COMMAND ${GIT_EXECUTABLE} pull + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + LOG_DOWNLOAD ON +) + +# Expose required variable (DOCTEST_INCLUDE_DIR) to parent scope +ExternalProject_Get_Property(doctest source_dir) +set(DOCTEST_INCLUDE_DIR ${source_dir}/doctest CACHE INTERNAL "Path to include folder for doctest") + +add_dependencies(${PROJECT_NAME} doctest) \ No newline at end of file diff --git a/cmake/external/mcss.cmake b/cmake/external/mcss.cmake new file mode 100644 index 0000000..404a75b --- /dev/null +++ b/cmake/external/mcss.cmake @@ -0,0 +1,20 @@ +include(ExternalProject) +find_package(Git REQUIRED) + +ExternalProject_Add( + mcss + PREFIX ${CMAKE_BINARY_DIR}/mcss + GIT_REPOSITORY https://github.com/mosra/m.css.git + TIMEOUT 10 + UPDATE_COMMAND ${GIT_EXECUTABLE} pull + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + LOG_DOWNLOAD ON +) + +# Expose required variable (MCSS_INCLUDE_DIR) to parent scope +ExternalProject_Get_Property(mcss source_dir) +set(MCSS_SOURCE_DIR ${source_dir} CACHE INTERNAL "Path to include folder for mcss") + +add_dependencies(${PROJECT_NAME} mcss) \ No newline at end of file diff --git a/cmake/guards.cmake b/cmake/guards.cmake deleted file mode 100644 index a066763..0000000 --- a/cmake/guards.cmake +++ /dev/null @@ -1,18 +0,0 @@ -# Not allowed to compile in the source directory -if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) - message(FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there.") -endif() - -# Guard against bad build-type strings -if (NOT CMAKE_BUILD_TYPE) - message(STATUS "No build type selected, default to Debug") - set(CMAKE_BUILD_TYPE "Debug") -endif() - -# Guard build type -string(TOLOWER "${CMAKE_BUILD_TYPE}" cmake_build_type_tolower) -string(TOUPPER "${CMAKE_BUILD_TYPE}" cmake_build_type_toupper) -if( NOT cmake_build_type_tolower STREQUAL "debug" - AND NOT cmake_build_type_tolower STREQUAL "release") - message(FATAL_ERROR "Unknown build type \"${CMAKE_BUILD_TYPE}\". Allowed values are Debug, Release (case-insensitive).") -endif() \ No newline at end of file diff --git a/cmake/manual/cpm.cmake b/cmake/manual/cpm.cmake deleted file mode 100644 index 1afd310..0000000 --- a/cmake/manual/cpm.cmake +++ /dev/null @@ -1,20 +0,0 @@ - -set(CPM_DOWNLOAD_VERSION 0.28.0) - -if(CPM_SOURCE_CACHE) - set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") -elseif(DEFINED ENV{CPM_SOURCE_CACHE}) - set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") -else() - set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake") -endif() - -if(NOT (EXISTS ${CPM_DOWNLOAD_LOCATION})) - message(STATUS "Downloading CPM.cmake to ${CPM_DOWNLOAD_LOCATION}") - file(DOWNLOAD - https://github.com/TheLartians/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake - ${CPM_DOWNLOAD_LOCATION} - ) -endif() - -include(${CPM_DOWNLOAD_LOCATION}) \ No newline at end of file diff --git a/cmake/scripts/EmbedData.cmake b/cmake/scripts/embed-data.cmake similarity index 96% rename from cmake/scripts/EmbedData.cmake rename to cmake/scripts/embed-data.cmake index 1addf21..ac30c3a 100644 --- a/cmake/scripts/EmbedData.cmake +++ b/cmake/scripts/embed-data.cmake @@ -41,5 +41,5 @@ endfunction() # let's use it as a script if(EXISTS "${PATH}") - embed_resource("${PATH}" "${HEADER}.h" "${GLOBAL}") + embed_resource("${PATH}" "${HEADER}" "${GLOBAL}") endif() diff --git a/cmake/tools/compile-shader.cmake b/cmake/tools/compile-shader.cmake new file mode 100644 index 0000000..61bb08a --- /dev/null +++ b/cmake/tools/compile-shader.cmake @@ -0,0 +1,51 @@ +#################################################################################################### +# This function compile any GLSL shader into SPIR-V shader and embed it in a C header file. +# Example: +# compile_shaders(TARGETS "assets/shader/basic.frag" "assets/shader/basic.vert") +#################################################################################################### + +function(compile_shaders) + + include(CMakeParseArguments) + cmake_parse_arguments(SHADERS "" "" "TARGETS" ${ARGN}) + + # Note: if it remains unparsed arguments, here, they can be found in variable PARSED_ARGS_UNPARSED_ARGUMENTS + if(NOT SHADERS) + message(FATAL_ERROR "You must provide targets.") + endif() + + # Find the glslangValidator executable + if(WIN32) + set(glslCompiler "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/glslangValidator.exe") + else() + set(glslCompiler "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/glslangValidator") + endif() + + # For each shader, we create a header file + foreach(SHADER ${SHADERS}) + + # Prepare a header name and a global variable for this shader + get_filename_component(SHADER_NAME ${SHADER} NAME) + string(REPLACE "." "_" HEADER_NAME ${SHADER_NAME}) + string(TOUPPER ${HEADER_NAME} GLOBAL_SHADER_VAR) + + set(SHADER_HEADER "${PROJECT_SOURCE_DIR}/include/${HEADER_NAME}.h") + + add_custom_target( + ${HEADER_NAME} + # Compile any GLSL shader into SPIR-V shader + COMMAND ${glslCompiler} -V ${SHADER} -o ${SHADER}.spv + # Make a C header file with the SPIR-V shader + COMMAND ${CMAKE_COMMAND} -DPATH="${SHADER}.spv" -DHEADER="${SHADER_HEADER}" -DGLOBAL="${GLOBAL_SHADER_VAR}" -P "${CMAKE_SOURCE_DIR}/cmake/scripts/embed-data.cmake" + # Rebuild the header file if the shader is updated + DEPENDS ${SHADER} + COMMENT "Building ${SHADER}.spv and embedding it into ${SHADER_HEADER}" + ) + + # Add the custom target like a dependencies of the project + add_dependencies(${PROJECT_NAME} ${HEADER_NAME}) + + message(STATUS "Generating build commands for ${SHADER}") + endforeach() + +endfunction() \ No newline at end of file diff --git a/cmake/tools/guards.cmake b/cmake/tools/guards.cmake new file mode 100644 index 0000000..6a0e68d --- /dev/null +++ b/cmake/tools/guards.cmake @@ -0,0 +1,23 @@ +# Building in-tree is not allowed (we take care of your craziness). +if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) + message(FATAL_ERROR "Prevented in-tree built. Please create a build directory outside of the source code and call cmake from there. Thank you.") +endif() + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +# https://stackoverflow.com/questions/41361631/optimize-in-cmake-by-default +if(NOT CMAKE_BUILD_TYPE) + message(STATUS "No build type selected, default to Release") + set(CMAKE_BUILD_TYPE Release) +endif() + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") +set(CMAKE_CXX_FLAGS_DEBUG "-g") +set(CMAKE_CXX_FLAGS_RELEASE "-O3") + +# https://stackoverflow.com/questions/6594796/how-do-i-make-cmake-output-into-a-bin-dir +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) \ No newline at end of file diff --git a/cmake/tools/warnings.cmake b/cmake/tools/warnings.cmake new file mode 100644 index 0000000..8b27e43 --- /dev/null +++ b/cmake/tools/warnings.cmake @@ -0,0 +1,125 @@ +# Helper script to set warnings +# Usage : +# target_set_warnings(target +# [ENABLE [ALL] [list of warning names]] +# [DISABLE [ALL/Annoying] [list of warning names]] +# [AS_ERROR ALL] +# ) +# +# ENABLE +# * ALL: means all the warnings possible to enable through a one parameter switch. +# Note that for some compilers, this does not mean every single warning will be enabled (GCC for instance). +# * Any other name: enable the warning with the given name +# +# DISABLE +# * ALL: will override any other settings and this target INTERFACE includes will be considered as system includes by targets linking it. +# * Annoying: Warnings that the author thinks should only be used as static analysis tools not in production. On MSVC, also sets _CRT_SECURE_NO_WARNINGS. +# * Any other name: disable the warning with the given name +# +# AS_ERROR +# * ALL: is the only option available as not all compilers let us set specific warnings as error from command line (MSVC). + +cmake_minimum_required(VERSION 3.8) + +option(ENABLE_WARNINGS_SETTINGS "Allow target_set_warnings to add flags and defines. Set this to OFF if you want to provide your own warning parameters." ON) + +function(target_set_warnings) + if(NOT ENABLE_WARNINGS_SETTINGS) + return() + endif() + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + set(WMSVC TRUE) + set(WARNING_ENABLE_PREFIX "/w1") # Means the warning will be available at all levels that do emit warnings + set(WARNING_DISABLE_PREFIX "/wd") + elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + set(WGCC TRUE) + set(WARNING_ENABLE_PREFIX "-W") + set(WARNING_DISABLE_PREFIX "-Wno-") + elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") + set(WCLANG TRUE) + set(WARNING_ENABLE_PREFIX "-W") + set(WARNING_DISABLE_PREFIX "-Wno-") + endif() + set(multiValueArgs ENABLE DISABLE AS_ERROR) + cmake_parse_arguments(this "" "" "${multiValueArgs}" ${ARGN}) + list(FIND this_ENABLE "ALL" enable_all) + list(FIND this_DISABLE "ALL" disable_all) + list(FIND this_AS_ERROR "ALL" as_error_all) + if(NOT ${enable_all} EQUAL -1) + if(WMSVC) + # Not all the warnings, but WAll is unusable when using libraries + # Unless you'd like to support MSVC in the code with pragmas, this is probably the best option + list(APPEND WarningFlags "/W4") + elseif(WGCC) + list(APPEND WarningFlags "-Wall" "-Wextra" "-Wpedantic") + elseif(WCLANG) + list(APPEND WarningFlags "-Wall" "-Weverything" "-Wpedantic") + endif() + elseif(NOT ${disable_all} EQUAL -1) + set(SystemIncludes TRUE) # Treat includes as if coming from system + if(WMSVC) + list(APPEND WarningFlags "/w" "/W0") + elseif(WGCC OR WCLANG) + list(APPEND WarningFlags "-w") + endif() + endif() + + list(FIND this_DISABLE "Annoying" disable_annoying) + if(NOT ${disable_annoying} EQUAL -1) + if(WMSVC) + # bounds-checked functions require to set __STDC_WANT_LIB_EXT1__ which we usually don't need/want + list(APPEND WarningDefinitions -D_CRT_SECURE_NO_WARNINGS) + # disable C4514 C4710 C4711... Those are useless to add most of the time + #list(APPEND WarningFlags "/wd4514" "/wd4710" "/wd4711") + #list(APPEND WarningFlags "/wd4365") #signed/unsigned mismatch + #list(APPEND WarningFlags "/wd4668") # is not defined as a preprocessor macro, replacing with '0' for + elseif(WGCC OR WCLANG) + list(APPEND WarningFlags -Wno-switch-enum) + if(WCLANG) + list(APPEND WarningFlags -Wno-unknown-warning-option -Wno-padded -Wno-undef -Wno-reserved-id-macro -Wno-inconsistent-missing-destructor-override -fcomment-block-commands=test,retval) + if(NOT CMAKE_CXX_STANDARD EQUAL 98) + list(APPEND WarningFlags -Wno-c++98-compat -Wno-c++98-compat-pedantic) + endif() + if ("${CMAKE_CXX_SIMULATE_ID}" STREQUAL "MSVC") # clang-cl has some VCC flags by default that it will not recognize... + list(APPEND WarningFlags -Wno-unused-command-line-argument) + endif() + endif(WCLANG) + endif() + endif() + + if(NOT ${as_error_all} EQUAL -1) + if(WMSVC) + list(APPEND WarningFlags "/WX") + elseif(WGCC OR WCLANG) + list(APPEND WarningFlags "-Werror") + endif() + endif() + + if(this_ENABLE) + list(REMOVE_ITEM this_ENABLE ALL) + foreach(warning-name IN LISTS this_ENABLE) + list(APPEND WarningFlags "${WARNING_ENABLE_PREFIX}${warning-name}") + endforeach() + endif() + + + if(this_DISABLE) + list(REMOVE_ITEM this_DISABLE ALL Annoying) + foreach(warning-name IN LISTS this_DISABLE) + list(APPEND WarningFlags "${WARNING_DISABLE_PREFIX}${warning-name}") + endforeach() + endif() + + foreach(target IN LISTS this_UNPARSED_ARGUMENTS) + if(WarningFlags) + target_compile_options(${target} PRIVATE ${WarningFlags}) + endif() + if(WarningDefinitions) + target_compile_definitions(${target} PRIVATE ${WarningDefinitions}) + endif() + if(SystemIncludes) + set_target_properties(${target} PROPERTIES + INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $) + endif() + endforeach() +endfunction(target_set_warnings) \ No newline at end of file diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index a940a25..5057317 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -1,15 +1,8 @@ -# ---- Dependencies ---- +include(../cmake/external/mcss.cmake) -include(../cmake/manual/cpm.cmake) - -CPMAddPackage( - NAME MCSS - DOWNLOAD_ONLY YES - GITHUB_REPOSITORY mosra/m.css - GIT_TAG 42d4a9a48f31f5df6e246c948403b54b50574a2a -) - -# ---- Doxygen variables ---- +# +# Doxygen configuration (documentation) +# # set Doxyfile variables set(DOXYGEN_PROJECT_NAME ${PROJECT_NAME}) @@ -18,17 +11,17 @@ set(DOXYGEN_PROJECT_ROOT "${CMAKE_CURRENT_LIST_DIR}/..") set(DOXYGEN_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/doxygen") configure_file(${CMAKE_CURRENT_LIST_DIR}/Doxyfile ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) - configure_file(${CMAKE_CURRENT_LIST_DIR}/conf.py ${CMAKE_CURRENT_BINARY_DIR}/conf.py) add_custom_target( GenerateDocs ${CMAKE_COMMAND} -E make_directory "${DOXYGEN_OUTPUT_DIRECTORY}" COMMAND "${MCSS_SOURCE_DIR}/documentation/doxygen.py" "${CMAKE_CURRENT_BINARY_DIR}/conf.py" + DEPENDS mcss COMMENT "Docs written to: ${DOXYGEN_OUTPUT_DIRECTORY}" WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" ) -add_dependencies(${LIBRARY_NAME} GenerateDocs) +add_dependencies(${PROJECT_NAME} GenerateDocs) install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} DESTINATION .) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ccb3b01..f55d7b1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,27 +1,21 @@ -cmake_minimum_required(VERSION 3.8) +include(../cmake/external/doctest.cmake) + +# +# Tests configuration +# -# ---- Project ---- set(TEST_MAIN ${PROJECT_NAME}Tests) set(TEST_RUNNER_PARAMS "") -# ---- Add source files ---- file(GLOB_RECURSE PROJECT_TEST_SOURCES "${CMAKE_SOURCE_DIR}/test/src/*.cpp") -# ---- Create Entry Point ---- add_executable(${TEST_MAIN} ${PROJECT_TEST_SOURCES}) -# Link the executable to library. -target_link_libraries(${TEST_MAIN} PRIVATE ${LIBRARY_NAME}) +# Link the executable to our library +target_link_libraries(${TEST_MAIN} PRIVATE ${PROJECT_NAME}) -set_target_properties(${TEST_MAIN} PROPERTIES - RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR} - CXX_STANDARD ${PROJECT_CXX_STANDARD} - CXX_STANDARD_REQUIRED YES - CXX_EXTENSIONS NO -) +# Add doctest +target_include_directories(${TEST_MAIN} PRIVATE ${DOCTEST_INCLUDE_DIR}) -# add in ctest -add_test( - # Use some per-module/project prefix so that it is easier to run only tests for this module - NAME ${LIBRARY_NAME}.${TEST_MAIN} - COMMAND ${TEST_MAIN} ${TEST_RUNNER_PARAMS}) \ No newline at end of file +# Add in ctest +add_test(NAME ${PROJECT_NAME}.${TEST_MAIN} COMMAND ${TEST_MAIN} ${TEST_RUNNER_PARAMS}) \ No newline at end of file