Skip to content

Commit

Permalink
Enable ccache compiler wrapper when available.
Browse files Browse the repository at this point in the history
Let CMake use ccache compiler wrapper via `..._LAUNCHER`.

For gcc and compatible compilers, the cost of rebuilding can be greatly
reduced when switching back and forth between branches. If ccache is not
installed or is not given a known-compatible compiler to wrap, this
change has no effect.

Potential side effects should already be familiar to ccache users:

* In some cases, a cache configured to grow too large may lose its benefit.
* If the cache is corrupted, it may need to be removed to restore utility.

We are not using any of the more aggressive caching options, so there
should be no risk of false positives in compile cache hits.

Resolves #2592

Change-Id: Ia04d7388a3e8367d31cc5728dfc4b245ea7ef774
  • Loading branch information
eirrgang authored and Kasson committed Aug 8, 2018
1 parent e86d25e commit 04190c7
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 0 deletions.
8 changes: 8 additions & 0 deletions CMakeLists.txt
Expand Up @@ -40,6 +40,14 @@ list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake ${CMAKE_CURRENT_

project(Gromacs)

# Use ccache if available to wrap CMAKE_C_COMPILER and CMAKE_CXX_COMPILER.
# Reference https://ccache.samba.org
option(ENABLE_CCACHE "Allow CMake to use ccache compiler wrappers if available." ON)
# CMAKE_C_COMPILER and CMAKE_CXX_COMPILER do not change after this line.
if(ENABLE_CCACHE)
include(gmxCcache)
endif()

set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
Expand Down
116 changes: 116 additions & 0 deletions cmake/gmxCcache.cmake
@@ -0,0 +1,116 @@
#
# This file is part of the GROMACS molecular simulation package.
#
# Copyright (c) 2018, by the GROMACS development team, led by
# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
# and including many others, as listed in the AUTHORS file in the
# top-level source directory and at http://www.gromacs.org.
#
# GROMACS is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1
# of the License, or (at your option) any later version.
#
# GROMACS is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with GROMACS; if not, see
# http://www.gnu.org/licenses, or write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# If you want to redistribute modifications to GROMACS, please
# consider that scientific software is very special. Version
# control is crucial - bugs must be traceable. We will be happy to
# consider code for inclusion in the official distribution, but
# derived work must not be called official GROMACS. Details are found
# in the README & COPYING files - if they are missing, get the
# official version at http://www.gromacs.org.
#
# To help us fund GROMACS development, we humbly ask that you cite
# the research papers on the package. Check out http://www.gromacs.org.

# Reference https://crascit.com/2016/04/09/using-ccache-with-cmake/
#
# Here we try to make sure that ccache is invoked as `/.../ccache compiler args` to best handle more than one local
# compiler or a compiler wrapper, whereas it is otherwise common to replace the default compilers with symbolic links
# to the ccache binary.
#
# ccache only works for gcc compatible compilers. We should test with anything other than CMAKE_<LANG>_COMPILER_ID==GNU
# Clang is reported to work with some caveats. See https://pspdfkit.com/blog/2015/ccache-for-fun-and-profit/
find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
# Check whether C compiler wrapper has been set up.
if(NOT DEFINED GMX_CACHE_C_COMPILER)
# Determine whether we have a cacheable compiler.
set(_cacheable OFF)
if (CMAKE_C_COMPILER_ID MATCHES "GNU"
OR CMAKE_C_COMPILER_ID MATCHES "AppleClang"
OR CMAKE_C_COMPILER_ID MATCHES "Clang")
message(STATUS "Setting up ccache wrapper for ${CMAKE_C_COMPILER_ID} C compiler ${CMAKE_C_COMPILER}")
set(_c_launcher "${CCACHE_PROGRAM}")
configure_file(launch-c.in ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/launch-c)
unset(_c_launcher)
file(COPY ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/launch-c
DESTINATION ${CMAKE_BINARY_DIR}
FILE_PERMISSIONS
OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
)
set(_cacheable ON)
else()
message(STATUS "Disabling ccache set up. Not confirmed to work with compiler ID ${CMAKE_C_COMPILER_ID}.")
endif() # GNU C compiler
set(GMX_CACHE_C_COMPILER ${_cacheable} CACHE INTERNAL "Whether the C compiler will be wrapped for caching.")
unset(_cacheable)
endif() # defined
# Check whether we should use the wrapper. If so, set CMAKE variables.
if(GMX_CACHE_C_COMPILER)
if(CMAKE_GENERATOR STREQUAL "Xcode")
# Set Xcode project attributes to route compilation and linking
# through our scripts
set(CMAKE_XCODE_ATTRIBUTE_CC "${CMAKE_BINARY_DIR}/launch-c")
set(CMAKE_XCODE_ATTRIBUTE_LD "${CMAKE_BINARY_DIR}/launch-c")
else()
# Support Unix Makefiles and Ninja
set(CMAKE_C_COMPILER_LAUNCHER "${CMAKE_BINARY_DIR}/launch-c")
endif()
endif(GMX_CACHE_C_COMPILER)

# Check whether CXX compiler wrapper has been set up
if(NOT DEFINED GMX_CACHE_CXX_COMPILER)
# Determine whether we have a cacheable compiler.
set(_cacheable OFF)
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU"
OR CMAKE_CXX_COMPILER_ID MATCHES "AppleClang"
OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
message(STATUS "Setting up ccache wrapper for ${CMAKE_CXX_COMPILER_ID} CXX compiler ${CMAKE_CXX_COMPILER}")
set(_cxx_launcher "${CCACHE_PROGRAM}")
configure_file(launch-cxx.in ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/launch-cxx)
unset(_cxx_launcher)
file(COPY ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/launch-cxx
DESTINATION ${CMAKE_BINARY_DIR}
FILE_PERMISSIONS
OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
)
set(_cacheable ON)
else()
message(STATUS "Skipping ccache set up. Not confirmed to work with compiler ID ${CMAKE_CXX_COMPILER_ID}.")
endif() # GNU C++ compiler
set(GMX_CACHE_CXX_COMPILER ${_cacheable} CACHE INTERNAL "Whether the C++ compiler will be wrapped for caching.")
unset(_cacheable)
endif() # defined
# Check whether we should use the wrapper. If so, set CMAKE variables.
if(GMX_CACHE_CXX_COMPILER)
if(CMAKE_GENERATOR STREQUAL "Xcode")
# Set Xcode project attributes to route compilation and linking
# through our scripts
set(CMAKE_XCODE_ATTRIBUTE_CXX "${CMAKE_BINARY_DIR}/launch-cxx")
set(CMAKE_XCODE_ATTRIBUTE_LDPLUSPLUS "${CMAKE_BINARY_DIR}/launch-cxx")
else()
# Support Unix Makefiles and Ninja
set(CMAKE_CXX_COMPILER_LAUNCHER "${CMAKE_BINARY_DIR}/launch-cxx")
endif()
endif(GMX_CACHE_CXX_COMPILER)
endif(CCACHE_PROGRAM) # ccache program
8 changes: 8 additions & 0 deletions docs/dev-manual/tools.rst
Expand Up @@ -62,6 +62,14 @@ Build system
CMake
Main tool used in the build system.

ccache
When the `ccache <https://ccache.samba.org>`_ caching compiler wrapper is
found on the PATH, we attempt to set up a caching compiler wrapper for CMake
builds. Not all compilers are supported. Refer to the ``ENABLE_CCACHE``
option in ``CMakeLists.txt`` and to ``cmake/gmxCcache.cmake``
for details. Please submit updates if you find that the current
configuration is too conservative.

packaging for distribution (CPack)

unit testing (CTest)
Expand Down
11 changes: 11 additions & 0 deletions launch-c.in
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
# Set up compiler wrapper to make it easier to use ccache.
#
# Xcode generator doesn't include the compiler as the
# first argument, Ninja and Makefiles do. Handle both cases.
if [[ "$1" = "${CMAKE_C_COMPILER}" ]] ; then
shift
fi

export CCACHE_CPP2=true
exec "${_c_launcher}" "${CMAKE_C_COMPILER}" "$@"
11 changes: 11 additions & 0 deletions launch-cxx.in
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
# Set up compiler wrapper to make it easier to use ccache.
#
# Xcode generator doesn't include the compiler as the
# first argument, Ninja and Makefiles do. Handle both cases.
if [[ "$1" = "${CMAKE_CXX_COMPILER}" ]] ; then
shift
fi

export CCACHE_CPP2=true
exec "${_cxx_launcher}" "${CMAKE_CXX_COMPILER}" "$@"

0 comments on commit 04190c7

Please sign in to comment.