diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index bfcf4443d..e4d6a7c7d 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -34,7 +34,15 @@ jobs: - { name: "Ubuntu GCC-12", os: ubuntu-latest, - compiler: { type: GCC, version: 12, conan: "gcc", cc: "gcc-12", cxx: "g++-12", std: 20 }, + compiler: + { + type: GCC, + version: 12, + conan: "gcc", + cc: "gcc-12", + cxx: "g++-12", + std: 20 + }, lib: "libstdc++11" } - { @@ -88,7 +96,15 @@ jobs: - { name: "Visual Studio 2019", os: windows-latest, - compiler: { type: VISUAL, version: 16, conan: "mscv", cc: "cl", cxx: "cl", std: 20 }, + compiler: + { + type: VISUAL, + version: 16, + conan: "mscv", + cc: "cl", + cxx: "cl", + std: 20 + }, } - { name: "MacOS Apple Clang 14", @@ -130,9 +146,9 @@ jobs: key: ${{ hashFiles('**/conanfile.py') }}-build-${{ matrix.settings.os }}-${{ matrix.configuration }}-${{ matrix.settings.compiler.conan }}-${{ matrix.settings.compiler.version }}-${{ matrix.settings.lib }} restore-keys: | ${{ hashFiles('**/conanfile.py') }}-build-${{ matrix.settings.os }}-${{ matrix.configuration }}-${{ matrix.settings.compiler.conan }}-${{ matrix.settings.compiler.version }}- - ${{ hashFiles('**/conanfile.py') }}-build-${{ matrix.settings.os }}-${{ matrix.configuration }}-${{ matrix.settings.compiler.conan }}- - ${{ hashFiles('**/conanfile.py') }}-build-${{ matrix.settings.os }}-${{ matrix.configuration }}- - ${{ hashFiles('**/conanfile.py') }}-build-${{ matrix.settings.os }}- + #${{ hashFiles('**/conanfile.py') }}-build-${{ matrix.settings.os }}-${{ matrix.configuration }}-${{ matrix.settings.compiler.conan }}- + #${{ hashFiles('**/conanfile.py') }}-build-${{ matrix.settings.os }}-${{ matrix.configuration }}- + #${{ hashFiles('**/conanfile.py') }}-build-${{ matrix.settings.os }}- # - uses: lhotari/action-upterm@v1 # with: @@ -214,10 +230,18 @@ jobs: conan profile show -pr default - name: Configure Install + if: matrix.settings.os != 'windows-latest' + working-directory: ${{github.workspace}} + shell: bash + run: | + conan install "${{github.workspace}}" --build missing -pr:b default -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" -o boost/*:without_cobalt=True + + - name: Configure Install + if: matrix.settings.os == 'windows-latest' working-directory: ${{github.workspace}} shell: bash run: | - conan install "${{github.workspace}}" --build missing -pr:b default -o boost/*:without_cobalt=True + conan install "${{github.workspace}}" --build missing -pr:b default -o boost/*:without_cobalt=True -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" - name: Configure Conan Build if: matrix.settings.os == 'windows-latest' @@ -241,29 +265,79 @@ jobs: # detached: true - name: Configure CMake - if: matrix.settings.os == 'windows-latest' + if: matrix.settings.os == 'windows-latest' && matrix.configuration == 'Release' shell: cmd run: | cmake --version call build\generators\conanbuild.bat - cmake --preset conan-default -DENABLE_ADDRESS_SANITIZER=ON -DENABLE_UNDEFINED_BEHAVIOUR_SANITIZER=ON + cmake --preset conan-default -DENABLE_ADDRESS_SANITIZER=ON -DENABLE_UNDEFINED_BEHAVIOUR_SANITIZER=ON -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_VS_GLOBALS="UseMultiToolTask=true;EnforceProcessCountAcrossBuilds=true" - name: Configure CMake - if: matrix.settings.os != 'windows-latest' + if: matrix.settings.os == 'windows-latest' && matrix.configuration == 'Debug' + shell: cmd + run: | + cmake --version + call build\generators\conanbuild.bat + cmake --preset conan-default -DENABLE_ADDRESS_SANITIZER=ON -DENABLE_UNDEFINED_BEHAVIOUR_SANITIZER=ON -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_FLAGS_DEBUG="/YI;/Z7" -DCMAKE_VS_GLOBALS="UseMultiToolTask=true;EnforceProcessCountAcrossBuilds=true;TrackFileAccess=false;DebugInformationFormat=OldStyle" + + - name: Configure CMake + if: matrix.settings.os != 'windows-latest' && matrix.settings.compiler.type == 'GCC' shell: bash run: | source build/generators/conanbuild.sh - cmake --preset conan-default -DENABLE_ADDRESS_SANITIZER=ON -DENABLE_UNDEFINED_BEHAVIOUR_SANITIZER=ON + cmake --preset conan-default -DENABLE_ADDRESS_SANITIZER=ON -DENABLE_UNDEFINED_BEHAVIOUR_SANITIZER=ON -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + + - name: Configure CMake + if: matrix.settings.os != 'windows-latest' && matrix.settings.compiler.type != 'GCC' + shell: bash + run: | + source build/generators/conanbuild.sh + cmake --preset conan-default -DENABLE_ADDRESS_SANITIZER=ON -DENABLE_UNDEFINED_BEHAVIOUR_SANITIZER=ON -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_FLAGS_DEBUG="-Xclang -fno-pch-timestamp" -DCMAKE_CXX_FLAGS_RELEASE="-Xclang -fno-pch-timestamp" - name: Conan Preset shell: bash run: echo "CONAN_PRESET=conan-$(echo ${{matrix.configuration}} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV + - name: CCache Configure + if: matrix.settings.os != 'windows-latest' + id: ccache-config-linux + shell: bash + run: | + mkdir $HOME/.ccache + echo "CCACHE_HOME=$HOME/.ccache" >> $GITHUB_ENV + + - name: Cache CCache data + if: matrix.settings.os == 'windows-latest' + uses: actions/cache@v3.3.2 + with: + path: C:\Users\runneradmin\AppData\Local\ccache\ + key: ccache-${{ matrix.settings.os }}-${{ matrix.configuration }}-${{ matrix.settings.compiler.conan }}-${{ matrix.settings.compiler.version }}-${{ matrix.settings.lib }}-${{ github.run_number }} + restore-keys: | + ccache-${{ matrix.settings.os }}-${{ matrix.configuration }}-${{ matrix.settings.compiler.conan }}-${{ matrix.settings.compiler.version }}-${{ matrix.settings.lib }}- + + - name: Cache CCache data + if: matrix.settings.os != 'windows-latest' + uses: actions/cache@v3.3.2 + with: + path: ${{ env.CCACHE_HOME }} + key: ccache-${{ matrix.settings.os }}-${{ matrix.configuration }}-${{ matrix.settings.compiler.conan }}-${{ matrix.settings.compiler.version }}-${{ matrix.settings.lib }}-${{ github.run_number }} + restore-keys: | + ccache-${{ matrix.settings.os }}-${{ matrix.configuration }}-${{ matrix.settings.compiler.conan }}-${{ matrix.settings.compiler.version }}-${{ matrix.settings.lib }}- + - name: Build if: matrix.settings.os == 'windows-latest' shell: cmd run: | call build\generators\conanbuild.bat + set CCACHE_BASEDIR=${{ github.workspace }} + set CCACHE_LOGFILE=D:\\a\\Morpheus\\Morpheus\\build\\CcacheLogFile.log + set CCACHE_NOHASHDIR=1 + set CCACHE_SLOPPINESS=pch_defines,time_macros,include_file_mtime,include_file_ctime + REM set CCACHE_DEBUG=1 + REM set CCACHE_DEBUGDIR=D:\\a\\Morpheus\\Morpheus\\build\\ + REM set CCACHE_RECACHE=1 + echo Morpheus ccache show configuration + ccache -p cmake --build --preset ${{ env.CONAN_PRESET }} - name: Build @@ -271,8 +345,52 @@ jobs: shell: bash run: | source build/generators/conanbuild.sh + export CCACHE_BASEDIR=${{ github.workspace }} + export CCACHE_DIR=$HOME/.ccache + export CCACHE_LOGFILE=$HOME/.ccache/CcacheLogFile.log + export CCACHE_NOHASHDIR=1 + export CCACHE_SLOPPINESS=pch_defines,time_macros,include_file_mtime,include_file_ctime + #export CCACHE_DEBUG=1 + #export CCACHE_DEBUGDIR=$HOME/.ccache/ + #export CCACHE_RECACHE=1 + echo "Morpheus ccache show configuration" + ccache -p cmake --build --preset ${{ env.CONAN_PRESET }} + - name: CCache Stats + if: matrix.settings.os == 'windows-latest' + shell: cmd + run: | + call build\generators\conanbuild.bat + echo Morpheus ccache show stats + ccache -d C:\Users\runneradmin\AppData\Local\ccache\ -svvz + echo Morpheus showing ccache log files + type D:\a\Morpheus\Morpheus\build\CcacheLogFile.log + REM echo Morpheus showing ccache debug input files + REM forfiles /M *.ccache-input-text /S /C "cmd /c type @file" + REM echo Morpheus showing ccache debug log files + REM forfiles /M *.ccache-log /S /C "cmd /c type @file" + REM dir D:\a\Morpheus\Morpheus\build + REM rm D:\a\Morpheus\Morpheus\build\CcacheLogFile.log + REM dir D:\a\Morpheus\Morpheus\build + + - name: CCache Stats + if: matrix.settings.os != 'windows-latest' + shell: bash + run: | + source build/generators/conanbuild.sh + echo "Morpheus ccache show stats" + ccache -d $HOME/.ccache -svvz + echo "Morpheus show ccache log files" + cat $HOME/.ccache/CcacheLogFile.log + #echo "Morpheus showing ccache debug input files" + #find . -name "*.ccache-input-text" -exec cat {} + + #echo "Morpheus showing ccache debug log files" + #find . -name "*.ccache-log" -exec cat {} + + #ls -la $HOME/.ccache + #rm $HOME/.ccache/CcacheLogFile.log + #ls -la $HOME/.ccache + - name: Test # Execute tests defined by the CMake configuration. # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail diff --git a/.github/workflows/code_coverage.yml b/.github/workflows/code_coverage.yml index e2e468aeb..98a91630b 100644 --- a/.github/workflows/code_coverage.yml +++ b/.github/workflows/code_coverage.yml @@ -51,12 +51,9 @@ jobs: cache-name: cache-conan-data with: path: ${{github.workspace}}/.conan2/p - key: ${{ hashFiles('**/conanfile.py') }}-build-${{ matrix.settings.os }}-${{ matrix.configuration }}-${{ matrix.settings.compiler.conan }}-${{ matrix.settings.compiler.version }}-${{ matrix.settings.lib }} + key: ${{ hashFiles('**/conanfile.py') }}-code-coverage restore-keys: | - ${{ hashFiles('**/conanfile.py') }}-build-${{ matrix.settings.os }}-${{ matrix.configuration }}-${{ matrix.settings.compiler.conan }}-${{ matrix.settings.compiler.version }}- - ${{ hashFiles('**/conanfile.py') }}-build-${{ matrix.settings.os }}-${{ matrix.configuration }}-${{ matrix.settings.compiler.conan }}- - ${{ hashFiles('**/conanfile.py') }}-build-${{ matrix.settings.os }}-${{ matrix.configuration }}- - ${{ hashFiles('**/conanfile.py') }}-build-${{ matrix.settings.os }}- + ${{ hashFiles('**/conanfile.py') }}-code-coverage # Previously GCC was installed via egor-tensin/setup-gcc@v1 but this does not install gcov with the compiler. # By default Ubuntu has Gcov 11 installed. This worked so long as the compiler was gcc 11, but if a later gcc was @@ -127,7 +124,14 @@ jobs: working-directory: ${{github.workspace}} shell: bash run: | - conan install "${{github.workspace}}" --build missing -o boost/*:without_cobalt=True + # In order to have ccache working correctly we can't build the catch library every time, otherwise the hash of the built files will + # change at every workflow run and then we will get cache misses. Therefore the --build catch2/3.4.0 option must be enabled only the + # first time in order to correctly build the cache for Conan packages. After the first build of the Conan cache the option must + # be removed for all the subsequent executions. + # The same procedure must be followed every time that it changes something in the conanfile.py. + # it's a bit tricky but it is what it is, this is what must be done in order to get 100% ccache hit rate. + #conan install "${{github.workspace}}" --build missing -c tools.cmake.cmaketoolchain:generator=Ninja --build catch2/3.4.0 --build gtest/1.14.0 + conan install "${{github.workspace}}" --build missing -c tools.cmake.cmaketoolchain:generator=Ninja -o boost/*:without_cobalt=True - name: Conan Preset shell: bash @@ -138,14 +142,58 @@ jobs: # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: | source build/${{env.BUILD_TYPE}}/generators/conanbuild.sh - cmake --preset ${{ env.CONAN_PRESET }} -DENABLE_CODE_COVERAGE=1 + cmake --preset ${{ env.CONAN_PRESET }} -DENABLE_CODE_COVERAGE=1 -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + + - name: CCache Configure + shell: bash + run: | + source build/${{env.BUILD_TYPE}}/generators/conanbuild.sh + mkdir $HOME/.ccache + echo "CCACHE_HOME=$HOME/.ccache" >> $GITHUB_ENV + + - name: Cache CCache data + uses: actions/cache@v3.3.2 + with: + path: ${{ env.CCACHE_HOME }} + key: ccache-code-coverage-${{ github.run_number }} + restore-keys: | + ccache-code-coverage- - name: Build # Build your program with the given configuration + shell: bash run: | source build/${{env.BUILD_TYPE}}/generators/conanbuild.sh + export CCACHE_DIR=$HOME/.ccache + export CCACHE_SLOPPINESS=pch_defines,time_macros,include_file_mtime,include_file_ctime + export CCACHE_NOHASHDIR=1 + export CCACHE_BASEDIR=${{ github.workspace }} + export CCACHE_LOGFILE=$HOME/.ccache/CcacheLogFile.log + #export CCACHE_DEBUG=1 + #export CCACHE_UMASK=002 + #export CCACHE_NOINODECACHE=1 + #export CCACHE_RECACHE=1 + #export CCACHE_DEBUGDIR=$HOME/.ccache/ + echo "Morpheus ccache show configuration" + ccache -p cmake --build --preset ${{ env.CONAN_PRESET }} + - name: CCache Stats + shell: bash + run: | + source build/${{env.BUILD_TYPE}}/generators/conanbuild.sh + echo "Morpheus ccache show stats" + ccache -d $HOME/.ccache -svvz + echo "Morpheus showing ccache log file" + cat $HOME/.ccache/CcacheLogFile.log + #echo "Morpheus showing ccache debug log files" + #find . -name "*.ccache-log" -exec cat {} + + #echo "Morpheus showing ccache debug input files" + #find . -name "*.ccache-input-text" -exec cat {} + + #ls -la $HOME/.ccache + #rm $HOME/.ccache/CcacheLogFile.log + #ls -la $HOME/.ccache + - name: Test working-directory: ${{github.workspace}} # Execute tests defined by the CMake configuration. diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d996f84e..4bb7fc96e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,6 +24,7 @@ include(GNUInstallDirs) include(CMakeDependentOption) include(CMakePackageConfigHelpers) +option(MORPHEUS_BUILD_WITH_CCACHE "Enable the CCache compiler caching" ON) option(MORPHEUS_RENDER_SYSTEM_DIRECT_X12 "Build with support for the Dirext X 12 render system" ON) option(MORPHEUS_RENDER_SYSTEM_METAL "Build with support for the Metal render system" ON) option(MORPHEUS_RENDER_SYSTEM_OPENGL "Build with support for the Open GL render system" ON) @@ -46,6 +47,7 @@ list(APPEND CMAKE_PREFIX_PATH "${CMAKE_BINARY_DIR}" "${CMAKE_BINARY_DIR}/generat #------------------------------------------------------------------------------------------------------------------------------------------ # Custom CMake Includes +include(ccache) include(coverage) include(compiler) include(conformance) @@ -82,7 +84,7 @@ set(CMAKE_BUILD_WITH_INSTALL_RPATH ON) set(CMAKE_SKIP_BUILD_RPATH FALSE) get_property(IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) -if(IS_MULTI_CONFIG) +if (IS_MULTI_CONFIG) set(RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/$) set(LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib/$) file(RELATIVE_PATH MORPHEUS_RELATIVE_BUILD_RPATH ${RUNTIME_OUTPUT_DIRECTORY} ${LIBRARY_OUTPUT_DIRECTORY}) @@ -100,6 +102,23 @@ endif() add_subdirectory(libraries) add_subdirectory(examples) +#[[ +Ccache / Icecream options management +In order to add/remove configuration options for ccache call the function enable_ccache with the following parameters: +DEBUG to enable debugging +ICECC to enable Icecream build support +LOGFILE to enable ccache logging to file +NOHASHDIR to exclude the current working directory from the cache hash +QUIET Searches for the ccache executable, and if found enables it for supported language with specified options +RECACHE ccache will not use any previously stored result. New results will overwrite any pre-existing results +SLOPPINESS ccache to relax some checks in order to increase the hit rate of cache hits +reference documentation: https://ccache.dev/documentation.html +]] +if (MORPHEUS_BUILD_WITH_CCACHE) + set(LANGUAGES CXX) + enable_ccache(QUIET LANGUAGES ICECC NOHASHDIR SLOPPINESS) +endif() + if (ENABLE_CODE_COVERAGE) enable_code_coverage() endif() diff --git a/README.md b/README.md index 4eae16ecf..e9974952d 100644 --- a/README.md +++ b/README.md @@ -58,10 +58,14 @@ To enable Mold linker usage for gcc and clang with Linux: conan install ./ -pr:h .conan2/profiles/gcc/12/x64-libstdc++11-debug -pr:b .conan2/profiles/gcc/12/x64-libstdc++11-debug --build missing source build/Debug/generators/conanbuild.sh # Access the environment variables needed to use the Mold linker with gcc and clang ``` -To disable Mold linker usage for gcc and clang with Linux: +To disable Mold linker usage for compilers gcc and clang with Linux: ```bash conan install ./ -pr:h .conan2/profiles/gcc/12/x64-libstdc++11-debug -pr:b .conan2/profiles/gcc/12/x64-libstdc++11-debug --build missing -o link_with_mold=False ``` +To disable CCache usage for compilers gcc and clang with Linux and macOS: +```bash +conan install ./ -pr:h .conan2/profiles/gcc/12/x64-libstdc++11-debug -pr:b .conan2/profiles/gcc/12/x64-libstdc++11-debug --build missing -o build_with_ccache=False +``` Use the preset generated by Conan ```bash cmake --preset conan-debug @@ -75,6 +79,7 @@ cmake --build --preset conan-debug ### Multi-Config Build Multi-config builds allow you to create a build folder containing sub-folders for different build configurations and build them side-by-side. Once again starting with the repository clone and Conan configured run the install stage, but this time we specity the Conan cmake tools use Ninja multi-config to generate `Release, Debug, RelWithDebInfo` configurations. To generate all 3 configuration we run the `conan-default` preset which configures CMake for these configurations. +Instructions about how to build the library with Visual Studio and Ninja Multi-Config can be found [here](./WINDOWS.md) ```bash conan install ./ -pr:h .conan2/profiles/msvc/193/x64-release -pr:b .conan2/profiles/msvc/193/x64-release --build missing -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" source build/generators/conanbuild.sh # Access the environment variables needed to use the Mold linker with gcc and clang diff --git a/VisualStudioInstall.png b/VisualStudioInstall.png new file mode 100644 index 000000000..f366428c7 Binary files /dev/null and b/VisualStudioInstall.png differ diff --git a/WINDOWS.md b/WINDOWS.md new file mode 100644 index 000000000..9fa61efba --- /dev/null +++ b/WINDOWS.md @@ -0,0 +1,58 @@ +## Visual Studio and Ninja Multi-Config Build Instructions + +The build use CMake for build system generation and Conan 2 for dependency management. Prerequisites for building are: + - A supported C++ compiler + * GCC, 11.x and later + * Clang, 14.x and later + * MSCV, 2022 and later + - Python + - Git + +Visual Studio 2022 can be downloaded from Microsoft [website](https://visualstudio.microsoft.com/vs/community/) +A minimum working installation to support the project build will have the following details: +![](./VisualStudioInstall.png) + +In general you can use your own [Conan profile](https://docs.conan.io/2/reference/commands/profile.html) but the project ships with profiles for all supported configurations. I you use your own profile then ensure that if you are building again libstdc++ with GCC or Clang that you build on the C++11 and onwards version. To do so insert the following into your Conan profile under the `[settings]` section: + +``` +compiler.libcxx=libstdc++11 +``` + +However, preferably use one of the pre-installed configurations in `/.conan/profiles` (which are installed via the `conan config install ./conan` command to the local conan configuration folder ./.conan2 as specified in the ./.conanrc file) as these are tested and known to work. + +### Cloning the Repo + +To clone the repo use git to clone the repository to your local machine: + +```bash +git clone https://github.com/Twon/Morpheus.git +``` + +### Configuring Conan + +To set up Conan for the repository create a repository local virtual environment for Python and [activate the environment (note this step differs for different shells)](https://docs.python.org/3/library/venv.html#how-venvs-work) +For Windows build with Visual Studio run the [Developer Command Prompt for Visual Studio 2022](https://learn.microsoft.com/en-us/visualstudio/ide/reference/command-prompt-powershell?view=vs-2022#start-in-visual-studio) + +```bash +cd +python -m venv .venv # Create a Python virtual env +.venv\Scripts\activate.bat # Activate the virtual env for bash by source. +pip install -r ./requirements.txt # Install all Python dependecies +conan profile detect --force # Generate a default configuration with the local machine settings +conan config install ./.conan # Install supported build profiles from ./.conan to ./conan2 +``` + +### Multi-Config Build + +Multi-config builds allow you to create a build folder containing sub-folders for different build configurations and build them side-by-side. Once again starting with the repository clone and Conan configured run the install stage, but this time we specity the Conan cmake tools use Ninja multi-config to generate `Release, Debug, RelWithDebInfo` configurations. To generate all 3 configuration we run the `conan-default` preset which configures CMake for these configurations. + +```bash +conan install ./ -pr:h .conan2/profiles/msvc/193/x64-release -pr:b .conan2/profiles/msvc/193/x64-release --build missing -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" +source build/generators/conanbuild.sh # Access the environment variables needed to use the Mold linker with gcc and clang +cmake --preset conan-default # The configure stage for multi-config builds is conan-default +``` + +Now with CMake configured we select the preset conresponding to the configuration we want to build, in this case the `Release` configuration. +```bash +cmake --build --preset conan-release # The build stage for multi-config builds is the conan- +``` diff --git a/cmake/ccache.cmake b/cmake/ccache.cmake new file mode 100644 index 000000000..db975ceda --- /dev/null +++ b/cmake/ccache.cmake @@ -0,0 +1,192 @@ +#[[ +Copyright 2023 Antony Peacock + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] + +include_guard(GLOBAL) + + +#[=======================================================================[.rst: +enable_ccacche +------------------ + +Overview +^^^^^^^^ + +Enable use of Ccache for compiler caching during the build process. + +.. code-block:: cmake + + enable_ccacche( + [DEBUG] + [ICECC] + [LOGFILE] + [NOHASDIR] + [QUIET] + [RECACHE] + [SLOPPINESS] + ) + -- Searches for the ccache executable, and if found enables it for supported + language with specified options. + + ``DEBUG`` to enable debugging. + ``ICECC`` to enable Icecream build support. + ``LOGFILE`` to enable ccache logging to file ${CMAKE_BINARY_DIR}/CCache_log.txt. + ``NOHASHDIR`` to exclude the current working directory from the cache hash. + ``QUIET`` Silent output from this method if ccache build is enabled. + ``RECACHE`` ccache will not use any previously stored result. New results will overwrite any pre-existing results. + ``SLOPPINESS`` ccache to relax some checks in order to increase the hit rate of cache hits: pch_defines,time_macros. + Please refer to `ccache documentation `_ for more details about options. + +#]=======================================================================] +function(enable_ccache) + set(options DEBUG ICECC LOGFILE NOHASHDIR QUIET RECACHE SLOPPINESS) + set(oneValueArgs) + set(multiValueArgs LANGUAGES) + cmake_parse_arguments(CCACHE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if (CCACHE_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Morpheus: enable_ccache invalid arguments ${CCACHE_UNPARSED_ARGUMENTS}") + endif() + + find_program(CCACHE_BIN ccache) + if (NOT CCACHE_BIN) + message(STATUS "Morpheus: CCache not found. Rebuilding all the source files.") + message(DEBUG "Morpheus: If CCache compiler cache is desired then ensure this is a supported platform and ensure the Conan buildenv is active") + return() + endif() + + if (NOT CCACHE_QUIET) + message(STATUS "Morpheus: CCache found: ${CCACHE_BIN}. Enabling ccache as compiler cache tool.") + endif() + + if (CCACHE_DEBUG) + message(STATUS "Morpheus: Create CCache debug files") + list(APPEND ccacheEnv "CCACHE_DEBUG=1") + endif() + + if (CCACHE_ICECC) + find_program(ICECC_BIN icecc) + if (ICECC_BIN) + message(STATUS "Morpheus: build with Icecream ${ICECC_BIN}") + list(APPEND ccacheEnv "CCACHE_PREFIX=icecc") + else() + message(STATUS "Morpheus: Icecream executable not found") + endif() + endif() + + if (CCACHE_LOGFILE) + message(STATUS "Morpheus: Enable CCache logfile") + list(APPEND ccacheEnv "CCACHE_LOGFILE=${CMAKE_BINARY_DIR}/CCache_log.txt") + endif() + + if (CCACHE_NOHASHDIR) + message(STATUS "Morpheus: CCache do not hash current working directory") + list(APPEND ccacheEnv "CCACHE_NOHASHDIR=1") + endif() + + if (CCACHE_RECACHE) + message(STATUS "Morpheus: Enable CCache forced recache") + list(APPEND ccacheEnv "CCACHE_RECACHE=1") + endif() + + if (CCACHE_SLOPPINESS) + message(STATUS "Morpheus: Enable CCache sloppiness") + list(APPEND ccacheEnv "CCACHE_SLOPPINESS=pch_defines,time_macros,include_file_mtime,include_file_ctime") + endif() + + foreach(lang IN ITEMS C CXX OBJC OBJCXX) + if (CMAKE_${lang}_COMPILER_ID MATCHES "Clang") + add_compile_options("$<$:SHELL:-Xclang -fno-pch-timestamp>") + endif() + endforeach() + + if (MSVC) + message(STATUS "Morpheus: found generator ${CMAKE_GENERATOR} and OS ${CMAKE_HOST_SYSTEM_NAME} and MSVC ${MSVC}") + + foreach(lang IN ITEMS C CXX) + foreach(config IN LISTS CMAKE_BUILD_TYPE CMAKE_CONFIGURATION_TYPES) + set(var CMAKE_${lang}_FLAGS) + if (NOT config STREQUAL "") + string(TOUPPER "${config}" config) + string(APPEND var "_${config}") + endif() + string(REGEX REPLACE "[-/]Z[iI]" "-Z7" ${var} "${${var}}") + set(${var} "${${var}}" CACHE STRING "Morpheus: Compile flags for MSVC" FORCE) + endforeach() + endforeach() + + if (DEFINED CMAKE_MSVC_DEBUG_INFORMATION_FORMAT) + string(REGEX REPLACE "ProgramDatabase|EditAndContinue" "Embedded" replaced "${CMAKE_MSVC_DEBUG_INFORMATION_FORMAT}") + set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "${replaced}" CACHE STRING "Morpheus: Compile flags for MSVC" FORCE) + else() + set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<$:Embedded>" CACHE STRING "Morpheus: Compile flags for MSVC" FORCE) + endif() + endif() + + if (${CMAKE_GENERATOR} MATCHES "Ninja|Ninja Multi-Config|Makefiles") + message(STATUS "Morpheus: found generator ${CMAKE_GENERATOR} and OS ${CMAKE_HOST_SYSTEM_NAME}") + + foreach(lang IN ITEMS ${LANGUAGES}) + set(CMAKE_${lang}_COMPILER_LAUNCHER ${CMAKE_COMMAND} -E env ${ccacheEnv} ${CCACHE_BIN} CACHE STRING "Morpheus compiler launcher" FORCE) + endforeach() + elseif (${CMAKE_GENERATOR} STREQUAL "Xcode") + message(STATUS "Morpheus: found generator ${CMAKE_GENERATOR} and OS ${CMAKE_HOST_SYSTEM_NAME}") + + foreach(lang IN ITEMS ${LANGUAGES}) + set(launch${lang} ${CMAKE_BINARY_DIR}/launch-${lang}) + file(WRITE ${launch${lang}} "#!/bin/bash\n\n") + foreach(envVal IN ITEMS ${ccacheEnv}) + file(APPEND ${launch${lang}} "export ${envVal}\n") + endforeach() + file(APPEND ${launch${lang}} "exec \"${CCACHE_BIN}\" \"${CMAKE_${lang}_COMPILER}\" \"$@\"\n") + execute_process(COMMAND chmod a+rx ${launch${lang}}) + set(${CMAKE_XCODE_ATTRIBUTE_${lang}} ${launch${lang}}) + if(lang STREQUAL "C") + set(CMAKE_XCODE_ATTRIBUTE_LD ${launchC}) + elseif(lang STREQUAL "CXX") + set(CMAKE_XCODE_ATTRIBUTE_LDPLUSPLUS ${launchCXX}) + endif() + endforeach() + elseif (${CMAKE_GENERATOR} MATCHES "Visual Studio") + message(STATUS "Morpheus: found generator ${CMAKE_GENERATOR} and OS ${CMAKE_HOST_SYSTEM_NAME}") + + cmake_path(NATIVE_PATH CCACHE_BIN ccache_exe) + file(WRITE ${CMAKE_BINARY_DIR}/launch-cl.cmd "@echo off\n") + + foreach(envVal IN ITEMS ${ccacheEnv}) + file(APPEND ${CMAKE_BINARY_DIR}/launch-cl.cmd "set ${envVal}\n") + endforeach() + + foreach(lang IN ITEMS ${LANGUAGES}) + file(APPEND ${CMAKE_BINARY_DIR}/launch-cl.cmd "\"${ccache_exe}\" \"${CMAKE_${lang}_COMPILER}\" %*\n") + endforeach() + + list(FILTER CMAKE_VS_GLOBALS EXCLUDE REGEX "^(CLTool(Path|Exe)|TrackFileAccess|UseMultiToolTask|DebugInformationFormat|EnforceProcessCountAcrossBuilds)=.*$" + ) + + list(APPEND CMAKE_VS_GLOBALS + CLToolPath=${CMAKE_BINARY_DIR} + CLToolExe=launch-cl.cmd + DebugInformationFormat=OldStyle + EnforceProcessCountAcrossBuilds=true + TrackFileAccess=false + UseMultiToolTask=true + ) + + set(CMAKE_VS_GLOBALS "${CMAKE_VS_GLOBALS}" CACHE STRING "Morpheus: Variables for Visual Studio" FORCE) + endif() + +endfunction() diff --git a/cmake/linker.cmake b/cmake/linker.cmake index 6d9871aad..b9d765b43 100644 --- a/cmake/linker.cmake +++ b/cmake/linker.cmake @@ -18,7 +18,7 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR include_guard(GLOBAL) if (${MORPHEUS_LINK_WITH_MOLD}) - find_program(MOLD_BIN mold REQUIRED) + find_program(MOLD_BIN mold) if(MOLD_BIN) message(STATUS "Morpheus: Mold linker found: ${MOLD_BIN}. Enabling mold as active linker.") target_link_options(MorpheusConfig diff --git a/conanfile.py b/conanfile.py index 91a675fcd..2e6bdd423 100644 --- a/conanfile.py +++ b/conanfile.py @@ -56,6 +56,7 @@ class Morpheus(ConanFile): no_copy_source = True options = { "build_docs": [True, False], + "build_with_ccache": [True, False], "fPIC": [True, False], "link_with_mold": [True, False], "shared": [True, False], @@ -67,6 +68,7 @@ class Morpheus(ConanFile): } default_options = { "build_docs": False, + "build_with_ccache": True, "fPIC": True, "link_with_mold": True, "shared": False, @@ -75,7 +77,7 @@ class Morpheus(ConanFile): "with_rs_metal": True, "with_rs_opengl": True, "with_rs_vulkan": True - } + } exports_sources = ["CMakeLists.txt", "LICENSE", "version.txt", "cmake/*", "examples/*" "libraries/*"] requires = ( "boost/1.85.0", @@ -131,6 +133,9 @@ def config_options(self): if not self.checkMoldIsSupported(): self.options.rm_safe("link_with_mold") + if not self.checkCCacheIsSupported(): + self.options.rm_safe("build_with_ccache") + if not (self.settings.os in ["Macos", "iOS", "tvOS"]): self.options.rm_safe("with_rs_metal") @@ -149,8 +154,11 @@ def build_requirements(self): self.build_requires("doxygen/1.9.4") # doxygen/1.9.5 will update dependency on zlib/1.2.12 to zlib/1.2.13 if self.options.get_safe("link_with_mold", False): - self.build_requires("mold/2.4.0") - self.build_requires("openssl/3.2.1", override=True) + self.build_requires("mold/1.11.0") + self.build_requires("openssl/3.1.2", override=True) + + if self.options.get_safe("build_with_ccache", False): + self.build_requires("ccache/4.8.3") def requirements(self): if self.options.get_safe("with_rs_vulkan", False): @@ -220,6 +228,7 @@ def generate(self): tc = CMakeToolchain(self) tc.variables["BUILD_SHARED_LIBS"] = self.options.shared tc.variables["MORPHEUS_BUILD_DOCS"] = self.options.build_docs + tc.variables["MORPHEUS_BUILD_WITH_CCACHE"] = self.options.get_safe("build_with_ccache", False) tc.variables["MORPHEUS_LINK_WITH_MOLD"] = self.options.get_safe("link_with_mold", False) tc.variables["MORPHEUS_RENDER_SYSTEM_DIRECT_X12"] = self.options.get_safe("with_rs_direct_x12", False) tc.variables["MORPHEUS_RENDER_SYSTEM_METAL"] = self.options.get_safe("with_rs_metal", False)