I have spent some very intense weeks this March to completely overhaul and refactor my CMake scripts. We are talking about more than two thousand lines of code!
I started by changing the way I cross-compile on Android. I dropped the use of CMake integrated NDK support introduced with version 3.7 and went back using the toolchain file provided by the NDK itself. It seems the way to go in order to provide full control and flexibility to each NDK update.
Target properties and expressions
Taking full advantage of CMake targets allowed me to completely remove any
set command involving variables like
Besides that I also started to rely more deeply on generator expressions for things like
$<CONFIG:cfg>. This last expression got rid of every
if(CMAKE_BUILD_TYPE MATCHES "Debug") conditional check.
But I didn’t stop there and I went on to convert my scripts to use targets everywhere. I now use imported targets for every external dependency library.
In the end it’s a better and more flexible way of handling the problem but it put a lot of stress on testing as not all
find_package scripts correctly set targets and some platforms need additional tweaking too.
- For example MSYS/MinGW needed a custom CMake function to find the DLL and set the
IMPORTED_LOCATIONtarget property as the corresponding
find_packagescripts only discovered the import library.
- As another example on macOS I needed a different custom CMake function to split the link options set by
find_packagescripts into the ones representing framework directories and the ones being
-frameworklink directives. There is also a need to append the library symlink name to the framework directory as that is what the
IMPORTED_LOCATIONtarget property expects when dealing with macOS frameworks (someone has even opened an issue ticket about that).
Discoverability and exported targets
In an attempt to make nCine discoverability more robust for external projects I have changed a lot of code based on cascaded conditions to a bunch of a lot cleaner
I now also always use exported targets and this has two very important benefits:
- It is now possible to link to the
ncinetarget and automatically have access to interface properties like for example
- By using the
nCine_DIRCMake variable when configuring a project it is possible to import the targets from a build directory.
The outcome of this last change is that there is no more
NCINE_HOME custom variable, all the discovery use cases are handled by the CMake way of doing things: using a
<package>_DIR variable that points to where the
nCineConfig.cmake script is. This will in turn include the
nCineTargets.cmake script to bring all the imported nCine targets into the namespace of an external package
A couple of additional changes are:
- I now build a new
ncine_mainstatic library and export it as a target, instead of distributing a
main.cppfile that the user never really had the need to modify.
- I have added an interface library pseudo target for the code coverage compiler and linker options as a way, as the CMake manual states, “to employ an entirely target-focussed design for usage requirements”.
That’s all for this update, I hope you enjoyed this in-depth review of CMake changes.