From cb1a037eb8b15e5332ad5318cb9ff732666c439b Mon Sep 17 00:00:00 2001 From: Sascha Kratky Date: Mon, 11 Mar 2013 22:00:00 +0100 Subject: [PATCH] cotire 1.4.0 --- CMake/cotire.cmake | 222 ++++++++++++++++++++++++++++++--------------- HISTORY.md | 7 ++ MANUAL.md | 97 ++++++++++++++++---- README.md | 5 +- 4 files changed, 240 insertions(+), 91 deletions(-) diff --git a/CMake/cotire.cmake b/CMake/cotire.cmake index af8c0ca..ba2c8f2 100644 --- a/CMake/cotire.cmake +++ b/CMake/cotire.cmake @@ -45,9 +45,10 @@ if (NOT CMAKE_SCRIPT_MODE_FILE) endif() set (COTIRE_CMAKE_MODULE_FILE "${CMAKE_CURRENT_LIST_FILE}") -set (COTIRE_CMAKE_MODULE_VERSION "1.3.6") +set (COTIRE_CMAKE_MODULE_VERSION "1.4.0") include(CMakeParseArguments) +include(ProcessorCount) function (cotire_determine_compiler_version _language _versionPrefix) if (NOT ${_versionPrefix}_VERSION) @@ -1519,11 +1520,31 @@ macro (cotire_get_intermediate_dir _cotireDir) get_filename_component(${_cotireDir} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${COTIRE_INTDIR}" ABSOLUTE) endmacro() -function (cotire_make_unity_source_file_paths _language _target _maxIncludes _unityFilesVar) - set (_sourceFiles ${ARGN}) - list (LENGTH _sourceFiles _numberOfSources) +macro (cotire_setup_file_extension_variables) set (_unityFileExt_C ".c") set (_unityFileExt_CXX ".cxx") + set (_prefixFileExt_C ".h") + set (_prefixFileExt_CXX ".hxx") +endmacro() + +function (cotire_make_single_unity_source_file_path _language _target _unityFileVar) + cotire_setup_file_extension_variables() + if (NOT DEFINED _unityFileExt_${_language}) + set (${_unityFileVar} "" PARENT_SCOPE) + return() + endif() + set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}") + set (_unityFileName "${_unityFileBaseName}${_unityFileExt_${_language}}") + cotire_get_intermediate_dir(_baseDir) + set (_unityFile "${_baseDir}/${_unityFileName}") + set (${_unityFileVar} "${_unityFile}" PARENT_SCOPE) + if (COTIRE_DEBUG) + message(STATUS "${_unityFile}") + endif() +endfunction() + +function (cotire_make_unity_source_file_paths _language _target _maxIncludes _unityFilesVar) + cotire_setup_file_extension_variables() if (NOT DEFINED _unityFileExt_${_language}) set (${_unityFileVar} "" PARENT_SCOPE) return() @@ -1533,11 +1554,13 @@ function (cotire_make_unity_source_file_paths _language _target _maxIncludes _un set (_startIndex 0) set (_index 0) set (_unityFiles "") + set (_sourceFiles ${ARGN}) foreach (_sourceFile ${_sourceFiles}) get_source_file_property(_startNew "${_sourceFile}" COTIRE_START_NEW_UNITY_SOURCE) math (EXPR _unityFileCount "${_index} - ${_startIndex}") if (_startNew OR (_maxIncludes GREATER 0 AND NOT _unityFileCount LESS _maxIncludes)) if (_index GREATER 0) + # start new unity file segment math (EXPR _endIndex "${_index} - 1") set (_unityFileName "${_unityFileBaseName}_${_startIndex}_${_endIndex}${_unityFileExt_${_language}}") list (APPEND _unityFiles "${_baseDir}/${_unityFileName}") @@ -1546,10 +1569,12 @@ function (cotire_make_unity_source_file_paths _language _target _maxIncludes _un endif() math (EXPR _index "${_index} + 1") endforeach() + list (LENGTH _sourceFiles _numberOfSources) if (_startIndex EQUAL 0) - set (_unityFileName "${_unityFileBaseName}${_unityFileExt_${_language}}") - list (APPEND _unityFiles "${_baseDir}/${_unityFileName}") + # there is only a single unity file + cotire_make_single_unity_source_file_path(${_language} ${_target} _unityFiles) elseif (_startIndex LESS _numberOfSources) + # end with final unity file segment math (EXPR _endIndex "${_index} - 1") set (_unityFileName "${_unityFileBaseName}_${_startIndex}_${_endIndex}${_unityFileExt_${_language}}") list (APPEND _unityFiles "${_baseDir}/${_unityFileName}") @@ -1560,9 +1585,21 @@ function (cotire_make_unity_source_file_paths _language _target _maxIncludes _un endif() endfunction() +function (cotire_unity_to_prefix_file_path _language _target _unityFile _prefixFileVar) + cotire_setup_file_extension_variables() + if (NOT DEFINED _unityFileExt_${_language}) + set (${_prefixFileVar} "" PARENT_SCOPE) + return() + endif() + set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}") + set (_prefixFileBaseName "${_target}_${_language}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}") + string (REPLACE "${_unityFileBaseName}" "${_prefixFileBaseName}" _prefixFile "${_unityFile}") + string (REGEX REPLACE "${_unityFileExt_${_language}}$" "${_prefixFileExt_${_language}}" _prefixFile "${_prefixFile}") + set (${_prefixFileVar} "${_prefixFile}" PARENT_SCOPE) +endfunction() + function (cotire_make_prefix_file_name _language _target _prefixFileBaseNameVar _prefixFileNameVar) - set (_prefixFileExt_C ".h") - set (_prefixFileExt_CXX ".hxx") + cotire_setup_file_extension_variables() if (NOT _language) set (_prefixFileBaseName "${_target}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}") set (_prefixFileName "${_prefixFileBaseName}${_prefixFileExt_C}") @@ -1811,6 +1848,43 @@ function (cotire_get_first_set_property_value _propertyValueVar _type _object) set (${_propertyValueVar} "" PARENT_SCOPE) endfunction() +function (cotire_setup_combine_command _sourceDir _targetScript _joinedFile _cmdsVar) + set (_files ${ARGN}) + set (_filesPaths "") + foreach (_file ${_files}) + if (IS_ABSOLUTE "${_file}") + set (_filePath "${_file}") + else() + get_filename_component(_filePath "${_sourceDir}/${_file}" ABSOLUTE) + endif() + file (RELATIVE_PATH _fileRelPath "${_sourceDir}" "${_filePath}") + if (NOT IS_ABSOLUTE "${_fileRelPath}" AND NOT "${_fileRelPath}" MATCHES "^\\.\\.") + list (APPEND _filesPaths "${_fileRelPath}") + else() + list (APPEND _filesPaths "${_filePath}") + endif() + endforeach() + cotire_set_cmd_to_prologue(_prefixCmd) + list (APPEND _prefixCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "combine") + if (_targetScript) + list (APPEND _prefixCmd "${_targetScript}") + endif() + list (APPEND _prefixCmd "${_joinedFile}" ${_filesPaths}) + if (COTIRE_DEBUG) + message (STATUS "add_custom_command: OUTPUT ${_joinedFile} COMMAND ${_prefixCmd} DEPENDS ${_files}") + endif() + set_property (SOURCE "${_joinedFile}" PROPERTY GENERATED TRUE) + file (RELATIVE_PATH _joinedFileRelPath "${CMAKE_BINARY_DIR}" "${_joinedFile}") + add_custom_command( + OUTPUT "${_joinedFile}" + COMMAND ${_prefixCmd} + DEPENDS ${_files} + COMMENT "Generating ${_joinedFileRelPath}" + WORKING_DIRECTORY "${_sourceDir}" VERBATIM) + list (APPEND ${_cmdsVar} COMMAND ${_prefixCmd}) + set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) +endfunction() + function (cotire_setup_target_pch_usage _languages _targetSourceDir _target _wholeTarget) if (XCODE) # for Xcode, we attach a pre-build action to generate the unity sources and prefix headers @@ -1892,20 +1966,17 @@ function (cotire_setup_unity_generation_commands _language _targetSourceDir _tar WORKING_DIRECTORY "${_targetSourceDir}" VERBATIM) list (APPEND ${_cmdsVar} COMMAND ${_unityCmd}) endforeach() - set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) -endfunction() - -function (cotire_setup_prefix_generation_command _language _target _targetSourceDir _targetScript _prefixFile _unityFiles _cmdsVar) - set (_sourceFiles ${ARGN}) list (LENGTH _unityFiles _numberOfUnityFiles) if (_numberOfUnityFiles GREATER 1) # create a joint unity file from all unity file segments - cotire_make_unity_source_file_paths(${_language} ${_target} 0 _unityFile ${_unityFiles}) + cotire_make_single_unity_source_file_path(${_language} ${_target} _unityFile) cotire_setup_combine_command("${_targetSourceDir}" "${_targetScript}" "${_unityFile}" ${_cmdsVar} ${_unityFiles}) - else() - set (_unityFile "${_unityFiles}") endif() - file (RELATIVE_PATH _prefixFileRelPath "${CMAKE_BINARY_DIR}" "${_prefixFile}") + set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) +endfunction() + +function (cotire_setup_single_prefix_generation_command _language _target _targetSourceDir _targetScript _prefixFile _unityFile _cmdsVar) + set (_sourceFiles ${ARGN}) set (_dependencySources "") cotire_get_prefix_header_dependencies(${_language} ${_target} _dependencySources ${_sourceFiles}) cotire_set_cmd_to_prologue(_prefixCmd) @@ -1914,6 +1985,7 @@ function (cotire_setup_prefix_generation_command _language _target _targetSource if (COTIRE_DEBUG) message (STATUS "add_custom_command: OUTPUT ${_prefixFile} COMMAND ${_prefixCmd} DEPENDS ${_targetScript} ${_unityFile} ${_dependencySources}") endif() + file (RELATIVE_PATH _prefixFileRelPath "${CMAKE_BINARY_DIR}" "${_prefixFile}") add_custom_command( OUTPUT "${_prefixFile}" "${_prefixFile}.log" COMMAND ${_prefixCmd} @@ -1924,40 +1996,25 @@ function (cotire_setup_prefix_generation_command _language _target _targetSource set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) endfunction() -function (cotire_setup_combine_command _sourceDir _targetScript _joinedFile _cmdsVar) - set (_files ${ARGN}) - set (_filesPaths "") - foreach (_file ${_files}) - if (IS_ABSOLUTE "${_file}") - set (_filePath "${_file}") - else() - get_filename_component(_filePath "${_sourceDir}/${_file}" ABSOLUTE) - endif() - file (RELATIVE_PATH _fileRelPath "${_sourceDir}" "${_filePath}") - if (NOT IS_ABSOLUTE "${_fileRelPath}" AND NOT "${_fileRelPath}" MATCHES "^\\.\\.") - list (APPEND _filesPaths "${_fileRelPath}") - else() - list (APPEND _filesPaths "${_filePath}") - endif() - endforeach() - cotire_set_cmd_to_prologue(_prefixCmd) - list (APPEND _prefixCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "combine") - if (_targetScript) - list (APPEND _prefixCmd "${_targetScript}") - endif() - list (APPEND _prefixCmd "${_joinedFile}" ${_filesPaths}) - if (COTIRE_DEBUG) - message (STATUS "add_custom_command: OUTPUT ${_joinedFile} COMMAND ${_prefixCmd} DEPENDS ${_files}") +function (cotire_setup_multi_prefix_generation_command _language _target _targetSourceDir _targetScript _prefixFile _unityFiles _cmdsVar) + set (_sourceFiles ${ARGN}) + list (LENGTH _unityFiles _numberOfUnityFiles) + if (_numberOfUnityFiles GREATER 1) + set (_prefixFiles "") + foreach (_unityFile ${_unityFiles}) + cotire_unity_to_prefix_file_path(${_language} ${_target} "${_unityFile}" _prefixFileSegment) + cotire_setup_single_prefix_generation_command( + ${_language} ${_target} "${_targetSourceDir}" "${_targetScript}" + "${_prefixFileSegment}" "${_unityFile}" ${_cmdsVar} ${_sourceFiles}) + list (APPEND _prefixFiles "${_prefixFileSegment}") + endforeach() + # create a joint prefix header file from all prefix header segments + cotire_setup_combine_command("${_targetSourceDir}" "${_targetScript}" "${_prefixFile}" ${_cmdsVar} ${_prefixFiles}) + else() + cotire_setup_single_prefix_generation_command( + ${_language} ${_target} "${_targetSourceDir}" "${_targetScript}" + "${_prefixFile}" "${_unityFiles}" ${_cmdsVar} ${_sourceFiles}) endif() - set_property (SOURCE "${_joinedFile}" PROPERTY GENERATED TRUE) - file (RELATIVE_PATH _joinedFileRelPath "${CMAKE_BINARY_DIR}" "${_joinedFile}") - add_custom_command( - OUTPUT "${_joinedFile}" - COMMAND ${_prefixCmd} - DEPENDS ${_files} - COMMENT "Generating ${_joinedFileRelPath}" - WORKING_DIRECTORY "${_sourceDir}" VERBATIM) - list (APPEND ${_cmdsVar} COMMAND ${_prefixCmd}) set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) endfunction() @@ -2135,6 +2192,30 @@ function (cotire_choose_target_languages _targetSourceDir _target _targetLanguag set (${_targetLanguagesVar} ${_targetLanguages} PARENT_SCOPE) endfunction() +function (cotire_compute_unity_max_number_of_includes _target _maxIncludesVar) + set (_sourceFiles ${ARGN}) + get_target_property(_maxIncludes ${_target} COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES) + if (_maxIncludes MATCHES "(-j|--parallel) ?([0-9]*)") + set (_numberOfThreads "${CMAKE_MATCH_2}") + if (NOT _numberOfThreads) + # use all available cores + ProcessorCount(_numberOfThreads) + endif() + list (LENGTH _sourceFiles _numberOfSources) + math (EXPR _maxIncludes "(${_numberOfSources} + ${_numberOfThreads} - 1) / ${_numberOfThreads}") + # a unity source segment must not contain less than COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES files + if (_maxIncludes LESS ${COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES}) + set (_maxIncludes ${COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES}) + endif() + elseif (NOT _maxIncludes MATCHES "[0-9]+") + set (_maxIncludes 0) + endif() + if (COTIRE_DEBUG) + message (STATUS "${_target} unity source max includes = ${_maxIncludes}") + endif() + set (${_maxIncludesVar} ${_maxIncludes} PARENT_SCOPE) +endfunction() + function (cotire_process_target_language _language _configurations _targetSourceDir _targetBinaryDir _target _wholeTargetVar _cmdsVar) set (${_cmdsVar} "" PARENT_SCOPE) get_target_property(_targetSourceFiles ${_target} SOURCES) @@ -2154,10 +2235,7 @@ function (cotire_process_target_language _language _configurations _targetSource endif() cotire_generate_target_script( ${_language} "${_configurations}" "${_targetSourceDir}" "${_targetBinaryDir}" ${_target} _targetScript ${_unitySourceFiles}) - get_target_property(_maxIncludes ${_target} COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES) - if (NOT _maxIncludes) - set (_maxIncludes 0) - endif() + cotire_compute_unity_max_number_of_includes(${_target} _maxIncludes ${_unitySourceFiles}) cotire_make_unity_source_file_paths(${_language} ${_target} ${_maxIncludes} _unityFiles ${_unitySourceFiles}) if (NOT _unityFiles) return() @@ -2171,7 +2249,7 @@ function (cotire_process_target_language _language _configurations _targetSource if (_prefixHeaderFiles) cotire_setup_combine_command("${_targetSourceDir}" "${_targetScript}" "${_prefixFile}" _cmds ${_prefixHeaderFiles}) else() - cotire_setup_prefix_generation_command( + cotire_setup_multi_prefix_generation_command( ${_language} ${_target} "${_targetSourceDir}" "${_targetScript}" "${_prefixFile}" "${_unityFiles}" _cmds ${_unitySourceFiles}) endif() get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER) @@ -2295,20 +2373,6 @@ function (cotire_setup_unity_build_target _languages _configurations _targetSour endif() # add unity source files instead list (APPEND _unityTargetSources ${_unityFiles}) - # make unity files use precompiled header if there are multiple unity files - list (LENGTH _unityFiles _numberOfUnityFiles) - if (_targetUsePCH AND _numberOfUnityFiles GREATER ${COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES}) - get_property(_prefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER) - get_property(_pchFile TARGET ${_target} PROPERTY COTIRE_${_language}_PRECOMPILED_HEADER) - if (_prefixFile AND _pchFile) - cotire_setup_pch_file_compilation( - ${_language} "${_targetBinaryDir}" "" "${_prefixFile}" "${_pchFile}" ${_unityFiles}) - cotire_setup_prefix_file_inclusion( - ${_language} ${_target} FALSE "${_prefixFile}" "${_pchFile}" ${_unityFiles}) - # add the prefix header to unity target sources - list (APPEND _unityTargetSources "${_prefixFile}") - endif() - endif() endif() endforeach() if (COTIRE_DEBUG) @@ -2756,7 +2820,17 @@ else() set (COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES "3" CACHE STRING "Minimum number of sources in target required to enable use of precompiled header.") - set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES "" CACHE STRING + if (NOT DEFINED COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT) + if (DEFINED COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES) + set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT ${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES}) + elseif ("${CMAKE_GENERATOR}" MATCHES "JOM|Ninja|Visual Studio") + # enable parallelization for generators that run multiple jobs by default + set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT "-j") + else() + set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT "0") + endif() + endif() + set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES "${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT}" CACHE STRING "Maximum number of source files to include in a single unity source file.") if (NOT COTIRE_PREFIX_HEADER_FILENAME_SUFFIX) @@ -2842,11 +2916,13 @@ else() CACHED_VARIABLE PROPERTY "COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES" BRIEF_DOCS "Maximum number of source files to include in a single unity source file." FULL_DOCS - "This may be set to an integer > 0." + "This may be set to an integer >= 0." + "If 0, cotire will only create a single unity source file." "If a target contains more than that number of source files, cotire will create multiple unity source files for it." - "If not set, cotire will only create a single unity source file." + "Can be set to \"-j\" to optimize the count of unity source files for the number of available processor cores." + "Can be set to \"-j jobs\" to optimize the number of unity source files for the given number of simultaneous jobs." "Is used to initialize the target property COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES." - "Defaults to empty." + "Defaults to \"-j\" for the generators Visual Studio, JOM or Ninja. Defaults to 0 otherwise." ) # define cotire directory properties diff --git a/HISTORY.md b/HISTORY.md index a88609a..c821ab6 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,10 @@ +## 1.4.0 (2013-03-11) + +* one year anniversary release. +* add support for multi-core optimized unity builds for some CMake generators. +* add support for multi-core optimized prefix header generation. +* add more examples to cotire manual. + ## 1.3.6 (2013-03-06) * fix bug with prefix header initialization for generator Xcode. diff --git a/MANUAL.md b/MANUAL.md index d522b24..047fd1f 100644 --- a/MANUAL.md +++ b/MANUAL.md @@ -127,6 +127,9 @@ The unity source file uses absolute paths to include the target's source file. T intended to be portable across different build folders or machines. It is an intermediate file tied to the build folder that is automatically recreated by the build system if it is missing. +For multi-core machines cotire can be configured to generate multiple unity file segments that +can be built in parallel by the chosen CMake generator (see below). + ### the prefix header The prefix header is produced from the unity source file by running the unity file through the @@ -180,10 +183,12 @@ The generated prefix file includes the selected header files by their absolute p up the precompiling of the prefix header because the compiler does not have to search for header files in include directories again. -The prefix header is tailored to the CMake target that it is generated for and cannot be re-used -for a different CMake target. It is tied to the compiler environment of the local machine and -is not portable across different compilers or machines. It is automatically recreated by the -build system if it goes missing. +The prefix header is tailored to the CMake target that it is generated for. It is tied to the +compiler environment of the local machine and is not portable across different compilers or +machines. It is automatically recreated by the build system if it goes missing. + +The generated prefix header can be applied to a different target added in the same source directory +(see below). ### the precompiled header @@ -226,11 +231,24 @@ the correct precompiled header depending on the compilation language of the sour For a cotired target the target properties `COTIRE__UNITY_SOURCE`, `COTIRE__PREFIX_HEADER`, `COTIRE__PRECOMPILED_HEADER` will be set to the paths of the generated files (`` can be set to `CXX` or `C`). The target property -`COTIRE_UNITY_TARGET_NAME` will be set to the name of the generated unity target. +`COTIRE_UNITY_TARGET_NAME` will be set to the name of the generated unity target: + + cotire(example) + ... + get_target_property(_unitySource example COTIRE_CXX_UNITY_SOURCE) + get_target_property(_prefixHeader example COTIRE_CXX_PREFIX_HEADER) + get_target_property(_precompiledHeader example COTIRE_CXX_PRECOMPILED_HEADER) If a source file's `COMPILE_FLAGS` are modified by cotire, it sets the source file property `COTIRE_TARGET` to the name of the target, that the source file's build command has been -altered for. +altered for: + + cotire(example) + ... + get_source_file_property(_cotireTargetName "example.cpp" COTIRE_TARGET) + if (_cotireTargetName) + message(STATUS "example.cpp has been cotired for target ${_cotireTargetName}") + endif() ### changing the name of the generated unity build target @@ -281,7 +299,10 @@ directories. A target inherits the property value from its enclosing directory. ### disabling precompiled headers for small targets The cache variable `COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES` can be set to the minimum number of -source files required to enable the use of a precompiled header. It defaults to 3. +source files required to enable the use of a precompiled header. It defaults to 3. To override the +default, run `cmake` with the following options: + + $ cmake -D COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES=5 ### using a manually maintained prefix header instead of the automatically generated one @@ -293,23 +314,25 @@ file. The path is interpreted relative to the target source directory: set_target_properties(example PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "stdafx.h") cotire(example) -The property can also be set to a list of header files which will then make up the contents of -the generated prefix header. - If the prefix header `stdafx.h` needs an accompanying source file (e.g., `stdafx.cpp`) in order to be pre-compiled properly, that source file needs to be the first one on the list of source files in the target's `add_executable` or `add_library` call. +The property `COTIRE_CXX_PREFIX_HEADER_INIT` can also be set to a list of header files which will +then make up the contents of the generated prefix header. + ### using a generated prefix header for multiple targets -A prefix header that is generated for a cotired target can be applied to a different target that -has been added in the same source directory: +A prefix header that is generated for a cotired target can be applied to a different target +added in the same source directory: cotire(example) get_target_property(_prefixHeader example COTIRE_CXX_PREFIX_HEADER) ... - set_target_properties(example2 PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "${_prefixHeader}") - cotire(example2) + set_target_properties(other_target PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "${_prefixHeader}") + cotire(other_target) + +The compilation of either target will trigger the generation of the prefix header. ### configuring the generation of the prefix header @@ -350,7 +373,9 @@ removed from a target source file). Cotire does not automatically recreate the p when a target source file is changed, because this would always trigger a re-compilation of the precompiled header and would result in a rebuild of the whole target. To make the prefix header creation dependent on changes to certain target source files, the source file property -`COTIRE_DEPENDENCY` can be set to `TRUE` for those files. +`COTIRE_DEPENDENCY` can be set to `TRUE` for those files: + + set_property (SOURCE "example.cpp" PROPERTY COTIRE_DEPENDENCY "TRUE") ### fixing linkage issues @@ -378,7 +403,7 @@ upon linking. ### using a manually maintained unity source instead of the automatically generated one -cotire can be configured to use an existing manually maintained unity source file instead of the +Cotire can be configured to use an existing manually maintained unity source file instead of the automatically generated one. Set the target property `COTIRE_CXX_UNITY_SOURCE_INIT` to the path of the existing unity source file. Its path is interpreted relative to the target source directory: @@ -417,6 +442,25 @@ this property, it will complete the current unity file and start a new one. The file will include the source file as the first one. This property essentially works as a separator for unity source files. +### optimizing the build process for multiple processor cores + +To make use of all the machine's CPU cores for the unity compilation of a target, the target +property `COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES` can be set to the string `-j`. Cotire +will then create as many unity file segments as there are CPU cores on the machine. Because +the unity file segments do not depend on each other, a multi-core aware build process can compile +the file segments in parallel. + +To explicitly specify the number of cores, append the number after `-j`, e.g. `-j 4` or `-j4`. + +For CMake generators that are multi-core aware by default (i.e., Visual Studio, JOM, Ninja) cotire +will automatically initialize the property to `-j`. For makefile based generators, this has to be +done explicitly by setting the cache variable `COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES`, i.e.: + + $ cmake -D COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES=-j4 + $ make -j 4 + +The setting `-j` will also make the automatic prefix header generation run in parallel. + ### fixing macro definition clashes Many unity build problems stem from macro definitions leaking into other target source files, @@ -452,6 +496,22 @@ source and the prefix header for verbose builds. `COTIRE_VERBOSE` defaults to `F When using a Makefile generator `COTIRE_VERBOSE` defaults to the value of the makefile variable `VERBOSE` (i.e., `make VERBOSE=1`). +### conditionally loading cotire + +To make a `CMakeLists.txt` robust against a missing `cotire.cmake` module, the following strategy +can be applied to using cotire: + + include(cotire OPTIONAL) + ... + add_executable(example main.cpp example.cpp log.cpp log.h example.h) + ... + if (COMMAND cotire) + cotire(example) + endif() + +The `include(cotire OPTIONAL)` will prevent CMake from raising an error if cotire cannot be +found. The actual calls to cotire need to be guarded by `if (COMMAND cotire)` blocks. + ### using cotire with compiler wrappers Cotire is compatible with CMake compiler wrappers. For example, the use of [ccache][ccch] may be @@ -514,6 +574,10 @@ The Intel compiler may issue incorrect warnings #672 (the command line options d used when precompiled header was created) or #673 (the initial sequence of preprocessing directives is not compatible with those of precompiled header file) upon compilation of cotired targets. +### IncrediBuild + +Cotire is not compatible with [Xoreax IncrediBuild][XGE]. + [1260]:http://www.cmake.org/Bug/view.php?id=1260 [ccch]:http://ccache.samba.org/ [clang_pch]:http://clang.llvm.org/docs/UsersManual.html#precompiledheaders @@ -528,3 +592,4 @@ is not compatible with those of precompiled header file) upon compilation of cot [objlib]:http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_library [pfh]:http://en.wikipedia.org/wiki/Prefix_header [icc_linux]:http://software.intel.com/en-us/non-commercial-software-development +[XGE]:http://www.incredibuild.com diff --git a/README.md b/README.md index b3620e6..d155ca2 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ features * Supports console (Makefile generator) and IDE (Visual Studio and Xcode) based builds. * Compatible with CMake single build type and CMake multi-configuration builds. * Compatible with most CMake generators (including [Ninja][ninja]). -* Compatible with parallel builds (make -j, [jom][jom], Visual Studio, Xcode). +* Supports multi-core unity builds for some generators (make -j, [jom][jom], Visual Studio, Ninja). * Leverages native precompiled header generation features of IDEs (Visual Studio and Xcode). * Compatible with CMake's [cross-compiling][ccrc] support. * Compatible with compiler wrappers like [ccache][ccch]. @@ -87,7 +87,8 @@ the original target, but does so much faster by entering: $ make MyExecutable_unity See the advanced usage section of the [cotire manual][manual] for information on how to -configure the cotire process (e.g., how to apply cotire to a certain build configuration only). +configure the cotire process (e.g., how to make the unity build use all available processor +cores). The directory `Patches` contains patch files to enable cotire for some popular open sources packages that use CMake as a build system.