diff --git a/SerialPrograms/BuildInstructions/Build-Mac-CompilerCache.md b/SerialPrograms/BuildInstructions/Build-Mac-CompilerCache.md new file mode 100644 index 0000000000..f066038f9d --- /dev/null +++ b/SerialPrograms/BuildInstructions/Build-Mac-CompilerCache.md @@ -0,0 +1,65 @@ +# Faster rebuilds on macOS with ccache + +Optional, for developers who build often or keep several worktrees. Get a +normal build working first with the [Mac build guide](CompilingForMac.md). + +The `macos-ccache` preset is the `RelWithDebInfo` preset plus +[ccache](https://ccache.dev): compilations are cached in one place for all your +checkouts, so switching branches or setting up another worktree reuses earlier +compiles instead of starting over. It needs ccache 4.8 or newer and Apple Clang. +Other presets and CI are unchanged. + +## Set up + +```sh +brew install ninja ccache +``` + +From the repository root, configure with the same options your normal build +uses (for example `CMAKE_PREFIX_PATH` for Qt, or `PKG_CONFIG_PATH` if OpenCV is +installed keg-only), then build: + +```sh +cmake -S SerialPrograms --preset macos-ccache \ + -DCMAKE_PREFIX_PATH=/path/to/Qt/6.8.3/macos +cmake --build build/macos-ccache --parallel 4 +``` + +The first build fills the cache and takes as long as a normal build. + +## What the preset sets + +- **Cache location and size:** `~/Library/Caches/pokemonautomation-ccache`, + capped at 5 GB; ccache evicts old entries itself. A full build adds about + 250 MB (compressed), so this holds around 20 revisions' worth of compiles. +- **Path rewriting:** `base_dir` is the checkout, so paths inside it are made + relative and two worktrees produce the same compiler commands. +- **Debug paths:** `-fdebug-prefix-map==.` and + `-fdebug-compilation-dir=.` keep the checkout's path out of the objects, so + they can be shared. Debug info then has relative paths: start the debugger + from the build directory or set its source path. + +These are passed on the compiler command line, so no environment variables are +needed. The preset sets `CMAKE_C_FLAGS` and `CMAKE_CXX_FLAGS`; if you need other +flags, add them to these rather than replacing them. + +To look at the cache: + +```sh +ccache --dir ~/Library/Caches/pokemonautomation-ccache --show-stats +``` + +## Getting cache hits + +Hits need the same compiler, SDK, Qt, dependencies and flags in each worktree. +A change to a widely included header still recompiles everything that includes +it, cached or not. + +Measured on Apple Silicon (Apple Clang 21, Qt 6.8.3, ccache 4.14): a second +worktree at the same revision built in 41 s with 1,601 of 1,607 compiles from +the cache, against 13 to 14 minutes uncached. + +## Turning it off + +Use a normal preset in a separate build directory. Switching presets in the +same directory keeps the launcher and flags stored in `CMakeCache.txt`. diff --git a/SerialPrograms/BuildInstructions/CompilingForMac.md b/SerialPrograms/BuildInstructions/CompilingForMac.md index fabda968ef..80533a2279 100644 --- a/SerialPrograms/BuildInstructions/CompilingForMac.md +++ b/SerialPrograms/BuildInstructions/CompilingForMac.md @@ -12,6 +12,11 @@ If you have any questions regarding the documentation or find any errors in the Warning: if you don't have software development experience and deviate from the guide steps, you are at your own risk. +## Faster rebuilds for developers + +After the normal build works, the optional [ccache guide](Build-Mac-CompilerCache.md) +makes rebuilds and new worktrees reuse earlier compiles. + ## Part 1: Install Pre-requisites ### Install XCode App diff --git a/SerialPrograms/CMakePresets.json b/SerialPrograms/CMakePresets.json index 1660f3f00b..d51487f19b 100644 --- a/SerialPrograms/CMakePresets.json +++ b/SerialPrograms/CMakePresets.json @@ -72,6 +72,23 @@ "CMAKE_BUILD_TYPE": "RelWithDebInfo", "PACKAGE_BUILD": "ON" } + }, + { + "name": "macos-ccache", + "inherits": "RelWithDebInfo", + "displayName": "macOS RelWithDebInfo with shared ccache", + "description": "Apple Clang builds with a 5 GB local compiler cache shared across worktrees.", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Darwin" + }, + "cacheVariables": { + "CMAKE_C_COMPILER_LAUNCHER": "ccache;cache_dir=$penv{HOME}/Library/Caches/pokemonautomation-ccache;base_dir=${sourceParentDir};max_size=5G", + "CMAKE_CXX_COMPILER_LAUNCHER": "ccache;cache_dir=$penv{HOME}/Library/Caches/pokemonautomation-ccache;base_dir=${sourceParentDir};max_size=5G", + "CMAKE_C_FLAGS": "-fdebug-prefix-map=${sourceParentDir}=. -fdebug-compilation-dir=.", + "CMAKE_CXX_FLAGS": "-fdebug-prefix-map=${sourceParentDir}=. -fdebug-compilation-dir=." + } } ], "buildPresets": [ @@ -99,6 +116,10 @@ { "name": "Publish", "configurePreset": "Publish" + }, + { + "name": "macos-ccache", + "configurePreset": "macos-ccache" } ] }