CMake 3.29.0-rc1 was released on February 13th. This release landed two major developer-experience improvements. Here's what to expect and the changes you'll need to make in order to make use of them.
-
CMake now supports generating compile-commands for Swift. This means that you can use SourceKit-LSP with your CMake projects for improved editor support. For the best SourceKit-LSP experience, add
add_compile_options($<$<COMPILE_LANGUAGE:Swift>:-index-store-path ${CMAKE_BINARY_DIR}/IndexStore/index>)
flag early in your project to ensure that the Swift compiler is generating index data. -
Swift targets won't rebuild if changes to the source file don't warrant changes to the output. The driver doesn't update timestamps on outputs if changes to the source don't warrant changing them. Changing a comment in a source won't affect the generated object, so the object file isn't updated. Ninja would see that the timestamp on the source file is newer than the object file output and schedule a rebuild. Ninja is now restat'ing Swift build outputs to track what is actually up-to-date avoiding unecessary rebuilds, so you should see faster rebuild times and more aggressive subtree pruning. Thanks @z2oh!
CMake received a fairly major overhaul in how it models Swift builds in order to support this. For CMake users, the change to be aware of is the introduction of a variable and target property to control the compilation mode. The CMAKE_Swift_COMPILATION_MODE
variable sets the default for whether a target is built single-file, incrementally, or with whole-module optimizations enabled. The swift_COMPILATION_MODE
target property enables you to control whether specific targets are built with WMO or incrementally. The default behavior is to build incrementally.
Allowed values for the variable and target property are
wholemodule
incremental
singlefile
As this change is not backward compatible with existing projects, CMake policy CMP0157 controls whether CMake uses the new build model or the old. CMP0157 must be set to NEW
before Swift is enabled, either with project(${project name} Swift)
or with enable_language(Swift)
or it will be considered off for the entire project, including nested projects using FetchContent
. Ensure that you have audited your project for forced -wmo
and -whole-module-optimization
flags to Swift targets before setting CMP0157 to NEW
or you may find that your build graph is broken.
Here is an example of how to migrate a simple project to the new model.
Wel start with the following project, which manually passes -whole-module-optimization
to the executable build target:
cmake_minimum_required(VERSION 3.28)
project(Example Swift)
add_executable(MyExecutable hello.swift foo.swift bar.swift)
target_compile_options(MyExecutable PRIVATE -whole-module-optimization)
Before declaring the project and enabling Swift, we set CMP0157
to NEW
. If CMP0157
is not set to NEW
, Swift_COMPILATION_MODE
and CMAKE_Swift_COMPILATION_MODE
will have no effect. Next, we replace the -whole-module-optimization
compile option by setting the Swift_COMPILATION_MODE
to wholemodule
on the executable target. For folks using the Xcode generator with your projects, you will notice that this now works with your Xcode builds.
cmake_minimum_required(VERSION 3.29)
cmake_policy(SET CMP0157 NEW)
project(Example Swift)
add_executable(MyExecutable hello.swift foo.swift bar.swift)
set_target_properties(MyExecutable PROPERTIES Swift_COMPILATION_MODE wholemodule)