2016. március 11., péntek

Unity Build macro for CMake

A half year ago, I came across some techniques to speed up the C++ compilation for bigger projects. As my evergrowing AiBO+ project is around 87000 C++ source lines without 3rd party libraries now, it really became important to keep the compilation time low. Apart from the ccache integration in my CMake build system, I decided to try out the Unity Build method. When I looked around the internet, I found that the Unity Build would shorten the build duration significantly and some people crafted some small CMake scripts, but these solutions were incomplete. Either they did not handle the Qt's moc files at all or all Unity files were regenerated each time when a CMake reconfigure was initiated. An other example is Cotire which does not handle the dependencies correctly (https://github.com/sakra/cotire/issues/77).

My script is based on Christoph Heindl's work although heavily modified. So here it is:

https://sourceforge.net/p/aiboplus/code/ci/master/tree/aiboplus/UnityBuild.cmake

The features of my Unity Build script for CMake:
- Easy to add to existing projects
- Configurable extension for the generated Unity Build files (c, cpp, cc etc.)
- Easy to exclude certain problematic sources from the Unity Build file generation
- Source file count limit for the Unity Build files
- Working out-of-source builds
- Qt support (handling moc files correctly)
- Track the source file changes with md5 hashes
- Regenerate the Unity Build files only when really needed

Limitation:
- The Unity Build files are not removed with "make clean".

Note:
- The UNITY_GENERATE_MOC() macro is optional. I wrote this lightweight moc file generation for Qt instead of the default slower moc invocations in CMake.

Basic usage of my script:

- Copy UnityBuild.cmake to your project's root directory.
- Include in the root CMakeLists.txt:

INCLUDE(UnityBuild.cmake)

- In any source directory, use like this:

SET(LIBEXAMPLE_SRC
    first.c ;
    second.c ;
    third.c ;
    )

# Parameters:
# 1. Name prefix for the generated Unity Build files
# 2. CMake variable which contains the source files
# 3. Unit size (source file count) per Unity Build file
# 4. Extension for the Unity Build files to invoke the correct compiler
ENABLE_UNITY_BUILD(libexample LIBEXAMPLE_SRC 10 c)

# Optional: Add any problematic source file which are not suitable for Unity Build and
# you are lazy to fix it.
SET(LIBEXAMPLE_SRC ${LIBEXAMPLE_SRC} lazy.c)

ADD_LIBRARY(libexample STATIC ${LIBEXAMPLE_SRC})