diff --git a/.gitignore b/.gitignore index 62a92525..f4195817 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ cotire/ Makefile Testing/ +.ninja_deps .ninja_log *.ninja diff --git a/CMake/cotire.cmake b/CMake/cotire.cmake deleted file mode 100644 index d855c1d4..00000000 --- a/CMake/cotire.cmake +++ /dev/null @@ -1,3551 +0,0 @@ -# - cotire (compile time reducer) -# -# See the cotire manual for usage hints. -# -#============================================================================= -# Copyright 2012-2014 Sascha Kratky -# -# Permission is hereby granted, free of charge, to any person -# obtaining a copy of this software and associated documentation -# files (the "Software"), to deal in the Software without -# restriction, including without limitation the rights to use, -# copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following -# conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -# OTHER DEALINGS IN THE SOFTWARE. -#============================================================================= - -if(__COTIRE_INCLUDED) - return() -endif() -set(__COTIRE_INCLUDED TRUE) - -# call cmake_minimum_required, but prevent modification of the CMake policy stack in include mode -# cmake_minimum_required also sets the policy version as a side effect, which we have to avoid -if (NOT CMAKE_SCRIPT_MODE_FILE) - cmake_policy(PUSH) -endif() -# we need the CMake variables CMAKE_SCRIPT_MODE_FILE and CMAKE_ARGV available since 2.8.5 -# we need APPEND_STRING option for set_property available since 2.8.6 -cmake_minimum_required(VERSION 2.8.6) -if (NOT CMAKE_SCRIPT_MODE_FILE) - cmake_policy(POP) -endif() - -set (COTIRE_CMAKE_MODULE_FILE "${CMAKE_CURRENT_LIST_FILE}") -set (COTIRE_CMAKE_MODULE_VERSION "1.6.6") - -include(CMakeParseArguments) -include(ProcessorCount) - -function (cotire_determine_compiler_version _language _versionPrefix) - if (NOT ${_versionPrefix}_VERSION) - # use CMake's predefined compiler version variable (available since CMake 2.8.8) - if (DEFINED CMAKE_${_language}_COMPILER_VERSION) - set (${_versionPrefix}_VERSION "${CMAKE_${_language}_COMPILER_VERSION}") - elseif (WIN32) - # cl.exe messes with the output streams unless the environment variable VS_UNICODE_OUTPUT is cleared - unset (ENV{VS_UNICODE_OUTPUT}) - string (STRIP "${CMAKE_${_language}_COMPILER_ARG1}" _compilerArg1) - execute_process ( - COMMAND ${CMAKE_${_language}_COMPILER} ${_compilerArg1} - ERROR_VARIABLE _versionLine OUTPUT_QUIET TIMEOUT 10) - string (REGEX REPLACE ".*Version *([0-9]+(\\.[0-9]+)*).*" "\\1" ${_versionPrefix}_VERSION "${_versionLine}") - else() - # assume GCC like command line interface - string (STRIP "${CMAKE_${_language}_COMPILER_ARG1}" _compilerArg1) - execute_process ( - COMMAND ${CMAKE_${_language}_COMPILER} ${_compilerArg1} "-dumpversion" - OUTPUT_VARIABLE ${_versionPrefix}_VERSION - RESULT_VARIABLE _result - OUTPUT_STRIP_TRAILING_WHITESPACE TIMEOUT 10) - if (_result) - set (${_versionPrefix}_VERSION "") - endif() - endif() - if (${_versionPrefix}_VERSION) - set (${_versionPrefix}_VERSION "${${_versionPrefix}_VERSION}" CACHE INTERNAL "${_language} compiler version") - endif() - set (${_versionPrefix}_VERSION "${${_versionPrefix}_VERSION}" PARENT_SCOPE) - if (COTIRE_DEBUG) - message (STATUS "${CMAKE_${_language}_COMPILER} version ${${_versionPrefix}_VERSION}") - endif() - endif() -endfunction() - -function (cotire_get_source_file_extension _sourceFile _extVar) - # get_filename_component returns extension from first occurrence of . in file name - # this function computes the extension from last occurrence of . in file name - string (FIND "${_sourceFile}" "." _index REVERSE) - if (_index GREATER -1) - math (EXPR _index "${_index} + 1") - string (SUBSTRING "${_sourceFile}" ${_index} -1 _sourceExt) - else() - set (_sourceExt "") - endif() - set (${_extVar} "${_sourceExt}" PARENT_SCOPE) -endfunction() - -macro (cotire_check_is_path_relative_to _path _isRelativeVar) - set (${_isRelativeVar} FALSE) - if (IS_ABSOLUTE "${_path}") - foreach (_dir ${ARGN}) - file (RELATIVE_PATH _relPath "${_dir}" "${_path}") - if (NOT _relPath OR (NOT IS_ABSOLUTE "${_relPath}" AND NOT "${_relPath}" MATCHES "^\\.\\.")) - set (${_isRelativeVar} TRUE) - break() - endif() - endforeach() - endif() -endmacro() - -function (cotire_filter_language_source_files _language _sourceFilesVar _excludedSourceFilesVar _cotiredSourceFilesVar) - set (_sourceFiles "") - set (_excludedSourceFiles "") - set (_cotiredSourceFiles "") - if (CMAKE_${_language}_SOURCE_FILE_EXTENSIONS) - set (_languageExtensions "${CMAKE_${_language}_SOURCE_FILE_EXTENSIONS}") - else() - set (_languageExtensions "") - endif() - if (CMAKE_${_language}_IGNORE_EXTENSIONS) - set (_ignoreExtensions "${CMAKE_${_language}_IGNORE_EXTENSIONS}") - else() - set (_ignoreExtensions "") - endif() - if (COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS) - set (_excludeExtensions "${COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS}") - else() - set (_excludeExtensions "") - endif() - if (COTIRE_DEBUG) - message (STATUS "${_language} source file extensions: ${_languageExtensions}") - message (STATUS "${_language} ignore extensions: ${_ignoreExtensions}") - message (STATUS "${_language} exclude extensions: ${_excludeExtensions}") - endif() - foreach (_sourceFile ${ARGN}) - get_source_file_property(_sourceIsHeaderOnly "${_sourceFile}" HEADER_FILE_ONLY) - get_source_file_property(_sourceIsExternal "${_sourceFile}" EXTERNAL_OBJECT) - get_source_file_property(_sourceIsSymbolic "${_sourceFile}" SYMBOLIC) - get_source_file_property(_sourceLanguage "${_sourceFile}" LANGUAGE) - set (_sourceIsFiltered FALSE) - if (NOT _sourceIsHeaderOnly AND NOT _sourceIsExternal AND NOT _sourceIsSymbolic) - cotire_get_source_file_extension("${_sourceFile}" _sourceExt) - if (_sourceExt) - list (FIND _ignoreExtensions "${_sourceExt}" _ignoreIndex) - if (_ignoreIndex LESS 0) - list (FIND _excludeExtensions "${_sourceExt}" _excludeIndex) - if (_excludeIndex GREATER -1) - list (APPEND _excludedSourceFiles "${_sourceFile}") - else() - list (FIND _languageExtensions "${_sourceExt}" _sourceIndex) - if (_sourceIndex GREATER -1) - set (_sourceIsFiltered TRUE) - elseif ("${_sourceLanguage}" STREQUAL "${_language}") - # add to excluded sources, if file is not ignored and has correct language without having the correct extension - list (APPEND _excludedSourceFiles "${_sourceFile}") - endif() - endif() - endif() - endif() - endif() - if (COTIRE_DEBUG) - message (STATUS "${_sourceFile} filtered=${_sourceIsFiltered} language=${_sourceLanguage} header=${_sourceIsHeaderOnly}") - endif() - if (_sourceIsFiltered) - get_source_file_property(_sourceIsExcluded "${_sourceFile}" COTIRE_EXCLUDED) - get_source_file_property(_sourceIsCotired "${_sourceFile}" COTIRE_TARGET) - get_source_file_property(_sourceCompileFlags "${_sourceFile}" COMPILE_FLAGS) - if (COTIRE_DEBUG) - message (STATUS "${_sourceFile} excluded=${_sourceIsExcluded} cotired=${_sourceIsCotired} compileFlags=${_sourceCompileFlags}") - endif() - if (_sourceIsCotired) - list (APPEND _cotiredSourceFiles "${_sourceFile}") - elseif (_sourceIsExcluded OR _sourceCompileFlags) - list (APPEND _excludedSourceFiles "${_sourceFile}") - else() - list (APPEND _sourceFiles "${_sourceFile}") - endif() - endif() - endforeach() - if (COTIRE_DEBUG) - message (STATUS "All: ${ARGN}") - message (STATUS "${_language}: ${_sourceFiles}") - message (STATUS "Excluded: ${_excludedSourceFiles}") - message (STATUS "Cotired: ${_cotiredSourceFiles}") - endif() - set (${_sourceFilesVar} ${_sourceFiles} PARENT_SCOPE) - set (${_excludedSourceFilesVar} ${_excludedSourceFiles} PARENT_SCOPE) - set (${_cotiredSourceFilesVar} ${_cotiredSourceFiles} PARENT_SCOPE) -endfunction() - -function (cotire_get_objects_with_property_on _filteredObjectsVar _property _type) - set (_filteredObjects "") - foreach (_object ${ARGN}) - get_property(_isSet ${_type} "${_object}" PROPERTY ${_property} SET) - if (_isSet) - get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property}) - if (_propertyValue) - list (APPEND _filteredObjects "${_object}") - endif() - endif() - endforeach() - set (${_filteredObjectsVar} ${_filteredObjects} PARENT_SCOPE) -endfunction() - -function (cotire_get_objects_with_property_off _filteredObjectsVar _property _type) - set (_filteredObjects "") - foreach (_object ${ARGN}) - get_property(_isSet ${_type} "${_object}" PROPERTY ${_property} SET) - if (_isSet) - get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property}) - if (NOT _propertyValue) - list (APPEND _filteredObjects "${_object}") - endif() - endif() - endforeach() - set (${_filteredObjectsVar} ${_filteredObjects} PARENT_SCOPE) -endfunction() - -function (cotire_get_source_file_property_values _valuesVar _property) - set (_values "") - foreach (_sourceFile ${ARGN}) - get_source_file_property(_propertyValue "${_sourceFile}" ${_property}) - if (_propertyValue) - list (APPEND _values "${_propertyValue}") - endif() - endforeach() - set (${_valuesVar} ${_values} PARENT_SCOPE) -endfunction() - -function (cotire_resolve_config_properites _configurations _propertiesVar) - set (_properties "") - foreach (_property ${ARGN}) - if ("${_property}" MATCHES "") - foreach (_config ${_configurations}) - string (TOUPPER "${_config}" _upperConfig) - string (REPLACE "" "${_upperConfig}" _configProperty "${_property}") - list (APPEND _properties ${_configProperty}) - endforeach() - else() - list (APPEND _properties ${_property}) - endif() - endforeach() - set (${_propertiesVar} ${_properties} PARENT_SCOPE) -endfunction() - -function (cotire_copy_set_properites _configurations _type _source _target) - cotire_resolve_config_properites("${_configurations}" _properties ${ARGN}) - foreach (_property ${_properties}) - get_property(_isSet ${_type} ${_source} PROPERTY ${_property} SET) - if (_isSet) - get_property(_propertyValue ${_type} ${_source} PROPERTY ${_property}) - set_property(${_type} ${_target} PROPERTY ${_property} "${_propertyValue}") - endif() - endforeach() -endfunction() - -function (cotire_get_target_link_libraries_for_usage_requirements _target _targetLinkLibrariesVar) - set (_targetLinkLibraries "") - get_target_property(_librariesToProcess ${_target} LINK_LIBRARIES) - while (_librariesToProcess) - # remove from head - list (GET _librariesToProcess 0 _library) - list (REMOVE_AT _librariesToProcess 0) - list (FIND _targetLinkLibraries ${_library} _index) - if (_index LESS 0) - list (APPEND _targetLinkLibraries ${_library}) - # process transitive libraries - if (TARGET ${_library}) - get_target_property(_libraries ${_library} INTERFACE_LINK_LIBRARIES) - if (_libraries) - list (APPEND _librariesToProcess ${_libraries}) - endif() - endif() - endif() - endwhile() - set (${_targetLinkLibrariesVar} ${_targetLinkLibraries} PARENT_SCOPE) -endfunction() - -function (cotire_filter_compile_flags _language _flagFilter _matchedOptionsVar _unmatchedOptionsVar) - if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") - set (_flagPrefix "[/-]") - else() - set (_flagPrefix "--?") - endif() - set (_optionFlag "") - set (_matchedOptions "") - set (_unmatchedOptions "") - foreach (_compileFlag ${ARGN}) - if (_compileFlag) - if (_optionFlag AND NOT "${_compileFlag}" MATCHES "^${_flagPrefix}") - # option with separate argument - list (APPEND _matchedOptions "${_compileFlag}") - set (_optionFlag "") - elseif ("${_compileFlag}" MATCHES "^(${_flagPrefix})(${_flagFilter})$") - # remember option - set (_optionFlag "${CMAKE_MATCH_2}") - elseif ("${_compileFlag}" MATCHES "^(${_flagPrefix})(${_flagFilter})(.+)$") - # option with joined argument - list (APPEND _matchedOptions "${CMAKE_MATCH_3}") - set (_optionFlag "") - else() - # flush remembered option - if (_optionFlag) - list (APPEND _matchedOptions "${_optionFlag}") - set (_optionFlag "") - endif() - # add to unfiltered options - list (APPEND _unmatchedOptions "${_compileFlag}") - endif() - endif() - endforeach() - if (_optionFlag) - list (APPEND _matchedOptions "${_optionFlag}") - endif() - if (COTIRE_DEBUG) - message (STATUS "Filter ${_flagFilter}") - if (_matchedOptions) - message (STATUS "Matched ${_matchedOptions}") - endif() - if (_unmatchedOptions) - message (STATUS "Unmatched ${_unmatchedOptions}") - endif() - endif() - set (${_matchedOptionsVar} ${_matchedOptions} PARENT_SCOPE) - set (${_unmatchedOptionsVar} ${_unmatchedOptions} PARENT_SCOPE) -endfunction() - -function (cotire_get_target_compile_flags _config _language _directory _target _flagsVar) - string (TOUPPER "${_config}" _upperConfig) - # collect options from CMake language variables - set (_compileFlags "") - if (CMAKE_${_language}_FLAGS) - set (_compileFlags "${_compileFlags} ${CMAKE_${_language}_FLAGS}") - endif() - if (CMAKE_${_language}_FLAGS_${_upperConfig}) - set (_compileFlags "${_compileFlags} ${CMAKE_${_language}_FLAGS_${_upperConfig}}") - endif() - if (_target) - # add option from CMake target type variable - get_target_property(_targetType ${_target} TYPE) - if (POLICY CMP0018) - # handle POSITION_INDEPENDENT_CODE property introduced with CMake 2.8.9 if policy CMP0018 is turned on - cmake_policy(GET CMP0018 _PIC_Policy) - else() - # default to old behavior - set (_PIC_Policy "OLD") - endif() - if (COTIRE_DEBUG) - message(STATUS "CMP0018=${_PIC_Policy}") - endif() - if (_PIC_Policy STREQUAL "NEW") - # NEW behavior: honor the POSITION_INDEPENDENT_CODE target property - get_target_property(_targetPIC ${_target} POSITION_INDEPENDENT_CODE) - if (_targetPIC) - if (_targetType STREQUAL "EXECUTABLE" AND CMAKE_${_language}_COMPILE_OPTIONS_PIE) - set (_compileFlags "${_compileFlags} ${CMAKE_${_language}_COMPILE_OPTIONS_PIE}") - elseif (CMAKE_${_language}_COMPILE_OPTIONS_PIC) - set (_compileFlags "${_compileFlags} ${CMAKE_${_language}_COMPILE_OPTIONS_PIC}") - endif() - endif() - else() - # OLD behavior or policy not set: use the value of CMAKE_SHARED_LIBRARY__FLAGS - if (_targetType STREQUAL "MODULE_LIBRARY") - # flags variable for module library uses different name SHARED_MODULE - # (e.g., CMAKE_SHARED_MODULE_C_FLAGS) - set (_targetType SHARED_MODULE) - endif() - if (CMAKE_${_targetType}_${_language}_FLAGS) - set (_compileFlags "${_compileFlags} ${CMAKE_${_targetType}_${_language}_FLAGS}") - endif() - endif() - endif() - if (_directory) - # add_definitions may have been used to add flags to the compiler command - get_directory_property(_dirDefinitions DIRECTORY "${_directory}" DEFINITIONS) - if (_dirDefinitions) - set (_compileFlags "${_compileFlags} ${_dirDefinitions}") - endif() - endif() - if (_target) - # add target compile options - get_target_property(_targetflags ${_target} COMPILE_FLAGS) - if (_targetflags) - set (_compileFlags "${_compileFlags} ${_targetflags}") - endif() - get_target_property(_targetOptions ${_target} COMPILE_OPTIONS) - if (_targetOptions) - set (_compileFlags "${_compileFlags} ${_targetOptions}") - endif() - # interface compile options from linked library targets - cotire_get_target_link_libraries_for_usage_requirements(${_target} _linkLibraries) - foreach (_library ${_linkLibraries}) - if (TARGET ${_library}) - get_target_property(_targetOptions ${_library} INTERFACE_COMPILE_OPTIONS) - if (_targetOptions) - set (_compileFlags "${_compileFlags} ${_targetOptions}") - endif() - endif() - endforeach() - endif() - if (UNIX) - separate_arguments(_compileFlags UNIX_COMMAND "${_compileFlags}") - elseif(WIN32) - separate_arguments(_compileFlags WINDOWS_COMMAND "${_compileFlags}") - else() - separate_arguments(_compileFlags) - endif() - # platform specific flags - if (APPLE) - get_target_property(_architectures ${_target} OSX_ARCHITECTURES_${_upperConfig}) - if (NOT _architectures) - get_target_property(_architectures ${_target} OSX_ARCHITECTURES) - endif() - if (_architectures) - foreach (_arch ${_architectures}) - list (APPEND _compileFlags "-arch" "${_arch}") - endforeach() - endif() - if (CMAKE_OSX_SYSROOT) - if (CMAKE_${_language}_SYSROOT_FLAG) - list (APPEND _compileFlags "${CMAKE_${_language}_SYSROOT_FLAG}" "${CMAKE_OSX_SYSROOT}") - else() - list (APPEND _compileFlags "-isysroot" "${CMAKE_OSX_SYSROOT}") - endif() - endif() - if (CMAKE_OSX_DEPLOYMENT_TARGET) - if (CMAKE_${_language}_OSX_DEPLOYMENT_TARGET_FLAG) - list (APPEND _compileFlags "${CMAKE_${_language}_OSX_DEPLOYMENT_TARGET_FLAG}${CMAKE_OSX_DEPLOYMENT_TARGET}") - else() - list (APPEND _compileFlags "-mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}") - endif() - endif() - endif() - if (COTIRE_DEBUG AND _compileFlags) - message (STATUS "Target ${_target} compile flags ${_compileFlags}") - endif() - set (${_flagsVar} ${_compileFlags} PARENT_SCOPE) -endfunction() - -function (cotire_get_target_include_directories _config _language _targetSourceDir _targetBinaryDir _target _includeDirsVar _systemIncludeDirsVar) - set (_includeDirs "") - set (_systemIncludeDirs "") - # default include dirs - if (CMAKE_INCLUDE_CURRENT_DIR) - list (APPEND _includeDirs "${_targetBinaryDir}") - list (APPEND _includeDirs "${_targetSourceDir}") - endif() - # parse additional include directories from target compile flags - set (_targetFlags "") - cotire_get_target_compile_flags("${_config}" "${_language}" "${_targetSourceDir}" "${_target}" _targetFlags) - cotire_filter_compile_flags("${_language}" "I" _dirs _ignore ${_targetFlags}) - if (_dirs) - list (APPEND _includeDirs ${_dirs}) - endif() - # target include directories - get_directory_property(_dirs DIRECTORY "${_targetSourceDir}" INCLUDE_DIRECTORIES) - if (_target) - get_target_property(_targetDirs ${_target} INCLUDE_DIRECTORIES) - if (_targetDirs) - list (APPEND _dirs ${_targetDirs}) - endif() - get_target_property(_targetDirs ${_target} INTERFACE_SYSTEM_INCLUDE_DIRECTORIES) - if (_targetDirs) - list (APPEND _systemIncludeDirs ${_targetDirs}) - endif() - - # interface include directories from linked library targets - cotire_get_target_link_libraries_for_usage_requirements(${_target} _linkLibraries) - foreach (_library ${_linkLibraries}) - if (TARGET ${_library}) - get_target_property(_targetDirs ${_library} INTERFACE_INCLUDE_DIRECTORIES) - if (_targetDirs) - list (APPEND _dirs ${_targetDirs}) - endif() - get_target_property(_targetDirs ${_library} INTERFACE_SYSTEM_INCLUDE_DIRECTORIES) - if (_targetDirs) - list (APPEND _systemIncludeDirs ${_targetDirs}) - endif() - endif() - endforeach() - endif() - if (dirs) - list (REMOVE_DUPLICATES _dirs) - endif() - list (LENGTH _includeDirs _projectInsertIndex) - foreach (_dir ${_dirs}) - if (CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE) - cotire_check_is_path_relative_to("${_dir}" _isRelative "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}") - if (_isRelative) - list (LENGTH _includeDirs _len) - if (_len EQUAL _projectInsertIndex) - list (APPEND _includeDirs "${_dir}") - else() - list (INSERT _includeDirs _projectInsertIndex "${_dir}") - endif() - math (EXPR _projectInsertIndex "${_projectInsertIndex} + 1") - else() - list (APPEND _includeDirs "${_dir}") - endif() - else() - list (APPEND _includeDirs "${_dir}") - endif() - endforeach() - list (REMOVE_DUPLICATES _includeDirs) - list (REMOVE_DUPLICATES _systemIncludeDirs) - if (CMAKE_${_language}_IMPLICIT_INCLUDE_DIRECTORIES) - list (REMOVE_ITEM _includeDirs ${CMAKE_${_language}_IMPLICIT_INCLUDE_DIRECTORIES}) - endif() - if (COTIRE_DEBUG AND _includeDirs) - message (STATUS "Target ${_target} include dirs ${_includeDirs}") - endif() - set (${_includeDirsVar} ${_includeDirs} PARENT_SCOPE) - if (COTIRE_DEBUG AND _systemIncludeDirs) - message (STATUS "Target ${_target} system include dirs ${_systemIncludeDirs}") - endif() - set (${_systemIncludeDirsVar} ${_systemIncludeDirs} PARENT_SCOPE) -endfunction() - -macro (cotire_make_C_identifier _identifierVar _str) - if (CMAKE_VERSION VERSION_LESS "2.8.12") - # mimic CMake SystemTools::MakeCindentifier behavior - if ("${_str}" MATCHES "^[0-9].+$") - set (_str "_${str}") - endif() - string (REGEX REPLACE "[^a-zA-Z0-9]" "_" ${_identifierVar} "${_str}") - else() - string (MAKE_C_IDENTIFIER "${_str}" "${_identifierVar}") - endif() -endmacro() - -function (cotire_get_target_export_symbol _target _exportSymbolVar) - set (_exportSymbol "") - get_target_property(_targetType ${_target} TYPE) - get_target_property(_enableExports ${_target} ENABLE_EXPORTS) - if (_targetType MATCHES "(SHARED|MODULE)_LIBRARY" OR - (_targetType STREQUAL "EXECUTABLE" AND _enableExports)) - get_target_property(_exportSymbol ${_target} DEFINE_SYMBOL) - if (NOT _exportSymbol) - set (_exportSymbol "${_target}_EXPORTS") - endif() - cotire_make_C_identifier(_exportSymbol "${_exportSymbol}") - endif() - set (${_exportSymbolVar} ${_exportSymbol} PARENT_SCOPE) -endfunction() - -function (cotire_get_target_compile_definitions _config _language _directory _target _definitionsVar) - string (TOUPPER "${_config}" _upperConfig) - set (_configDefinitions "") - # CMAKE_INTDIR for multi-configuration build systems - if (NOT "${CMAKE_CFG_INTDIR}" STREQUAL ".") - list (APPEND _configDefinitions "CMAKE_INTDIR=\"${_config}\"") - endif() - # target export define symbol - cotire_get_target_export_symbol("${_target}" _defineSymbol) - if (_defineSymbol) - list (APPEND _configDefinitions "${_defineSymbol}") - endif() - # directory compile definitions - get_directory_property(_definitions DIRECTORY "${_directory}" COMPILE_DEFINITIONS) - if (_definitions) - list (APPEND _configDefinitions ${_definitions}) - endif() - get_directory_property(_definitions DIRECTORY "${_directory}" COMPILE_DEFINITIONS_${_upperConfig}) - if (_definitions) - list (APPEND _configDefinitions ${_definitions}) - endif() - # target compile definitions - get_target_property(_definitions ${_target} COMPILE_DEFINITIONS) - if (_definitions) - list (APPEND _configDefinitions ${_definitions}) - endif() - get_target_property(_definitions ${_target} COMPILE_DEFINITIONS_${_upperConfig}) - if (_definitions) - list (APPEND _configDefinitions ${_definitions}) - endif() - # interface compile definitions from linked library targets - cotire_get_target_link_libraries_for_usage_requirements(${_target} _linkLibraries) - foreach (_library ${_linkLibraries}) - if (TARGET ${_library}) - get_target_property(_definitions ${_library} INTERFACE_COMPILE_DEFINITIONS) - if (_definitions) - list (APPEND _configDefinitions ${_definitions}) - endif() - endif() - endforeach() - # parse additional compile definitions from target compile flags - # and don't look at directory compile definitions, which we already handled - set (_targetFlags "") - cotire_get_target_compile_flags("${_config}" "${_language}" "" "${_target}" _targetFlags) - cotire_filter_compile_flags("${_language}" "D" _definitions _ignore ${_targetFlags}) - if (_definitions) - list (APPEND _configDefinitions ${_definitions}) - endif() - list (REMOVE_DUPLICATES _configDefinitions) - if (COTIRE_DEBUG AND _configDefinitions) - message (STATUS "Target ${_target} compile definitions ${_configDefinitions}") - endif() - set (${_definitionsVar} ${_configDefinitions} PARENT_SCOPE) -endfunction() - -function (cotire_get_target_compiler_flags _config _language _directory _target _compilerFlagsVar) - # parse target compile flags omitting compile definitions and include directives - set (_targetFlags "") - cotire_get_target_compile_flags("${_config}" "${_language}" "${_directory}" "${_target}" _targetFlags) - set (_compilerFlags "") - cotire_filter_compile_flags("${_language}" "[ID]" _ignore _compilerFlags ${_targetFlags}) - if (COTIRE_DEBUG AND _compilerFlags) - message (STATUS "Target ${_target} compiler flags ${_compilerFlags}") - endif() - set (${_compilerFlagsVar} ${_compilerFlags} PARENT_SCOPE) -endfunction() - -function (cotire_add_sys_root_paths _pathsVar) - if (APPLE) - if (CMAKE_OSX_SYSROOT AND CMAKE_${_language}_HAS_ISYSROOT) - foreach (_path IN LISTS ${_pathsVar}) - if (IS_ABSOLUTE "${_path}") - get_filename_component(_path "${CMAKE_OSX_SYSROOT}/${_path}" ABSOLUTE) - if (EXISTS "${_path}") - list (APPEND ${_pathsVar} "${_path}") - endif() - endif() - endforeach() - endif() - endif() - set (${_pathsVar} ${${_pathsVar}} PARENT_SCOPE) - if (COTIRE_DEBUG) - message (STATUS "${_pathsVar}=${${_pathsVar}}") - endif() -endfunction() - -function (cotire_get_source_extra_properties _sourceFile _pattern _resultVar) - set (_extraProperties ${ARGN}) - set (_result "") - if (_extraProperties) - list (FIND _extraProperties "${_sourceFile}" _index) - if (_index GREATER -1) - math (EXPR _index "${_index} + 1") - list (LENGTH _extraProperties _len) - math (EXPR _len "${_len} - 1") - foreach (_index RANGE ${_index} ${_len}) - list (GET _extraProperties ${_index} _value) - if (_value MATCHES "${_pattern}") - list (APPEND _result "${_value}") - else() - break() - endif() - endforeach() - endif() - endif() - set (${_resultVar} ${_result} PARENT_SCOPE) -endfunction() - -function (cotire_get_source_compile_definitions _config _language _sourceFile _definitionsVar) - set (_compileDefinitions "") - if (NOT CMAKE_SCRIPT_MODE_FILE) - string (TOUPPER "${_config}" _upperConfig) - get_source_file_property(_definitions "${_sourceFile}" COMPILE_DEFINITIONS) - if (_definitions) - list (APPEND _compileDefinitions ${_definitions}) - endif() - get_source_file_property(_definitions "${_sourceFile}" COMPILE_DEFINITIONS_${_upperConfig}) - if (_definitions) - list (APPEND _compileDefinitions ${_definitions}) - endif() - endif() - cotire_get_source_extra_properties("${_sourceFile}" "^[a-zA-Z0-9_]+(=.*)?$" _definitions ${ARGN}) - if (_definitions) - list (APPEND _compileDefinitions ${_definitions}) - endif() - if (COTIRE_DEBUG AND _compileDefinitions) - message (STATUS "Source ${_sourceFile} compile definitions ${_compileDefinitions}") - endif() - set (${_definitionsVar} ${_compileDefinitions} PARENT_SCOPE) -endfunction() - -function (cotire_get_source_files_compile_definitions _config _language _definitionsVar) - set (_configDefinitions "") - foreach (_sourceFile ${ARGN}) - cotire_get_source_compile_definitions("${_config}" "${_language}" "${_sourceFile}" _sourceDefinitions) - if (_sourceDefinitions) - list (APPEND _configDefinitions "${_sourceFile}" ${_sourceDefinitions} "-") - endif() - endforeach() - set (${_definitionsVar} ${_configDefinitions} PARENT_SCOPE) -endfunction() - -function (cotire_get_source_undefs _sourceFile _property _sourceUndefsVar) - set (_sourceUndefs "") - if (NOT CMAKE_SCRIPT_MODE_FILE) - get_source_file_property(_undefs "${_sourceFile}" ${_property}) - if (_undefs) - list (APPEND _sourceUndefs ${_undefs}) - endif() - endif() - cotire_get_source_extra_properties("${_sourceFile}" "^[a-zA-Z0-9_]+$" _undefs ${ARGN}) - if (_undefs) - list (APPEND _sourceUndefs ${_undefs}) - endif() - if (COTIRE_DEBUG AND _sourceUndefs) - message (STATUS "Source ${_sourceFile} ${_property} undefs ${_sourceUndefs}") - endif() - set (${_sourceUndefsVar} ${_sourceUndefs} PARENT_SCOPE) -endfunction() - -function (cotire_get_source_files_undefs _property _sourceUndefsVar) - set (_sourceUndefs "") - foreach (_sourceFile ${ARGN}) - cotire_get_source_undefs("${_sourceFile}" ${_property} _undefs) - if (_undefs) - list (APPEND _sourceUndefs "${_sourceFile}" ${_undefs} "-") - endif() - endforeach() - set (${_sourceUndefsVar} ${_sourceUndefs} PARENT_SCOPE) -endfunction() - -macro (cotire_set_cmd_to_prologue _cmdVar) - set (${_cmdVar} "${CMAKE_COMMAND}") - if (COTIRE_DEBUG) - list (APPEND ${_cmdVar} "--warn-uninitialized") - endif() - list (APPEND ${_cmdVar} "-DCOTIRE_BUILD_TYPE:STRING=$") - if (COTIRE_VERBOSE) - list (APPEND ${_cmdVar} "-DCOTIRE_VERBOSE:BOOL=ON") - elseif("${CMAKE_GENERATOR}" MATCHES "Makefiles") - list (APPEND ${_cmdVar} "-DCOTIRE_VERBOSE:BOOL=$(VERBOSE)") - endif() -endmacro() - -function (cotire_init_compile_cmd _cmdVar _language _compilerExe _compilerArg1) - if (NOT _compilerExe) - set (_compilerExe "${CMAKE_${_language}_COMPILER}") - endif() - if (NOT _compilerArg1) - set (_compilerArg1 ${CMAKE_${_language}_COMPILER_ARG1}) - endif() - string (STRIP "${_compilerArg1}" _compilerArg1) - set (${_cmdVar} "${_compilerExe}" ${_compilerArg1} PARENT_SCOPE) -endfunction() - -macro (cotire_add_definitions_to_cmd _cmdVar _language) - foreach (_definition ${ARGN}) - if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") - list (APPEND ${_cmdVar} "/D${_definition}") - else() - list (APPEND ${_cmdVar} "-D${_definition}") - endif() - endforeach() -endmacro() - -macro (cotire_add_includes_to_cmd _cmdVar _language _includeSystemFlag _includesVar _systemIncludesVar) - foreach (_include ${${_includesVar}}) - if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") - file (TO_NATIVE_PATH "${_include}" _include) - list (APPEND ${_cmdVar} "/I${_include}") - else() - list (FIND ${_systemIncludesVar} ${_include} _index) - if(_index GREATER -1 AND NOT "${_includeSystemFlag}" STREQUAL "") - list (APPEND ${_cmdVar} "${_includeSystemFlag}${_include}") - else() - list (APPEND ${_cmdVar} "-I${_include}") - endif() - endif() - endforeach() -endmacro() - -macro (cotire_add_frameworks_to_cmd _cmdVar _language) - if (APPLE) - set (_frameWorkDirs "") - foreach (_include ${ARGN}) - if (IS_ABSOLUTE "${_include}" AND _include MATCHES "\\.framework$") - get_filename_component(_frameWorkDir "${_include}" PATH) - list (APPEND _frameWorkDirs "${_frameWorkDir}") - endif() - endforeach() - if (_frameWorkDirs) - list (REMOVE_DUPLICATES _frameWorkDirs) - foreach (_frameWorkDir ${_frameWorkDirs}) - list (APPEND ${_cmdVar} "-F${_frameWorkDir}") - endforeach() - endif() - endif() -endmacro() - -macro (cotire_add_compile_flags_to_cmd _cmdVar) - foreach (_flag ${ARGN}) - list (APPEND ${_cmdVar} "${_flag}") - endforeach() -endmacro() - -function (cotire_check_file_up_to_date _fileIsUpToDateVar _file) - set (${_fileIsUpToDateVar} FALSE PARENT_SCOPE) - set (_triggerFile "") - foreach (_dependencyFile ${ARGN}) - if (EXISTS "${_dependencyFile}" AND "${_dependencyFile}" IS_NEWER_THAN "${_file}") - set (_triggerFile "${_dependencyFile}") - break() - endif() - endforeach() - get_filename_component(_fileName "${_file}" NAME) - if (EXISTS "${_file}") - if (_triggerFile) - if (COTIRE_VERBOSE) - message (STATUS "${_fileName} update triggered by ${_triggerFile} change.") - endif() - else() - if (COTIRE_VERBOSE) - message (STATUS "${_fileName} is up-to-date.") - endif() - set (${_fileIsUpToDateVar} TRUE PARENT_SCOPE) - endif() - else() - if (COTIRE_VERBOSE) - message (STATUS "${_fileName} does not exist yet.") - endif() - endif() -endfunction() - -macro (cotire_find_closest_relative_path _headerFile _includeDirs _relPathVar) - set (${_relPathVar} "") - foreach (_includeDir ${_includeDirs}) - if (IS_DIRECTORY "${_includeDir}") - file (RELATIVE_PATH _relPath "${_includeDir}" "${_headerFile}") - if (NOT IS_ABSOLUTE "${_relPath}" AND NOT "${_relPath}" MATCHES "^\\.\\.") - string (LENGTH "${${_relPathVar}}" _closestLen) - string (LENGTH "${_relPath}" _relLen) - if (_closestLen EQUAL 0 OR _relLen LESS _closestLen) - set (${_relPathVar} "${_relPath}") - endif() - endif() - elseif ("${_includeDir}" STREQUAL "${_headerFile}") - # if path matches exactly, return short non-empty string - set (${_relPathVar} "1") - break() - endif() - endforeach() -endmacro() - -macro (cotire_check_header_file_location _headerFile _insideIncudeDirs _outsideIncudeDirs _headerIsInside) - # check header path against ignored and honored include directories - cotire_find_closest_relative_path("${_headerFile}" "${_insideIncudeDirs}" _insideRelPath) - if (_insideRelPath) - # header is inside, but could be become outside if there is a shorter outside match - cotire_find_closest_relative_path("${_headerFile}" "${_outsideIncudeDirs}" _outsideRelPath) - if (_outsideRelPath) - string (LENGTH "${_insideRelPath}" _insideRelPathLen) - string (LENGTH "${_outsideRelPath}" _outsideRelPathLen) - if (_outsideRelPathLen LESS _insideRelPathLen) - set (${_headerIsInside} FALSE) - else() - set (${_headerIsInside} TRUE) - endif() - else() - set (${_headerIsInside} TRUE) - endif() - else() - # header is outside - set (${_headerIsInside} FALSE) - endif() -endmacro() - -macro (cotire_check_ignore_header_file_path _headerFile _headerIsIgnoredVar) - if (NOT EXISTS "${_headerFile}") - set (${_headerIsIgnoredVar} TRUE) - elseif (IS_DIRECTORY "${_headerFile}") - set (${_headerIsIgnoredVar} TRUE) - elseif ("${_headerFile}" MATCHES "\\.\\.|[_-]fixed" AND "${_headerFile}" MATCHES "\\.h$") - # heuristic: ignore C headers with embedded parent directory references or "-fixed" or "_fixed" in path - # these often stem from using GCC #include_next tricks, which may break the precompiled header compilation - # with the error message "error: no include path in which to search for header.h" - set (${_headerIsIgnoredVar} TRUE) - else() - set (${_headerIsIgnoredVar} FALSE) - endif() -endmacro() - -macro (cotire_check_ignore_header_file_ext _headerFile _ignoreExtensionsVar _headerIsIgnoredVar) - # check header file extension - cotire_get_source_file_extension("${_headerFile}" _headerFileExt) - set (${_headerIsIgnoredVar} FALSE) - if (_headerFileExt) - list (FIND ${_ignoreExtensionsVar} "${_headerFileExt}" _index) - if (_index GREATER -1) - set (${_headerIsIgnoredVar} TRUE) - endif() - endif() -endmacro() - -macro (cotire_parse_line _line _headerFileVar _headerDepthVar) - if (MSVC) - # cl.exe /showIncludes output looks different depending on the language pack used, e.g.: - # English: "Note: including file: C:\directory\file" - # German: "Hinweis: Einlesen der Datei: C:\directory\file" - # We use a very general regular expression, relying on the presence of the : characters - if (_line MATCHES ":( +)([^:]+:[^:]+)$") - # Visual Studio compiler output - string (LENGTH "${CMAKE_MATCH_1}" ${_headerDepthVar}) - get_filename_component(${_headerFileVar} "${CMAKE_MATCH_2}" ABSOLUTE) - else() - set (${_headerFileVar} "") - set (${_headerDepthVar} 0) - endif() - else() - if (_line MATCHES "^(\\.+) (.*)$") - # GCC like output - string (LENGTH "${CMAKE_MATCH_1}" ${_headerDepthVar}) - if (IS_ABSOLUTE "${CMAKE_MATCH_2}") - set (${_headerFileVar} "${CMAKE_MATCH_2}") - else() - get_filename_component(${_headerFileVar} "${CMAKE_MATCH_2}" REALPATH) - endif() - else() - set (${_headerFileVar} "") - set (${_headerDepthVar} 0) - endif() - endif() -endmacro() - -function (cotire_parse_includes _language _scanOutput _ignoredIncudeDirs _honoredIncudeDirs _ignoredExtensions _selectedIncludesVar _unparsedLinesVar) - if (WIN32) - # prevent CMake macro invocation errors due to backslash characters in Windows paths - string (REPLACE "\\" "/" _scanOutput "${_scanOutput}") - endif() - # canonize slashes - string (REPLACE "//" "/" _scanOutput "${_scanOutput}") - # prevent semicolon from being interpreted as a line separator - string (REPLACE ";" "\\;" _scanOutput "${_scanOutput}") - # then separate lines - string (REGEX REPLACE "\n" ";" _scanOutput "${_scanOutput}") - list (LENGTH _scanOutput _len) - # remove duplicate lines to speed up parsing - list (REMOVE_DUPLICATES _scanOutput) - list (LENGTH _scanOutput _uniqueLen) - if (COTIRE_VERBOSE OR COTIRE_DEBUG) - message (STATUS "Scanning ${_uniqueLen} unique lines of ${_len} for includes") - if (_ignoredExtensions) - message (STATUS "Ignored extensions: ${_ignoredExtensions}") - endif() - if (_ignoredIncudeDirs) - message (STATUS "Ignored paths: ${_ignoredIncudeDirs}") - endif() - if (_honoredIncudeDirs) - message (STATUS "Included paths: ${_honoredIncudeDirs}") - endif() - endif() - set (_sourceFiles ${ARGN}) - set (_selectedIncludes "") - set (_unparsedLines "") - # stack keeps track of inside/outside project status of processed header files - set (_headerIsInsideStack "") - foreach (_line IN LISTS _scanOutput) - if (_line) - cotire_parse_line("${_line}" _headerFile _headerDepth) - if (_headerFile) - cotire_check_header_file_location("${_headerFile}" "${_ignoredIncudeDirs}" "${_honoredIncudeDirs}" _headerIsInside) - if (COTIRE_DEBUG) - message (STATUS "${_headerDepth}: ${_headerFile} ${_headerIsInside}") - endif() - # update stack - list (LENGTH _headerIsInsideStack _stackLen) - if (_headerDepth GREATER _stackLen) - math (EXPR _stackLen "${_stackLen} + 1") - foreach (_index RANGE ${_stackLen} ${_headerDepth}) - list (APPEND _headerIsInsideStack ${_headerIsInside}) - endforeach() - else() - foreach (_index RANGE ${_headerDepth} ${_stackLen}) - list (REMOVE_AT _headerIsInsideStack -1) - endforeach() - list (APPEND _headerIsInsideStack ${_headerIsInside}) - endif() - if (COTIRE_DEBUG) - message (STATUS "${_headerIsInsideStack}") - endif() - # header is a candidate if it is outside project - if (NOT _headerIsInside) - # get parent header file's inside/outside status - if (_headerDepth GREATER 1) - math (EXPR _index "${_headerDepth} - 2") - list (GET _headerIsInsideStack ${_index} _parentHeaderIsInside) - else() - set (_parentHeaderIsInside TRUE) - endif() - # select header file if parent header file is inside project - # (e.g., a project header file that includes a standard header file) - if (_parentHeaderIsInside) - cotire_check_ignore_header_file_path("${_headerFile}" _headerIsIgnored) - if (NOT _headerIsIgnored) - cotire_check_ignore_header_file_ext("${_headerFile}" _ignoredExtensions _headerIsIgnored) - if (NOT _headerIsIgnored) - list (APPEND _selectedIncludes "${_headerFile}") - else() - # fix header's inside status on stack, it is ignored by extension now - list (REMOVE_AT _headerIsInsideStack -1) - list (APPEND _headerIsInsideStack TRUE) - endif() - endif() - if (COTIRE_DEBUG) - message (STATUS "${_headerFile} ${_ignoredExtensions} ${_headerIsIgnored}") - endif() - endif() - endif() - else() - if (MSVC) - # for cl.exe do not keep unparsed lines which solely consist of a source file name - string (FIND "${_sourceFiles}" "${_line}" _index) - if (_index LESS 0) - list (APPEND _unparsedLines "${_line}") - endif() - else() - list (APPEND _unparsedLines "${_line}") - endif() - endif() - endif() - endforeach() - list (REMOVE_DUPLICATES _selectedIncludes) - set (${_selectedIncludesVar} ${_selectedIncludes} PARENT_SCOPE) - set (${_unparsedLinesVar} ${_unparsedLines} PARENT_SCOPE) -endfunction() - -function (cotire_scan_includes _includesVar) - set(_options "") - set(_oneValueArgs COMPILER_ID COMPILER_EXECUTABLE COMPILER_VERSION INCLUDE_SYSTEM_FLAG LANGUAGE UNPARSED_LINES) - set(_multiValueArgs COMPILE_DEFINITIONS COMPILE_FLAGS INCLUDE_DIRECTORIES SYSTEM_INCLUDE_DIRECTORIES IGNORE_PATH INCLUDE_PATH IGNORE_EXTENSIONS) - cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) - set (_sourceFiles ${_option_UNPARSED_ARGUMENTS}) - if (NOT _option_LANGUAGE) - set (_option_LANGUAGE "CXX") - endif() - if (NOT _option_COMPILER_ID) - set (_option_COMPILER_ID "${CMAKE_${_option_LANGUAGE}_ID}") - endif() - set (_cmd "${_option_COMPILER_EXECUTABLE}" ${_option_COMPILER_ARG1}) - cotire_init_compile_cmd(_cmd "${_option_LANGUAGE}" "${_option_COMPILER_EXECUTABLE}" "${_option_COMPILER_ARG1}") - cotire_add_definitions_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_COMPILE_DEFINITIONS}) - cotire_add_compile_flags_to_cmd(_cmd ${_option_COMPILE_FLAGS}) - cotire_add_includes_to_cmd(_cmd "${_option_LANGUAGE}" "${_option_INCLUDE_SYSTEM_FLAG}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES) - cotire_add_frameworks_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_INCLUDE_DIRECTORIES}) - cotire_add_makedep_flags("${_option_LANGUAGE}" "${_option_COMPILER_ID}" "${_option_COMPILER_VERSION}" _cmd) - # only consider existing source files for scanning - set (_existingSourceFiles "") - foreach (_sourceFile ${_sourceFiles}) - if (EXISTS "${_sourceFile}") - list (APPEND _existingSourceFiles "${_sourceFile}") - endif() - endforeach() - if (NOT _existingSourceFiles) - set (${_includesVar} "" PARENT_SCOPE) - return() - endif() - list (APPEND _cmd ${_existingSourceFiles}) - if (COTIRE_VERBOSE) - message (STATUS "execute_process: ${_cmd}") - endif() - if (_option_COMPILER_ID MATCHES "MSVC") - if (COTIRE_DEBUG) - message (STATUS "clearing VS_UNICODE_OUTPUT") - endif() - # cl.exe messes with the output streams unless the environment variable VS_UNICODE_OUTPUT is cleared - unset (ENV{VS_UNICODE_OUTPUT}) - endif() - execute_process( - COMMAND ${_cmd} WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - RESULT_VARIABLE _result OUTPUT_QUIET ERROR_VARIABLE _output) - if (_result) - message (STATUS "Result ${_result} scanning includes of ${_existingSourceFiles}.") - endif() - cotire_parse_includes( - "${_option_LANGUAGE}" "${_output}" - "${_option_IGNORE_PATH}" "${_option_INCLUDE_PATH}" - "${_option_IGNORE_EXTENSIONS}" - _includes _unparsedLines - ${_sourceFiles}) - set (${_includesVar} ${_includes} PARENT_SCOPE) - if (_option_UNPARSED_LINES) - set (${_option_UNPARSED_LINES} ${_unparsedLines} PARENT_SCOPE) - endif() -endfunction() - -macro (cotire_append_undefs _contentsVar) - set (_undefs ${ARGN}) - if (_undefs) - list (REMOVE_DUPLICATES _undefs) - foreach (_definition ${_undefs}) - list (APPEND ${_contentsVar} "#undef ${_definition}") - endforeach() - endif() -endmacro() - -macro (cotire_comment_str _language _commentText _commentVar) - if ("${_language}" STREQUAL "CMAKE") - set (${_commentVar} "# ${_commentText}") - else() - set (${_commentVar} "/* ${_commentText} */") - endif() -endmacro() - -function (cotire_write_file _language _file _contents _force) - get_filename_component(_moduleName "${COTIRE_CMAKE_MODULE_FILE}" NAME) - cotire_comment_str("${_language}" "${_moduleName} ${COTIRE_CMAKE_MODULE_VERSION} generated file" _header1) - cotire_comment_str("${_language}" "${_file}" _header2) - set (_contents "${_header1}\n${_header2}\n${_contents}") - if (COTIRE_DEBUG) - message (STATUS "${_contents}") - endif() - if (_force OR NOT EXISTS "${_file}") - file (WRITE "${_file}" "${_contents}") - else() - file (READ "${_file}" _oldContents) - if (NOT "${_oldContents}" STREQUAL "${_contents}") - file (WRITE "${_file}" "${_contents}") - else() - if (COTIRE_DEBUG) - message (STATUS "${_file} unchanged") - endif() - endif() - endif() -endfunction() - -function (cotire_generate_unity_source _unityFile) - set(_options "") - set(_oneValueArgs LANGUAGE) - set(_multiValueArgs - DEPENDS SOURCES_COMPILE_DEFINITIONS - PRE_UNDEFS SOURCES_PRE_UNDEFS POST_UNDEFS SOURCES_POST_UNDEFS PROLOGUE EPILOGUE) - cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) - if (_option_DEPENDS) - cotire_check_file_up_to_date(_unityFileIsUpToDate "${_unityFile}" ${_option_DEPENDS}) - if (_unityFileIsUpToDate) - return() - endif() - endif() - set (_sourceFiles ${_option_UNPARSED_ARGUMENTS}) - if (NOT _option_PRE_UNDEFS) - set (_option_PRE_UNDEFS "") - endif() - if (NOT _option_SOURCES_PRE_UNDEFS) - set (_option_SOURCES_PRE_UNDEFS "") - endif() - if (NOT _option_POST_UNDEFS) - set (_option_POST_UNDEFS "") - endif() - if (NOT _option_SOURCES_POST_UNDEFS) - set (_option_SOURCES_POST_UNDEFS "") - endif() - set (_contents "") - if (_option_PROLOGUE) - list (APPEND _contents ${_option_PROLOGUE}) - endif() - if (_option_LANGUAGE AND _sourceFiles) - if ("${_option_LANGUAGE}" STREQUAL "CXX") - list (APPEND _contents "#ifdef __cplusplus") - elseif ("${_option_LANGUAGE}" STREQUAL "C") - list (APPEND _contents "#ifndef __cplusplus") - endif() - endif() - set (_compileUndefinitions "") - foreach (_sourceFile ${_sourceFiles}) - cotire_get_source_compile_definitions( - "${_option_CONFIGURATION}" "${_option_LANGUAGE}" "${_sourceFile}" _compileDefinitions - ${_option_SOURCES_COMPILE_DEFINITIONS}) - cotire_get_source_undefs("${_sourceFile}" COTIRE_UNITY_SOURCE_PRE_UNDEFS _sourcePreUndefs ${_option_SOURCES_PRE_UNDEFS}) - cotire_get_source_undefs("${_sourceFile}" COTIRE_UNITY_SOURCE_POST_UNDEFS _sourcePostUndefs ${_option_SOURCES_POST_UNDEFS}) - if (_option_PRE_UNDEFS) - list (APPEND _compileUndefinitions ${_option_PRE_UNDEFS}) - endif() - if (_sourcePreUndefs) - list (APPEND _compileUndefinitions ${_sourcePreUndefs}) - endif() - if (_compileUndefinitions) - cotire_append_undefs(_contents ${_compileUndefinitions}) - set (_compileUndefinitions "") - endif() - if (_sourcePostUndefs) - list (APPEND _compileUndefinitions ${_sourcePostUndefs}) - endif() - if (_option_POST_UNDEFS) - list (APPEND _compileUndefinitions ${_option_POST_UNDEFS}) - endif() - foreach (_definition ${_compileDefinitions}) - if (_definition MATCHES "^([a-zA-Z0-9_]+)=(.+)$") - list (APPEND _contents "#define ${CMAKE_MATCH_1} ${CMAKE_MATCH_2}") - list (INSERT _compileUndefinitions 0 "${CMAKE_MATCH_1}") - else() - list (APPEND _contents "#define ${_definition}") - list (INSERT _compileUndefinitions 0 "${_definition}") - endif() - endforeach() - get_filename_component(_sourceFile "${_sourceFile}" ABSOLUTE) - if (WIN32) - file (TO_NATIVE_PATH "${_sourceFile}" _sourceFile) - endif() - list (APPEND _contents "#include \"${_sourceFile}\"") - endforeach() - if (_compileUndefinitions) - cotire_append_undefs(_contents ${_compileUndefinitions}) - set (_compileUndefinitions "") - endif() - if (_option_LANGUAGE AND _sourceFiles) - list (APPEND _contents "#endif") - endif() - if (_option_EPILOGUE) - list (APPEND _contents ${_option_EPILOGUE}) - endif() - list (APPEND _contents "") - string (REPLACE ";" "\n" _contents "${_contents}") - if (COTIRE_VERBOSE) - message ("${_contents}") - endif() - cotire_write_file("${_option_LANGUAGE}" "${_unityFile}" "${_contents}" TRUE) -endfunction() - -function (cotire_generate_prefix_header _prefixFile) - set(_options "") - set(_oneValueArgs LANGUAGE COMPILER_EXECUTABLE COMPILER_ID COMPILER_VERSION INCLUDE_SYSTEM_FLAG) - set(_multiValueArgs DEPENDS COMPILE_DEFINITIONS COMPILE_FLAGS - INCLUDE_DIRECTORIES SYSTEM_INCLUDE_DIRECTORIES IGNORE_PATH INCLUDE_PATH IGNORE_EXTENSIONS) - cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) - if (_option_DEPENDS) - cotire_check_file_up_to_date(_prefixFileIsUpToDate "${_prefixFile}" ${_option_DEPENDS}) - if (_prefixFileIsUpToDate) - set (_unparsedLinesFile "${_prefixFile}.log") - file (WRITE "${_unparsedLinesFile}" "") - return() - endif() - endif() - set (_prologue "") - set (_epilogue "") - if (_option_COMPILER_ID MATCHES "Clang") - set (_prologue "#pragma clang system_header") - elseif (_option_COMPILER_ID MATCHES "GNU") - set (_prologue "#pragma GCC system_header") - elseif (_option_COMPILER_ID MATCHES "MSVC") - set (_prologue "#pragma warning(push, 0)") - set (_epilogue "#pragma warning(pop)") - elseif (_option_COMPILER_ID MATCHES "Intel") - # Intel compiler requires hdrstop pragma to stop generating PCH file - set (_epilogue "#pragma hdrstop") - endif() - set (_sourceFiles ${_option_UNPARSED_ARGUMENTS}) - cotire_scan_includes(_selectedHeaders ${_sourceFiles} - LANGUAGE "${_option_LANGUAGE}" - COMPILER_EXECUTABLE "${_option_COMPILER_EXECUTABLE}" - COMPILER_ID "${_option_COMPILER_ID}" - COMPILER_VERSION "${_option_COMPILER_VERSION}" - COMPILE_DEFINITIONS ${_option_COMPILE_DEFINITIONS} - COMPILE_FLAGS ${_option_COMPILE_FLAGS} - INCLUDE_DIRECTORIES ${_option_INCLUDE_DIRECTORIES} - INCLUDE_SYSTEM_FLAG ${_option_INCLUDE_SYSTEM_FLAG} - SYSTEM_INCLUDE_DIRECTORIES ${_option_SYSTEM_INCLUDE_DIRECTORIES} - IGNORE_PATH ${_option_IGNORE_PATH} - INCLUDE_PATH ${_option_INCLUDE_PATH} - IGNORE_EXTENSIONS ${_option_IGNORE_EXTENSIONS} - UNPARSED_LINES _unparsedLines) - cotire_generate_unity_source("${_prefixFile}" - PROLOGUE ${_prologue} EPILOGUE ${_epilogue} LANGUAGE "${_option_LANGUAGE}" ${_selectedHeaders}) - set (_unparsedLinesFile "${_prefixFile}.log") - if (_unparsedLines) - if (COTIRE_VERBOSE OR NOT _selectedHeaders) - list (LENGTH _unparsedLines _skippedLineCount) - file (RELATIVE_PATH _unparsedLinesFileRelPath "${CMAKE_BINARY_DIR}" "${_unparsedLinesFile}") - message (STATUS "${_skippedLineCount} line(s) skipped, see ${_unparsedLinesFileRelPath}") - endif() - string (REPLACE ";" "\n" _unparsedLines "${_unparsedLines}") - endif() - file (WRITE "${_unparsedLinesFile}" "${_unparsedLines}") -endfunction() - -function (cotire_add_makedep_flags _language _compilerID _compilerVersion _flagsVar) - set (_flags ${${_flagsVar}}) - if (_compilerID MATCHES "MSVC") - # cl.exe options used - # /nologo suppresses display of sign-on banner - # /TC treat all files named on the command line as C source files - # /TP treat all files named on the command line as C++ source files - # /EP preprocess to stdout without #line directives - # /showIncludes list include files - set (_sourceFileTypeC "/TC") - set (_sourceFileTypeCXX "/TP") - if (_flags) - # append to list - list (APPEND _flags /nologo "${_sourceFileType${_language}}" /EP /showIncludes) - else() - # return as a flag string - set (_flags "${_sourceFileType${_language}} /EP /showIncludes") - endif() - elseif (_compilerID MATCHES "GNU") - # GCC options used - # -H print the name of each header file used - # -E invoke preprocessor - # -fdirectives-only do not expand macros, requires GCC >= 4.3 - if (_flags) - # append to list - list (APPEND _flags -H -E) - if (NOT "${_compilerVersion}" VERSION_LESS "4.3.0") - list (APPEND _flags "-fdirectives-only") - endif() - else() - # return as a flag string - set (_flags "-H -E") - if (NOT "${_compilerVersion}" VERSION_LESS "4.3.0") - set (_flags "${_flags} -fdirectives-only") - endif() - endif() - elseif (_compilerID MATCHES "Clang") - # Clang options used - # -H print the name of each header file used - # -E invoke preprocessor - if (_flags) - # append to list - list (APPEND _flags -H -E) - else() - # return as a flag string - set (_flags "-H -E") - endif() - elseif (_compilerID MATCHES "Intel") - if (WIN32) - # Windows Intel options used - # /nologo do not display compiler version information - # /QH display the include file order - # /EP preprocess to stdout, omitting #line directives - # /TC process all source or unrecognized file types as C source files - # /TP process all source or unrecognized file types as C++ source files - set (_sourceFileTypeC "/TC") - set (_sourceFileTypeCXX "/TP") - if (_flags) - # append to list - list (APPEND _flags /nologo "${_sourceFileType${_language}}" /EP /QH) - else() - # return as a flag string - set (_flags "${_sourceFileType${_language}} /EP /QH") - endif() - else() - # Linux / Mac OS X Intel options used - # -H print the name of each header file used - # -EP preprocess to stdout, omitting #line directives - # -Kc++ process all source or unrecognized file types as C++ source files - if (_flags) - # append to list - if ("${_language}" STREQUAL "CXX") - list (APPEND _flags -Kc++) - endif() - list (APPEND _flags -H -EP) - else() - # return as a flag string - if ("${_language}" STREQUAL "CXX") - set (_flags "-Kc++ ") - endif() - set (_flags "${_flags}-H -EP") - endif() - endif() - else() - message (FATAL_ERROR "cotire: unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.") - endif() - set (${_flagsVar} ${_flags} PARENT_SCOPE) -endfunction() - -function (cotire_add_pch_compilation_flags _language _compilerID _compilerVersion _prefixFile _pchFile _hostFile _flagsVar) - set (_flags ${${_flagsVar}}) - if (_compilerID MATCHES "MSVC") - file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative) - file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative) - file (TO_NATIVE_PATH "${_hostFile}" _hostFileNative) - # cl.exe options used - # /Yc creates a precompiled header file - # /Fp specifies precompiled header binary file name - # /FI forces inclusion of file - # /TC treat all files named on the command line as C source files - # /TP treat all files named on the command line as C++ source files - # /Zs syntax check only - set (_sourceFileTypeC "/TC") - set (_sourceFileTypeCXX "/TP") - if (_flags) - # append to list - list (APPEND _flags /nologo "${_sourceFileType${_language}}" - "/Yc${_prefixFileNative}" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}" /Zs "${_hostFileNative}") - else() - # return as a flag string - set (_flags "/Yc\"${_prefixFileNative}\" /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"") - endif() - elseif (_compilerID MATCHES "GNU|Clang") - # GCC / Clang options used - # -x specify the source language - # -c compile but do not link - # -o place output in file - # note that we cannot use -w to suppress all warnings upon pre-compiling, because turning off a warning may - # alter compile flags as a side effect (e.g., -Wwrite-string implies -fconst-strings) - set (_xLanguage_C "c-header") - set (_xLanguage_CXX "c++-header") - if (_flags) - # append to list - list (APPEND _flags "-x" "${_xLanguage_${_language}}" "-c" "${_prefixFile}" -o "${_pchFile}") - else() - # return as a flag string - set (_flags "-x ${_xLanguage_${_language}} -c \"${_prefixFile}\" -o \"${_pchFile}\"") - endif() - elseif (_compilerID MATCHES "Intel") - if (WIN32) - file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative) - file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative) - file (TO_NATIVE_PATH "${_hostFile}" _hostFileNative) - # Windows Intel options used - # /nologo do not display compiler version information - # /Yc create a precompiled header (PCH) file - # /Fp specify a path or file name for precompiled header files - # /FI tells the preprocessor to include a specified file name as the header file - # /TC process all source or unrecognized file types as C source files - # /TP process all source or unrecognized file types as C++ source files - # /Zs syntax check only - # /Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2) - set (_sourceFileTypeC "/TC") - set (_sourceFileTypeCXX "/TP") - if (_flags) - # append to list - list (APPEND _flags /nologo "${_sourceFileType${_language}}" - "/Yc" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}" /Zs "${_hostFileNative}") - if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") - list (APPEND _flags "/Wpch-messages") - endif() - else() - # return as a flag string - set (_flags "/Yc /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"") - if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") - set (_flags "${_flags} /Wpch-messages") - endif() - endif() - else() - # Linux / Mac OS X Intel options used - # -pch-dir location for precompiled header files - # -pch-create name of the precompiled header (PCH) to create - # -Kc++ process all source or unrecognized file types as C++ source files - # -fsyntax-only check only for correct syntax - # -Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2) - get_filename_component(_pchDir "${_pchFile}" PATH) - get_filename_component(_pchName "${_pchFile}" NAME) - set (_xLanguage_C "c-header") - set (_xLanguage_CXX "c++-header") - if (_flags) - # append to list - if ("${_language}" STREQUAL "CXX") - list (APPEND _flags -Kc++) - endif() - list (APPEND _flags "-include" "${_prefixFile}" "-pch-dir" "${_pchDir}" "-pch-create" "${_pchName}" "-fsyntax-only" "${_hostFile}") - if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") - list (APPEND _flags "-Wpch-messages") - endif() - else() - # return as a flag string - set (_flags "-include \"${_prefixFile}\" -pch-dir \"${_pchDir}\" -pch-create \"${_pchName}\"") - if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") - set (_flags "${_flags} -Wpch-messages") - endif() - endif() - endif() - else() - message (FATAL_ERROR "cotire: unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.") - endif() - set (${_flagsVar} ${_flags} PARENT_SCOPE) -endfunction() - -function (cotire_add_prefix_pch_inclusion_flags _language _compilerID _compilerVersion _prefixFile _pchFile _flagsVar) - set (_flags ${${_flagsVar}}) - if (_compilerID MATCHES "MSVC") - file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative) - # cl.exe options used - # /Yu uses a precompiled header file during build - # /Fp specifies precompiled header binary file name - # /FI forces inclusion of file - if (_pchFile) - file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative) - if (_flags) - # append to list - list (APPEND _flags "/Yu${_prefixFileNative}" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}") - else() - # return as a flag string - set (_flags "/Yu\"${_prefixFileNative}\" /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"") - endif() - else() - # no precompiled header, force inclusion of prefix header - if (_flags) - # append to list - list (APPEND _flags "/FI${_prefixFileNative}") - else() - # return as a flag string - set (_flags "/FI\"${_prefixFileNative}\"") - endif() - endif() - elseif (_compilerID MATCHES "GNU") - # GCC options used - # -include process include file as the first line of the primary source file - # -Winvalid-pch warns if precompiled header is found but cannot be used - # note: ccache requires the -include flag to be used in order to process precompiled header correctly - if (_flags) - # append to list - list (APPEND _flags "-Winvalid-pch" "-include" "${_prefixFile}") - else() - # return as a flag string - set (_flags "-Winvalid-pch -include \"${_prefixFile}\"") - endif() - elseif (_compilerID MATCHES "Clang") - # Clang options used - # -include process include file as the first line of the primary source file - # -include-pch include precompiled header file - # -Qunused-arguments don't emit warning for unused driver arguments - # note: ccache requires the -include flag to be used in order to process precompiled header correctly - if (_flags) - # append to list - list (APPEND _flags "-Qunused-arguments" "-include" "${_prefixFile}") - else() - # return as a flag string - set (_flags "-Qunused-arguments -include \"${_prefixFile}\"") - endif() - elseif (_compilerID MATCHES "Intel") - if (WIN32) - file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative) - # Windows Intel options used - # /Yu use a precompiled header (PCH) file - # /Fp specify a path or file name for precompiled header files - # /FI tells the preprocessor to include a specified file name as the header file - # /Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2) - if (_pchFile) - file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative) - if (_flags) - # append to list - list (APPEND _flags "/Yu" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}") - if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") - list (APPEND _flags "/Wpch-messages") - endif() - else() - # return as a flag string - set (_flags "/Yu /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"") - if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") - set (_flags "${_flags} /Wpch-messages") - endif() - endif() - else() - # no precompiled header, force inclusion of prefix header - if (_flags) - # append to list - list (APPEND _flags "/FI${_prefixFileNative}") - else() - # return as a flag string - set (_flags "/FI\"${_prefixFileNative}\"") - endif() - endif() - else() - # Linux / Mac OS X Intel options used - # -pch-dir location for precompiled header files - # -pch-use name of the precompiled header (PCH) to use - # -include process include file as the first line of the primary source file - # -Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2) - if (_pchFile) - get_filename_component(_pchDir "${_pchFile}" PATH) - get_filename_component(_pchName "${_pchFile}" NAME) - if (_flags) - # append to list - list (APPEND _flags "-include" "${_prefixFile}" "-pch-dir" "${_pchDir}" "-pch-use" "${_pchName}") - if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") - list (APPEND _flags "-Wpch-messages") - endif() - else() - # return as a flag string - set (_flags "-include \"${_prefixFile}\" -pch-dir \"${_pchDir}\" -pch-use \"${_pchName}\"") - if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") - set (_flags "${_flags} -Wpch-messages") - endif() - endif() - else() - # no precompiled header, force inclusion of prefix header - if (_flags) - # append to list - list (APPEND _flags "-include" "${_prefixFile}") - else() - # return as a flag string - set (_flags "-include \"${_prefixFile}\"") - endif() - endif() - endif() - else() - message (FATAL_ERROR "cotire: unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.") - endif() - set (${_flagsVar} ${_flags} PARENT_SCOPE) -endfunction() - -function (cotire_precompile_prefix_header _prefixFile _pchFile _hostFile) - set(_options "") - set(_oneValueArgs COMPILER_EXECUTABLE COMPILER_ID COMPILER_VERSION INCLUDE_SYSTEM_FLAG LANGUAGE) - set(_multiValueArgs COMPILE_DEFINITIONS COMPILE_FLAGS INCLUDE_DIRECTORIES SYSTEM_INCLUDE_DIRECTORIES SYS) - cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) - if (NOT _option_LANGUAGE) - set (_option_LANGUAGE "CXX") - endif() - if (NOT _option_COMPILER_ID) - set (_option_COMPILER_ID "${CMAKE_${_option_LANGUAGE}_ID}") - endif() - cotire_init_compile_cmd(_cmd "${_option_LANGUAGE}" "${_option_COMPILER_EXECUTABLE}" "${_option_COMPILER_ARG1}") - cotire_add_definitions_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_COMPILE_DEFINITIONS}) - cotire_add_compile_flags_to_cmd(_cmd ${_option_COMPILE_FLAGS}) - cotire_add_includes_to_cmd(_cmd "${_option_LANGUAGE}" "${_option_INCLUDE_SYSTEM_FLAG}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES) - cotire_add_frameworks_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_INCLUDE_DIRECTORIES}) - cotire_add_pch_compilation_flags( - "${_option_LANGUAGE}" "${_option_COMPILER_ID}" "${_option_COMPILER_VERSION}" - "${_prefixFile}" "${_pchFile}" "${_hostFile}" _cmd) - if (COTIRE_VERBOSE) - message (STATUS "execute_process: ${_cmd}") - endif() - if (_option_COMPILER_ID MATCHES "MSVC") - if (COTIRE_DEBUG) - message (STATUS "clearing VS_UNICODE_OUTPUT") - endif() - # cl.exe messes with the output streams unless the environment variable VS_UNICODE_OUTPUT is cleared - unset (ENV{VS_UNICODE_OUTPUT}) - endif() - execute_process( - COMMAND ${_cmd} - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - RESULT_VARIABLE _result) - if (_result) - message (FATAL_ERROR "cotire: error ${_result} precompiling ${_prefixFile}.") - endif() -endfunction() - -function (cotire_check_precompiled_header_support _language _targetSourceDir _target _msgVar) - set (_unsupportedCompiler - "Precompiled headers not supported for ${_language} compiler ${CMAKE_${_language}_COMPILER_ID}") - if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC") - # supported since Visual Studio C++ 6.0 - # and CMake does not support an earlier version - set (${_msgVar} "" PARENT_SCOPE) - elseif (CMAKE_${_language}_COMPILER_ID MATCHES "GNU") - # GCC PCH support requires version >= 3.4 - cotire_determine_compiler_version("${_language}" COTIRE_${_language}_COMPILER) - if ("${COTIRE_${_language}_COMPILER_VERSION}" MATCHES ".+" AND - "${COTIRE_${_language}_COMPILER_VERSION}" VERSION_LESS "3.4.0") - set (${_msgVar} "${_unsupportedCompiler} version ${COTIRE_${_language}_COMPILER_VERSION}." PARENT_SCOPE) - else() - set (${_msgVar} "" PARENT_SCOPE) - endif() - elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Clang") - # all Clang versions have PCH support - set (${_msgVar} "" PARENT_SCOPE) - elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Intel") - # Intel PCH support requires version >= 8.0.0 - cotire_determine_compiler_version("${_language}" COTIRE_${_language}_COMPILER) - if ("${COTIRE_${_language}_COMPILER_VERSION}" MATCHES ".+" AND - "${COTIRE_${_language}_COMPILER_VERSION}" VERSION_LESS "8.0.0") - set (${_msgVar} "${_unsupportedCompiler} version ${COTIRE_${_language}_COMPILER_VERSION}." PARENT_SCOPE) - else() - set (${_msgVar} "" PARENT_SCOPE) - endif() - else() - set (${_msgVar} "${_unsupportedCompiler}." PARENT_SCOPE) - endif() - if (CMAKE_${_language}_COMPILER MATCHES "ccache") - if (NOT "$ENV{CCACHE_SLOPPINESS}" MATCHES "time_macros") - set (${_msgVar} - "ccache requires the environment variable CCACHE_SLOPPINESS to be set to time_macros." - PARENT_SCOPE) - endif() - endif() - if (APPLE) - # PCH compilation not supported by GCC / Clang for multi-architecture builds (e.g., i386, x86_64) - if (CMAKE_CONFIGURATION_TYPES) - set (_configs ${CMAKE_CONFIGURATION_TYPES}) - elseif (CMAKE_BUILD_TYPE) - set (_configs ${CMAKE_BUILD_TYPE}) - else() - set (_configs "None") - endif() - foreach (_config ${_configs}) - set (_targetFlags "") - cotire_get_target_compile_flags("${_config}" "${_language}" "${_targetSourceDir}" "${_target}" _targetFlags) - cotire_filter_compile_flags("${_language}" "arch" _architectures _ignore ${_targetFlags}) - list (LENGTH _architectures _numberOfArchitectures) - if (_numberOfArchitectures GREATER 1) - string (REPLACE ";" ", " _architectureStr "${_architectures}") - set (${_msgVar} - "Precompiled headers not supported on Darwin for multi-architecture builds (${_architectureStr})." - PARENT_SCOPE) - break() - endif() - endforeach() - endif() -endfunction() - -macro (cotire_get_intermediate_dir _cotireDir) - get_filename_component(${_cotireDir} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${COTIRE_INTDIR}" ABSOLUTE) -endmacro() - -macro (cotire_setup_file_extension_variables) - set (_unityFileExt_C ".c") - set (_unityFileExt_CXX ".cxx") - set (_prefixFileExt_C ".h") - set (_prefixFileExt_CXX ".hxx") - set (_prefixSourceFileExt_C ".c") - set (_prefixSourceFileExt_CXX ".cxx") -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() - endif() - set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}") - cotire_get_intermediate_dir(_baseDir) - 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}") - endif() - set (_startIndex ${_index}) - endif() - math (EXPR _index "${_index} + 1") - endforeach() - list (LENGTH _sourceFiles _numberOfSources) - if (_startIndex EQUAL 0) - # 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}") - endif() - set (${_unityFilesVar} ${_unityFiles} PARENT_SCOPE) - if (COTIRE_DEBUG) - message(STATUS "${_unityFiles}") - 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_prefix_header_to_source_file_path _language _prefixHeaderFile _prefixSourceFileVar) - cotire_setup_file_extension_variables() - if (NOT DEFINED _prefixSourceFileExt_${_language}) - set (${_prefixSourceFileVar} "" PARENT_SCOPE) - return() - endif() - string (REGEX REPLACE "${_prefixFileExt_${_language}}$" "${_prefixSourceFileExt_${_language}}" _prefixSourceFile "${_prefixHeaderFile}") - set (${_prefixSourceFileVar} "${_prefixSourceFile}" PARENT_SCOPE) -endfunction() - -function (cotire_make_prefix_file_name _language _target _prefixFileBaseNameVar _prefixFileNameVar) - cotire_setup_file_extension_variables() - if (NOT _language) - set (_prefixFileBaseName "${_target}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}") - set (_prefixFileName "${_prefixFileBaseName}${_prefixFileExt_C}") - elseif (DEFINED _prefixFileExt_${_language}) - set (_prefixFileBaseName "${_target}_${_language}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}") - set (_prefixFileName "${_prefixFileBaseName}${_prefixFileExt_${_language}}") - else() - set (_prefixFileBaseName "") - set (_prefixFileName "") - endif() - set (${_prefixFileBaseNameVar} "${_prefixFileBaseName}" PARENT_SCOPE) - set (${_prefixFileNameVar} "${_prefixFileName}" PARENT_SCOPE) -endfunction() - -function (cotire_make_prefix_file_path _language _target _prefixFileVar) - cotire_make_prefix_file_name("${_language}" "${_target}" _prefixFileBaseName _prefixFileName) - set (${_prefixFileVar} "" PARENT_SCOPE) - if (_prefixFileName) - if (NOT _language) - set (_language "C") - endif() - if (MSVC OR CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang|Intel") - cotire_get_intermediate_dir(_baseDir) - set (${_prefixFileVar} "${_baseDir}/${_prefixFileName}" PARENT_SCOPE) - endif() - endif() -endfunction() - -function (cotire_make_pch_file_path _language _targetSourceDir _target _pchFileVar) - cotire_make_prefix_file_name("${_language}" "${_target}" _prefixFileBaseName _prefixFileName) - set (${_pchFileVar} "" PARENT_SCOPE) - if (_prefixFileBaseName AND _prefixFileName) - cotire_check_precompiled_header_support("${_language}" "${_targetSourceDir}" "${_target}" _msg) - if (NOT _msg) - if (XCODE) - # For Xcode, we completely hand off the compilation of the prefix header to the IDE - return() - endif() - cotire_get_intermediate_dir(_baseDir) - if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC") - # MSVC uses the extension .pch added to the prefix header base name - set (${_pchFileVar} "${_baseDir}/${_prefixFileBaseName}.pch" PARENT_SCOPE) - elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Clang") - # Clang looks for a precompiled header corresponding to the prefix header with the extension .pch appended - set (${_pchFileVar} "${_baseDir}/${_prefixFileName}.pch" PARENT_SCOPE) - elseif (CMAKE_${_language}_COMPILER_ID MATCHES "GNU") - # GCC looks for a precompiled header corresponding to the prefix header with the extension .gch appended - set (${_pchFileVar} "${_baseDir}/${_prefixFileName}.gch" PARENT_SCOPE) - elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Intel") - # Intel uses the extension .pchi added to the prefix header base name - set (${_pchFileVar} "${_baseDir}/${_prefixFileBaseName}.pchi" PARENT_SCOPE) - endif() - endif() - endif() -endfunction() - -function (cotire_select_unity_source_files _unityFile _sourcesVar) - set (_sourceFiles ${ARGN}) - if (_sourceFiles AND "${_unityFile}" MATCHES "${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}_([0-9]+)_([0-9]+)") - set (_startIndex ${CMAKE_MATCH_1}) - set (_endIndex ${CMAKE_MATCH_2}) - list (LENGTH _sourceFiles _numberOfSources) - if (NOT _startIndex LESS _numberOfSources) - math (EXPR _startIndex "${_numberOfSources} - 1") - endif() - if (NOT _endIndex LESS _numberOfSources) - math (EXPR _endIndex "${_numberOfSources} - 1") - endif() - set (_files "") - foreach (_index RANGE ${_startIndex} ${_endIndex}) - list (GET _sourceFiles ${_index} _file) - list (APPEND _files "${_file}") - endforeach() - else() - set (_files ${_sourceFiles}) - endif() - set (${_sourcesVar} ${_files} PARENT_SCOPE) -endfunction() - -function (cotire_get_unity_source_dependencies _language _target _dependencySourcesVar) - set (_dependencySources "") - # depend on target's generated source files - cotire_get_objects_with_property_on(_generatedSources GENERATED SOURCE ${ARGN}) - if (_generatedSources) - # but omit all generated source files that have the COTIRE_EXCLUDED property set to true - cotire_get_objects_with_property_on(_excludedGeneratedSources COTIRE_EXCLUDED SOURCE ${_generatedSources}) - if (_excludedGeneratedSources) - list (REMOVE_ITEM _generatedSources ${_excludedGeneratedSources}) - endif() - # and omit all generated source files that have the COTIRE_DEPENDENCY property set to false explicitly - cotire_get_objects_with_property_off(_excludedNonDependencySources COTIRE_DEPENDENCY SOURCE ${_generatedSources}) - if (_excludedNonDependencySources) - list (REMOVE_ITEM _generatedSources ${_excludedNonDependencySources}) - endif() - if (_generatedSources) - list (APPEND _dependencySources ${_generatedSources}) - endif() - endif() - if (COTIRE_DEBUG AND _dependencySources) - message (STATUS "${_language} ${_target} unity source depends on ${_dependencySources}") - endif() - set (${_dependencySourcesVar} ${_dependencySources} PARENT_SCOPE) -endfunction() - -function (cotire_get_prefix_header_dependencies _language _target _dependencySourcesVar) - # depend on target source files marked with custom COTIRE_DEPENDENCY property - set (_dependencySources "") - cotire_get_objects_with_property_on(_dependencySources COTIRE_DEPENDENCY SOURCE ${ARGN}) - if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang") - # GCC and clang raise a fatal error if a file is not found during preprocessing - # thus we depend on target's generated source files for prefix header generation - cotire_get_objects_with_property_on(_generatedSources GENERATED SOURCE ${ARGN}) - if (_generatedSources) - list (APPEND _dependencySources ${_generatedSources}) - endif() - endif() - if (COTIRE_DEBUG AND _dependencySources) - message (STATUS "${_language} ${_target} prefix header DEPENDS ${_dependencySources}") - endif() - set (${_dependencySourcesVar} ${_dependencySources} PARENT_SCOPE) -endfunction() - -function (cotire_generate_target_script _language _configurations _targetSourceDir _targetBinaryDir _target _targetScriptVar _targetConfigScriptVar) - set (COTIRE_TARGET_SOURCES ${ARGN}) - cotire_get_prefix_header_dependencies(${_language} ${_target} COTIRE_TARGET_PREFIX_DEPENDS ${COTIRE_TARGET_SOURCES}) - cotire_get_unity_source_dependencies(${_language} ${_target} COTIRE_TARGET_UNITY_DEPENDS ${COTIRE_TARGET_SOURCES}) - # set up variables to be configured - set (COTIRE_TARGET_LANGUAGE "${_language}") - cotire_determine_compiler_version("${COTIRE_TARGET_LANGUAGE}" COTIRE_${_language}_COMPILER) - get_target_property(COTIRE_TARGET_IGNORE_PATH ${_target} COTIRE_PREFIX_HEADER_IGNORE_PATH) - cotire_add_sys_root_paths(COTIRE_TARGET_IGNORE_PATH) - get_target_property(COTIRE_TARGET_INCLUDE_PATH ${_target} COTIRE_PREFIX_HEADER_INCLUDE_PATH) - cotire_add_sys_root_paths(COTIRE_TARGET_INCLUDE_PATH) - get_target_property(COTIRE_TARGET_PRE_UNDEFS ${_target} COTIRE_UNITY_SOURCE_PRE_UNDEFS) - get_target_property(COTIRE_TARGET_POST_UNDEFS ${_target} COTIRE_UNITY_SOURCE_POST_UNDEFS) - get_target_property(COTIRE_TARGET_MAXIMUM_NUMBER_OF_INCLUDES ${_target} COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES) - cotire_get_source_files_undefs(COTIRE_UNITY_SOURCE_PRE_UNDEFS COTIRE_TARGET_SOURCES_PRE_UNDEFS ${COTIRE_TARGET_SOURCES}) - cotire_get_source_files_undefs(COTIRE_UNITY_SOURCE_POST_UNDEFS COTIRE_TARGET_SOURCES_POST_UNDEFS ${COTIRE_TARGET_SOURCES}) - string (STRIP "${CMAKE_INCLUDE_SYSTEM_FLAG_${_language}}" COTIRE_INCLUDE_SYSTEM_FLAG) - set (COTIRE_TARGET_CONFIGURATION_TYPES "${_configurations}") - foreach (_config ${_configurations}) - string (TOUPPER "${_config}" _upperConfig) - cotire_get_target_include_directories( - "${_config}" "${_language}" "${_targetSourceDir}" "${_targetBinaryDir}" "${_target}" COTIRE_TARGET_INCLUDE_DIRECTORIES_${_upperConfig} COTIRE_TARGET_SYSTEM_INCLUDE_DIRECTORIES_${_upperConfig}) - cotire_get_target_compile_definitions( - "${_config}" "${_language}" "${_targetSourceDir}" "${_target}" COTIRE_TARGET_COMPILE_DEFINITIONS_${_upperConfig}) - cotire_get_target_compiler_flags( - "${_config}" "${_language}" "${_targetSourceDir}" "${_target}" COTIRE_TARGET_COMPILE_FLAGS_${_upperConfig}) - cotire_get_source_files_compile_definitions( - "${_config}" "${_language}" COTIRE_TARGET_SOURCES_COMPILE_DEFINITIONS_${_upperConfig} ${COTIRE_TARGET_SOURCES}) - endforeach() - get_cmake_property(_vars VARIABLES) - string (REGEX MATCHALL "COTIRE_[A-Za-z0-9_]+" _matchVars "${_vars}") - # remove COTIRE_VERBOSE which is passed as a CMake define on command line - list (REMOVE_ITEM _matchVars COTIRE_VERBOSE) - set (_contents "") - set (_contentsHasGeneratorExpressions FALSE) - foreach (_var IN LISTS _matchVars ITEMS - MSVC CMAKE_GENERATOR CMAKE_BUILD_TYPE CMAKE_CONFIGURATION_TYPES - CMAKE_${_language}_COMPILER_ID CMAKE_${_language}_COMPILER CMAKE_${_language}_COMPILER_ARG1 - CMAKE_${_language}_SOURCE_FILE_EXTENSIONS) - if (DEFINED ${_var}) - string (REPLACE "\"" "\\\"" _value "${${_var}}") - set (_contents "${_contents}set (${_var} \"${_value}\")\n") - if (NOT _contentsHasGeneratorExpressions) - if ("${_value}" MATCHES "\\$<.*>") - set (_contentsHasGeneratorExpressions TRUE) - endif() - endif() - endif() - endforeach() - get_filename_component(_moduleName "${COTIRE_CMAKE_MODULE_FILE}" NAME) - set (_targetCotireScript "${CMAKE_CURRENT_BINARY_DIR}/${_target}_${_language}_${_moduleName}") - cotire_write_file("CMAKE" "${_targetCotireScript}" "${_contents}" FALSE) - if (_contentsHasGeneratorExpressions) - # use file(GENERATE ...) to expand generator expressions in the target script at CMake generate-time - if (NOT CMAKE_VERSION VERSION_LESS "2.8.12") - # the file(GENERATE ...) command requires cmake 2.8.12 or later - set (_configNameOrNoneGeneratorExpression "$<$:None>$<$>:$>") - set (_targetCotireConfigScript "${CMAKE_CURRENT_BINARY_DIR}/${_target}_${_language}_${_configNameOrNoneGeneratorExpression}_${_moduleName}") - file (GENERATE OUTPUT "${_targetCotireConfigScript}" INPUT "${_targetCotireScript}") - else() - message (WARNING "cotire: generator expression used in target ${_target}. This requires CMake 2.8.12 or later.") - set (_targetCotireConfigScript "${_targetCotireScript}") - endif() - else() - set (_targetCotireConfigScript "${_targetCotireScript}") - endif() - set (${_targetScriptVar} "${_targetCotireScript}" PARENT_SCOPE) - set (${_targetConfigScriptVar} "${_targetCotireConfigScript}" PARENT_SCOPE) -endfunction() - -function (cotire_setup_pch_file_compilation _language _target _targetSourceDir _targetScript _prefixFile _pchFile) - set (_sourceFiles ${ARGN}) - if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") - # for Visual Studio and Intel, we attach the precompiled header compilation to the first source file - # the remaining files include the precompiled header, see cotire_setup_pch_file_inclusion - if (_sourceFiles) - file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative) - file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative) - list (GET _sourceFiles 0 _hostFile) - set (_flags "") - cotire_determine_compiler_version("${_language}" COTIRE_${_language}_COMPILER) - cotire_add_pch_compilation_flags( - "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${COTIRE_${_language}_COMPILER_VERSION}" - "${_prefixFile}" "${_pchFile}" "${_hostFile}" _flags) - set_property (SOURCE ${_hostFile} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ") - set_property (SOURCE ${_hostFile} APPEND PROPERTY OBJECT_OUTPUTS "${_pchFile}") - # make first source file depend on prefix header - set_property (SOURCE ${_hostFile} APPEND PROPERTY OBJECT_DEPENDS "${_prefixFile}") - # mark first source file as cotired to prevent it from being used in another cotired target - set_property (SOURCE ${_hostFile} PROPERTY COTIRE_TARGET "${_target}") - endif() - elseif ("${CMAKE_GENERATOR}" MATCHES "Makefiles|Ninja") - # for makefile based generator, we add a custom command to precompile the prefix header - if (_targetScript) - cotire_set_cmd_to_prologue(_cmds) - list (GET _sourceFiles 0 _hostFile) - list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "precompile" "${_targetScript}" "${_prefixFile}" "${_pchFile}" "${_hostFile}") - file (RELATIVE_PATH _pchFileRelPath "${CMAKE_BINARY_DIR}" "${_pchFile}") - if (COTIRE_DEBUG) - message (STATUS "add_custom_command: OUTPUT ${_pchFile} ${_cmds} DEPENDS ${_prefixFile} IMPLICIT_DEPENDS ${_language} ${_prefixFile}") - endif() - set_property (SOURCE "${_pchFile}" PROPERTY GENERATED TRUE) - add_custom_command( - OUTPUT "${_pchFile}" - COMMAND ${_cmds} - DEPENDS "${_prefixFile}" - IMPLICIT_DEPENDS ${_language} "${_prefixFile}" - WORKING_DIRECTORY "${_targetSourceDir}" - COMMENT "Building ${_language} precompiled header ${_pchFileRelPath}" VERBATIM) - endif() - endif() -endfunction() - -function (cotire_setup_pch_file_inclusion _language _target _wholeTarget _prefixFile _pchFile) - set (_sourceFiles ${ARGN}) - if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") - # for Visual Studio and Intel, we include the precompiled header in all but the first source file - # the first source file does the precompiled header compilation, see cotire_setup_pch_file_compilation - list (LENGTH _sourceFiles _numberOfSourceFiles) - if (_numberOfSourceFiles GREATER 1) - # mark sources as cotired to prevent them from being used in another cotired target - set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}") - list (REMOVE_AT _sourceFiles 0) - set (_flags "") - cotire_determine_compiler_version("${_language}" COTIRE_${_language}_COMPILER) - cotire_add_prefix_pch_inclusion_flags( - "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${COTIRE_${_language}_COMPILER_VERSION}" - "${_prefixFile}" "${_pchFile}" _flags) - set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ") - # make source files depend on precompiled header - set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_pchFile}") - endif() - elseif ("${CMAKE_GENERATOR}" MATCHES "Makefiles|Ninja") - if (NOT _wholeTarget) - # for makefile based generator, we force the inclusion of the prefix header for a subset - # of the source files, if this is a multi-language target or has excluded files - set (_flags "") - cotire_determine_compiler_version("${_language}" COTIRE_${_language}_COMPILER) - cotire_add_prefix_pch_inclusion_flags( - "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${COTIRE_${_language}_COMPILER_VERSION}" - "${_prefixFile}" "${_pchFile}" _flags) - set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ") - # mark sources as cotired to prevent them from being used in another cotired target - set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}") - endif() - # make source files depend on precompiled header - set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_pchFile}") - endif() -endfunction() - -function (cotire_setup_prefix_file_inclusion _language _target _prefixFile) - set (_sourceFiles ${ARGN}) - # force the inclusion of the prefix header for the given source files - set (_flags "") - cotire_determine_compiler_version("${_language}" COTIRE_${_language}_COMPILER) - cotire_add_prefix_pch_inclusion_flags( - "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${COTIRE_${_language}_COMPILER_VERSION}" - "${_prefixFile}" "" _flags) - set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ") - # mark sources as cotired to prevent them from being used in another cotired target - set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}") - # make source files depend on prefix header - set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_prefixFile}") -endfunction() - -function (cotire_get_first_set_property_value _propertyValueVar _type _object) - set (_properties ${ARGN}) - foreach (_property ${_properties}) - get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property}) - if (_propertyValue) - set (${_propertyValueVar} ${_propertyValue} PARENT_SCOPE) - return() - endif() - endforeach() - set (${_propertyValueVar} "" PARENT_SCOPE) -endfunction() - -function (cotire_setup_combine_command _language _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}") - get_filename_component(_joinedFileBaseName "${_joinedFile}" NAME_WE) - get_filename_component(_joinedFileExt "${_joinedFile}" EXT) - if (_language AND _joinedFileBaseName MATCHES "${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}$") - set (_comment "Generating ${_language} unity source ${_joinedFileRelPath}") - elseif (_language AND _joinedFileBaseName MATCHES "${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}$") - if (_joinedFileExt MATCHES "^\\.c") - set (_comment "Generating ${_language} prefix source ${_joinedFileRelPath}") - else() - set (_comment "Generating ${_language} prefix header ${_joinedFileRelPath}") - endif() - else() - set (_comment "Generating ${_joinedFileRelPath}") - endif() - add_custom_command( - OUTPUT "${_joinedFile}" - COMMAND ${_prefixCmd} - DEPENDS ${_files} - COMMENT "${_comment}" - 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 - # if necessary, we also generate a single prefix header which includes all language specific prefix headers - set (_prefixFiles "") - foreach (_language ${_languages}) - get_property(_prefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER) - if (_prefixFile) - list (APPEND _prefixFiles "${_prefixFile}") - endif() - endforeach() - set (_cmds ${ARGN}) - list (LENGTH _prefixFiles _numberOfPrefixFiles) - if (_numberOfPrefixFiles GREATER 1) - cotire_make_prefix_file_path("" ${_target} _prefixHeader) - cotire_setup_combine_command("" "${_targetSourceDir}" "" "${_prefixHeader}" _cmds ${_prefixFiles}) - else() - set (_prefixHeader "${_prefixFiles}") - endif() - if (COTIRE_DEBUG) - message (STATUS "add_custom_command: TARGET ${_target} PRE_BUILD ${_cmds}") - endif() - add_custom_command(TARGET "${_target}" - PRE_BUILD ${_cmds} - WORKING_DIRECTORY "${_targetSourceDir}" - COMMENT "Updating target ${_target} prefix headers" VERBATIM) - # make Xcode precompile the generated prefix header with ProcessPCH and ProcessPCH++ - set_target_properties(${_target} PROPERTIES XCODE_ATTRIBUTE_GCC_PRECOMPILE_PREFIX_HEADER "YES") - set_target_properties(${_target} PROPERTIES XCODE_ATTRIBUTE_GCC_PREFIX_HEADER "${_prefixHeader}") - elseif ("${CMAKE_GENERATOR}" MATCHES "Makefiles|Ninja") - # for makefile based generator, we force inclusion of the prefix header for all target source files - # if this is a single-language target without any excluded files - if (_wholeTarget) - set (_language "${_languages}") - # for Visual Studio and Intel, precompiled header inclusion is always done on the source file level - # see cotire_setup_pch_file_inclusion - if (NOT CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") - get_property(_prefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER) - get_property(_pchFile TARGET ${_target} PROPERTY COTIRE_${_language}_PRECOMPILED_HEADER) - set (_flags "") - cotire_determine_compiler_version("${_language}" COTIRE_${_language}_COMPILER) - cotire_add_prefix_pch_inclusion_flags( - "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${COTIRE_${_language}_COMPILER_VERSION}" - "${_prefixFile}" "${_pchFile}" _flags) - set_property(TARGET ${_target} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ") - endif() - endif() - endif() -endfunction() - -function (cotire_setup_unity_generation_commands _language _targetSourceDir _target _targetScript _targetConfigScript _unityFiles _cmdsVar) - set (_dependencySources "") - cotire_get_unity_source_dependencies(${_language} ${_target} _dependencySources ${ARGN}) - foreach (_unityFile ${_unityFiles}) - file (RELATIVE_PATH _unityFileRelPath "${CMAKE_BINARY_DIR}" "${_unityFile}") - set_property (SOURCE "${_unityFile}" PROPERTY GENERATED TRUE) - # set up compiled unity source dependencies - # this ensures that missing source files are generated before the unity file is compiled - if (COTIRE_DEBUG AND _dependencySources) - message (STATUS "${_unityFile} OBJECT_DEPENDS ${_dependencySources}") - endif() - if (_dependencySources) - set_property (SOURCE "${_unityFile}" PROPERTY OBJECT_DEPENDS ${_dependencySources}) - endif() - if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") - # unity file compilation results in potentially huge object file, thus use /bigobj by default unter MSVC and Windows Intel - set_property (SOURCE "${_unityFile}" APPEND_STRING PROPERTY COMPILE_FLAGS "/bigobj") - endif() - cotire_set_cmd_to_prologue(_unityCmd) - list (APPEND _unityCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "unity" "${_targetConfigScript}" "${_unityFile}") - if (COTIRE_DEBUG) - message (STATUS "add_custom_command: OUTPUT ${_unityFile} COMMAND ${_unityCmd} DEPENDS ${_targetScript}") - endif() - add_custom_command( - OUTPUT "${_unityFile}" - COMMAND ${_unityCmd} - DEPENDS "${_targetScript}" - COMMENT "Generating ${_language} unity source ${_unityFileRelPath}" - WORKING_DIRECTORY "${_targetSourceDir}" VERBATIM) - list (APPEND ${_cmdsVar} COMMAND ${_unityCmd}) - endforeach() - list (LENGTH _unityFiles _numberOfUnityFiles) - if (_numberOfUnityFiles GREATER 1) - # create a joint unity file from all unity file segments - cotire_make_single_unity_source_file_path(${_language} ${_target} _unityFile) - cotire_setup_combine_command(${_language} "${_targetSourceDir}" "${_targetConfigScript}" "${_unityFile}" ${_cmdsVar} ${_unityFiles}) - endif() - set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) -endfunction() - -function (cotire_setup_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) - list (APPEND _prefixCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "prefix" "${_targetScript}" "${_prefixFile}" "${_unityFile}") - set_property (SOURCE "${_prefixFile}" PROPERTY GENERATED TRUE) - if (COTIRE_DEBUG) - message (STATUS "add_custom_command: OUTPUT ${_prefixFile} COMMAND ${_prefixCmd} DEPENDS ${_unityFile} ${_dependencySources}") - endif() - file (RELATIVE_PATH _prefixFileRelPath "${CMAKE_BINARY_DIR}" "${_prefixFile}") - get_filename_component(_prefixFileExt "${_prefixFile}" EXT) - if (_prefixFileExt MATCHES "^\\.c") - set (_comment "Generating ${_language} prefix source ${_prefixFileRelPath}") - else() - set (_comment "Generating ${_language} prefix header ${_prefixFileRelPath}") - endif() - add_custom_command( - OUTPUT "${_prefixFile}" "${_prefixFile}.log" - COMMAND ${_prefixCmd} - DEPENDS "${_unityFile}" ${_dependencySources} - COMMENT "${_comment}" - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" VERBATIM) - list (APPEND ${_cmdsVar} COMMAND ${_prefixCmd}) - set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) -endfunction() - -function (cotire_setup_prefix_generation_from_unity_command _language _target _targetSourceDir _targetScript _prefixFile _unityFiles _cmdsVar) - set (_sourceFiles ${ARGN}) - if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang") - # GNU and Clang require indirect compilation of the prefix header to make them honor the system_header pragma - cotire_prefix_header_to_source_file_path(${_language} "${_prefixFile}" _prefixSourceFile) - else() - set (_prefixSourceFile "${_prefixFile}") - endif() - list (LENGTH _unityFiles _numberOfUnityFiles) - if (_numberOfUnityFiles GREATER 1) - cotire_make_single_unity_source_file_path(${_language} ${_target} _unityFile) - cotire_setup_prefix_generation_command( - ${_language} ${_target} "${_targetSourceDir}" "${_targetScript}" - "${_prefixSourceFile}" "${_unityFile}" ${_cmdsVar} ${_sourceFiles}) - else() - cotire_setup_prefix_generation_command( - ${_language} ${_target} "${_targetSourceDir}" "${_targetScript}" - "${_prefixSourceFile}" "${_unityFiles}" ${_cmdsVar} ${_sourceFiles}) - endif() - if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang") - cotire_setup_combine_command(${_language} "${_targetSourceDir}" "${_targetScript}" "${_prefixFile}" ${_cmdsVar} ${_prefixSourceFile}) - endif() - set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) -endfunction() - -function (cotire_setup_prefix_generation_from_provided_command _language _target _targetSourceDir _targetScript _prefixFile _cmdsVar) - set (_prefixHeaderFiles ${ARGN}) - if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang") - # GNU and Clang require indirect compilation of the prefix header to make them honor the system_header pragma - cotire_prefix_header_to_source_file_path(${_language} "${_prefixFile}" _prefixSourceFile) - else() - set (_prefixSourceFile "${_prefixFile}") - endif() - cotire_setup_combine_command(${_language} "${_targetSourceDir}" "${_targetScript}" "${_prefixSourceFile}" _cmds ${_prefixHeaderFiles}) - if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang") - cotire_setup_combine_command(${_language} "${_targetSourceDir}" "${_targetScript}" "${_prefixFile}" _cmds ${_prefixSourceFile}) - endif() - set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) -endfunction() - -function (cotire_init_cotire_target_properties _target) - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER SET) - if (NOT _isSet) - set_property(TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER TRUE) - endif() - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD SET) - if (NOT _isSet) - set_property(TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD TRUE) - endif() - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ADD_CLEAN SET) - if (NOT _isSet) - set_property(TARGET ${_target} PROPERTY COTIRE_ADD_CLEAN FALSE) - endif() - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH SET) - if (NOT _isSet) - set_property(TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH "${CMAKE_SOURCE_DIR}") - cotire_check_is_path_relative_to("${CMAKE_BINARY_DIR}" _isRelative "${CMAKE_SOURCE_DIR}") - if (NOT _isRelative) - set_property(TARGET ${_target} APPEND PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH "${CMAKE_BINARY_DIR}") - endif() - endif() - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PATH SET) - if (NOT _isSet) - set_property(TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PATH "") - endif() - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_PRE_UNDEFS SET) - if (NOT _isSet) - set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_PRE_UNDEFS "") - endif() - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_POST_UNDEFS SET) - if (NOT _isSet) - set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_POST_UNDEFS "") - endif() - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_LINK_LIBRARIES_INIT SET) - if (NOT _isSet) - set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_LINK_LIBRARIES_INIT "") - endif() - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES SET) - if (NOT _isSet) - if (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES) - set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES}") - else() - set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "") - endif() - endif() -endfunction() - -function (cotire_make_target_message _target _languages _disableMsg _targetMsgVar) - get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER) - get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD) - string (REPLACE ";" " " _languagesStr "${_languages}") - math (EXPR _numberOfExcludedFiles "${ARGC} - 4") - if (_numberOfExcludedFiles EQUAL 0) - set (_excludedStr "") - elseif (COTIRE_VERBOSE OR _numberOfExcludedFiles LESS 4) - string (REPLACE ";" ", " _excludedStr "excluding ${ARGN}") - else() - set (_excludedStr "excluding ${_numberOfExcludedFiles} files") - endif() - set (_targetMsg "") - if (NOT _languages) - set (_targetMsg "Target ${_target} cannot be cotired.") - if (_disableMsg) - set (_targetMsg "${_targetMsg} ${_disableMsg}") - endif() - elseif (NOT _targetUsePCH AND NOT _targetAddSCU) - set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build and precompiled header.") - if (_disableMsg) - set (_targetMsg "${_targetMsg} ${_disableMsg}") - endif() - elseif (NOT _targetUsePCH) - if (_excludedStr) - set (_targetMsg "${_languagesStr} target ${_target} cotired without precompiled header ${_excludedStr}.") - else() - set (_targetMsg "${_languagesStr} target ${_target} cotired without precompiled header.") - endif() - if (_disableMsg) - set (_targetMsg "${_targetMsg} ${_disableMsg}") - endif() - elseif (NOT _targetAddSCU) - if (_excludedStr) - set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build ${_excludedStr}.") - else() - set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build.") - endif() - else() - if (_excludedStr) - set (_targetMsg "${_languagesStr} target ${_target} cotired ${_excludedStr}.") - else() - set (_targetMsg "${_languagesStr} target ${_target} cotired.") - endif() - endif() - set (${_targetMsgVar} "${_targetMsg}" PARENT_SCOPE) -endfunction() - -function (cotire_choose_target_languages _targetSourceDir _target _targetLanguagesVar) - set (_languages ${ARGN}) - set (_allSourceFiles "") - set (_allExcludedSourceFiles "") - set (_allCotiredSourceFiles "") - set (_targetLanguages "") - get_target_property(_targetType ${_target} TYPE) - get_target_property(_targetSourceFiles ${_target} SOURCES) - get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER) - get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD) - set (_disableMsg "") - foreach (_language ${_languages}) - get_target_property(_prefixHeader ${_target} COTIRE_${_language}_PREFIX_HEADER) - get_target_property(_unityBuildFile ${_target} COTIRE_${_language}_UNITY_SOURCE) - if (_prefixHeader OR _unityBuildFile) - message (STATUS "cotire: target ${_target} has already been cotired.") - set (${_targetLanguagesVar} "" PARENT_SCOPE) - return() - endif() - if (_targetUsePCH AND "${_language}" MATCHES "^C|CXX$") - cotire_check_precompiled_header_support("${_language}" "${_targetSourceDir}" "${_target}" _disableMsg) - if (_disableMsg) - set (_targetUsePCH FALSE) - endif() - endif() - set (_sourceFiles "") - set (_excludedSources "") - set (_cotiredSources "") - cotire_filter_language_source_files(${_language} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles}) - if (_sourceFiles OR _excludedSources OR _cotiredSources) - list (APPEND _targetLanguages ${_language}) - endif() - if (_sourceFiles) - list (APPEND _allSourceFiles ${_sourceFiles}) - endif() - if (_excludedSources) - list (APPEND _allExcludedSourceFiles ${_excludedSources}) - endif() - if (_cotiredSources) - list (APPEND _allCotiredSourceFiles ${_cotiredSources}) - endif() - endforeach() - set (_targetMsgLevel STATUS) - if (NOT _targetLanguages) - string (REPLACE ";" " or " _languagesStr "${_languages}") - set (_disableMsg "No ${_languagesStr} source files.") - set (_targetUsePCH FALSE) - set (_targetAddSCU FALSE) - endif() - if (_targetUsePCH) - list (LENGTH _allSourceFiles _numberOfSources) - if (_numberOfSources LESS ${COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES}) - set (_disableMsg "Too few applicable sources.") - set (_targetUsePCH FALSE) - elseif (_allCotiredSourceFiles) - cotire_get_source_file_property_values(_cotireTargets COTIRE_TARGET ${_allCotiredSourceFiles}) - list (REMOVE_DUPLICATES _cotireTargets) - string (REPLACE ";" ", " _cotireTargetsStr "${_cotireTargets}") - set (_disableMsg "Target sources already include a precompiled header for target(s) ${_cotireTargets}.") - set (_disableMsg "${_disableMsg} Set target property COTIRE_ENABLE_PRECOMPILED_HEADER to FALSE for targets ${_target},") - set (_disableMsg "${_disableMsg} ${_cotireTargetsStr} to get a workable build system.") - set (_targetMsgLevel SEND_ERROR) - set (_targetUsePCH FALSE) - elseif (XCODE AND _allExcludedSourceFiles) - # for Xcode, we cannot apply the precompiled header to individual sources, only to the whole target - set (_disableMsg "Exclusion of source files not supported for generator Xcode.") - set (_targetUsePCH FALSE) - elseif (XCODE AND "${_targetType}" STREQUAL "OBJECT_LIBRARY") - # for Xcode, we cannot apply the required PRE_BUILD action to generate the prefix header to an OBJECT_LIBRARY target - set (_disableMsg "Required PRE_BUILD action not supported for OBJECT_LIBRARY targets for generator Xcode.") - set (_targetUsePCH FALSE) - endif() - endif() - set_property(TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER ${_targetUsePCH}) - set_property(TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD ${_targetAddSCU}) - cotire_make_target_message(${_target} "${_targetLanguages}" "${_disableMsg}" _targetMsg ${_allExcludedSourceFiles}) - if (_targetMsg) - if (NOT DEFINED COTIREMSG_${_target}) - set (COTIREMSG_${_target} "") - endif() - if (COTIRE_VERBOSE OR NOT "${_targetMsgLevel}" STREQUAL "STATUS" OR - NOT "${COTIREMSG_${_target}}" STREQUAL "${_targetMsg}") - # cache message to avoid redundant messages on re-configure - set (COTIREMSG_${_target} "${_targetMsg}" CACHE INTERNAL "${_target} cotire message.") - message (${_targetMsgLevel} "${_targetMsg}") - endif() - endif() - 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|--jobs) ?([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) - set (_sourceFiles "") - set (_excludedSources "") - set (_cotiredSources "") - cotire_filter_language_source_files(${_language} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles}) - if (NOT _sourceFiles AND NOT _cotiredSources) - return() - endif() - set (_wholeTarget ${${_wholeTargetVar}}) - set (_cmds "") - # check for user provided unity source file list - get_property(_unitySourceFiles TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE_INIT) - if (NOT _unitySourceFiles) - set (_unitySourceFiles ${_sourceFiles} ${_cotiredSources}) - endif() - cotire_generate_target_script( - ${_language} "${_configurations}" "${_targetSourceDir}" "${_targetBinaryDir}" ${_target} _targetScript _targetConfigScript ${_unitySourceFiles}) - 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() - endif() - cotire_setup_unity_generation_commands( - ${_language} "${_targetSourceDir}" ${_target} "${_targetScript}" "${_targetConfigScript}" "${_unityFiles}" _cmds ${_unitySourceFiles}) - cotire_make_prefix_file_path(${_language} ${_target} _prefixFile) - if (_prefixFile) - # check for user provided prefix header files - get_property(_prefixHeaderFiles TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER_INIT) - if (_prefixHeaderFiles) - cotire_setup_prefix_generation_from_provided_command( - ${_language} ${_target} "${_targetSourceDir}" "${_targetConfigScript}" "${_prefixFile}" _cmds ${_prefixHeaderFiles}) - else() - cotire_setup_prefix_generation_from_unity_command( - ${_language} ${_target} "${_targetSourceDir}" "${_targetConfigScript}" "${_prefixFile}" "${_unityFiles}" _cmds ${_unitySourceFiles}) - endif() - get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER) - if (_targetUsePCH) - cotire_make_pch_file_path(${_language} "${_targetSourceDir}" ${_target} _pchFile) - if (_pchFile) - cotire_setup_pch_file_compilation( - ${_language} ${_target} "${_targetSourceDir}" "${_targetConfigScript}" "${_prefixFile}" "${_pchFile}" ${_sourceFiles}) - if (_excludedSources) - set (_wholeTarget FALSE) - endif() - cotire_setup_pch_file_inclusion( - ${_language} ${_target} ${_wholeTarget} "${_prefixFile}" "${_pchFile}" ${_sourceFiles}) - endif() - elseif (_prefixHeaderFiles) - # user provided prefix header must be included - cotire_setup_prefix_file_inclusion( - ${_language} ${_target} "${_prefixFile}" ${_sourceFiles}) - endif() - endif() - # mark target as cotired for language - set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE "${_unityFiles}") - if (_prefixFile) - set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER "${_prefixFile}") - if (_targetUsePCH AND _pchFile) - set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_PRECOMPILED_HEADER "${_pchFile}") - endif() - endif() - set (${_wholeTargetVar} ${_wholeTarget} PARENT_SCOPE) - set (${_cmdsVar} ${_cmds} PARENT_SCOPE) -endfunction() - -function (cotire_setup_clean_target _target) - set (_cleanTargetName "${_target}${COTIRE_CLEAN_TARGET_SUFFIX}") - if (NOT TARGET "${_cleanTargetName}") - cotire_set_cmd_to_prologue(_cmds) - get_filename_component(_outputDir "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}" ABSOLUTE) - list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "cleanup" "${_outputDir}" "${COTIRE_INTDIR}" "${_target}") - add_custom_target(${_cleanTargetName} COMMAND ${_cmds} WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" - COMMENT "Cleaning up target ${_target} cotire generated files" VERBATIM) - cotire_init_target("${_cleanTargetName}") - endif() -endfunction() - -function (cotire_setup_pch_target _languages _configurations _target) - if ("${CMAKE_GENERATOR}" MATCHES "Makefiles|Ninja") - # for makefile based generators, we add a custom target to trigger the generation of the cotire related files - set (_dependsFiles "") - foreach (_language ${_languages}) - set (_props COTIRE_${_language}_PREFIX_HEADER COTIRE_${_language}_UNITY_SOURCE) - if (NOT CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") - # Visual Studio and Intel only create precompiled header as a side effect - list (INSERT _props 0 COTIRE_${_language}_PRECOMPILED_HEADER) - endif() - cotire_get_first_set_property_value(_dependsFile TARGET ${_target} ${_props}) - if (_dependsFile) - list (APPEND _dependsFiles "${_dependsFile}") - endif() - endforeach() - if (_dependsFiles) - set (_pchTargetName "${_target}${COTIRE_PCH_TARGET_SUFFIX}") - add_custom_target("${_pchTargetName}" DEPENDS ${_dependsFiles}) - cotire_init_target("${_pchTargetName}") - cotire_add_to_pch_all_target(${_pchTargetName}) - endif() - else() - # for other generators, we add the "clean all" target to clean up the precompiled header - cotire_setup_clean_all_target() - endif() -endfunction() - -function (cotire_setup_unity_build_target _languages _configurations _targetSourceDir _target) - get_target_property(_unityTargetName ${_target} COTIRE_UNITY_TARGET_NAME) - if (NOT _unityTargetName) - set (_unityTargetName "${_target}${COTIRE_UNITY_BUILD_TARGET_SUFFIX}") - endif() - # determine unity target sub type - get_target_property(_targetType ${_target} TYPE) - if ("${_targetType}" STREQUAL "EXECUTABLE") - set (_unityTargetSubType "") - elseif (_targetType MATCHES "(STATIC|SHARED|MODULE|OBJECT)_LIBRARY") - set (_unityTargetSubType "${CMAKE_MATCH_1}") - else() - message (WARNING "cotire: target ${_target} has unknown target type ${_targetType}.") - return() - endif() - # determine unity target sources - get_target_property(_targetSourceFiles ${_target} SOURCES) - set (_unityTargetSources ${_targetSourceFiles}) - foreach (_language ${_languages}) - get_property(_unityFiles TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE) - if (_unityFiles) - # remove source files that are included in the unity source - set (_sourceFiles "") - set (_excludedSources "") - set (_cotiredSources "") - cotire_filter_language_source_files(${_language} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles}) - if (_sourceFiles OR _cotiredSources) - list (REMOVE_ITEM _unityTargetSources ${_sourceFiles} ${_cotiredSources}) - endif() - # if cotire is applied to a target which has not been added in the current source dir, - # non-existing files cannot be referenced from the unity build target (this is a CMake restriction) - if (NOT "${_targetSourceDir}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}") - set (_nonExistingFiles "") - foreach (_file ${_unityTargetSources}) - if (NOT EXISTS "${_file}") - list (APPEND _nonExistingFiles "${_file}") - endif() - endforeach() - if (_nonExistingFiles) - if (COTIRE_VERBOSE) - message (STATUS "removing non-existing ${_nonExistingFiles} from ${_unityTargetName}") - endif() - list (REMOVE_ITEM _unityTargetSources ${_nonExistingFiles}) - endif() - endif() - # add unity source files instead - list (APPEND _unityTargetSources ${_unityFiles}) - endif() - endforeach() - if (COTIRE_DEBUG) - message (STATUS "add ${_targetType} ${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources}") - endif() - # generate unity target - if ("${_targetType}" STREQUAL "EXECUTABLE") - add_executable(${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources}) - else() - add_library(${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources}) - endif() - set (_outputDirProperties - ARCHIVE_OUTPUT_DIRECTORY ARCHIVE_OUTPUT_DIRECTORY_ - LIBRARY_OUTPUT_DIRECTORY LIBRARY_OUTPUT_DIRECTORY_ - RUNTIME_OUTPUT_DIRECTORY RUNTIME_OUTPUT_DIRECTORY_) - # copy output location properties - if (COTIRE_UNITY_OUTPUT_DIRECTORY) - set (_setDefaultOutputDir TRUE) - if (IS_ABSOLUTE "${COTIRE_UNITY_OUTPUT_DIRECTORY}") - set (_outputDir "${COTIRE_UNITY_OUTPUT_DIRECTORY}") - else() - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} ${_outputDirProperties}) - cotire_resolve_config_properites("${_configurations}" _properties ${_outputDirProperties}) - foreach (_property ${_properties}) - get_property(_outputDir TARGET ${_target} PROPERTY ${_property}) - if (_outputDir) - get_filename_component(_outputDir "${_outputDir}/${COTIRE_UNITY_OUTPUT_DIRECTORY}" ABSOLUTE) - set_property(TARGET ${_unityTargetName} PROPERTY ${_property} "${_outputDir}") - set (_setDefaultOutputDir FALSE) - endif() - endforeach() - if (_setDefaultOutputDir) - get_filename_component(_outputDir "${CMAKE_CURRENT_BINARY_DIR}/${COTIRE_UNITY_OUTPUT_DIRECTORY}" ABSOLUTE) - endif() - endif() - if (_setDefaultOutputDir) - set_target_properties(${_unityTargetName} PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY "${_outputDir}" - LIBRARY_OUTPUT_DIRECTORY "${_outputDir}" - RUNTIME_OUTPUT_DIRECTORY "${_outputDir}") - endif() - else() - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} ${_outputDirProperties}) - endif() - # copy output name - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - ARCHIVE_OUTPUT_NAME ARCHIVE_OUTPUT_NAME_ - LIBRARY_OUTPUT_NAME LIBRARY_OUTPUT_NAME_ - OUTPUT_NAME OUTPUT_NAME_ - RUNTIME_OUTPUT_NAME RUNTIME_OUTPUT_NAME_ - PREFIX _POSTFIX SUFFIX) - # copy compile stuff - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - COMPILE_DEFINITIONS COMPILE_DEFINITIONS_ - COMPILE_FLAGS COMPILE_OPTIONS - Fortran_FORMAT Fortran_MODULE_DIRECTORY - INCLUDE_DIRECTORIES - INTERPROCEDURAL_OPTIMIZATION INTERPROCEDURAL_OPTIMIZATION_ - POSITION_INDEPENDENT_CODE - C_VISIBILITY_PRESET CXX_VISIBILITY_PRESET VISIBILITY_INLINES_HIDDEN) - # copy interface stuff - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - COMPATIBLE_INTERFACE_BOOL COMPATIBLE_INTERFACE_NUMBER_MAX COMPATIBLE_INTERFACE_NUMBER_MIN COMPATIBLE_INTERFACE_STRING - INTERFACE_COMPILE_DEFINITIONS INTERFACE_COMPILE_OPTIONS INTERFACE_INCLUDE_DIRECTORIES - INTERFACE_POSITION_INDEPENDENT_CODE INTERFACE_SYSTEM_INCLUDE_DIRECTORIES - INTERFACE_AUTOUIC_OPTIONS) - # copy link stuff - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - BUILD_WITH_INSTALL_RPATH INSTALL_RPATH INSTALL_RPATH_USE_LINK_PATH SKIP_BUILD_RPATH - LINKER_LANGUAGE LINK_DEPENDS LINK_DEPENDS_NO_SHARED - LINK_FLAGS LINK_FLAGS_ - LINK_INTERFACE_LIBRARIES LINK_INTERFACE_LIBRARIES_ - LINK_INTERFACE_MULTIPLICITY LINK_INTERFACE_MULTIPLICITY_ - LINK_SEARCH_START_STATIC LINK_SEARCH_END_STATIC - STATIC_LIBRARY_FLAGS STATIC_LIBRARY_FLAGS_ - NO_SONAME SOVERSION VERSION) - # copy Qt stuff - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - AUTOMOC AUTOMOC_MOC_OPTIONS AUTOUIC AUTOUIC_OPTIONS AUTORCC AUTORCC_OPTIONS - AUTOGEN_TARGET_DEPENDS) - # copy cmake stuff - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - IMPLICIT_DEPENDS_INCLUDE_TRANSFORM RULE_LAUNCH_COMPILE RULE_LAUNCH_CUSTOM RULE_LAUNCH_LINK) - # copy Apple platform specific stuff - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - BUNDLE BUNDLE_EXTENSION FRAMEWORK INSTALL_NAME_DIR MACOSX_BUNDLE MACOSX_BUNDLE_INFO_PLIST MACOSX_FRAMEWORK_INFO_PLIST - MACOSX_RPATH OSX_ARCHITECTURES OSX_ARCHITECTURES_ PRIVATE_HEADER PUBLIC_HEADER RESOURCE) - # copy Windows platform specific stuff - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - GNUtoMS - PDB_NAME PDB_NAME_ PDB_OUTPUT_DIRECTORY PDB_OUTPUT_DIRECTORY_ - VS_DOTNET_REFERENCES VS_GLOBAL_KEYWORD VS_GLOBAL_PROJECT_TYPES VS_GLOBAL_ROOTNAMESPACE VS_KEYWORD - VS_SCC_AUXPATH VS_SCC_LOCALPATH VS_SCC_PROJECTNAME VS_SCC_PROVIDER - VS_WINRT_EXTENSIONS VS_WINRT_REFERENCES WIN32_EXECUTABLE) - # use output name from original target - get_target_property(_targetOutputName ${_unityTargetName} OUTPUT_NAME) - if (NOT _targetOutputName) - set_property(TARGET ${_unityTargetName} PROPERTY OUTPUT_NAME "${_target}") - endif() - # use export symbol from original target - cotire_get_target_export_symbol("${_target}" _defineSymbol) - if (_defineSymbol) - set_property(TARGET ${_unityTargetName} PROPERTY DEFINE_SYMBOL "${_defineSymbol}") - if ("${_targetType}" STREQUAL "EXECUTABLE") - set_property(TARGET ${_unityTargetName} PROPERTY ENABLE_EXPORTS TRUE) - endif() - endif() - cotire_init_target(${_unityTargetName}) - cotire_add_to_unity_all_target(${_unityTargetName}) - set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_TARGET_NAME "${_unityTargetName}") -endfunction(cotire_setup_unity_build_target) - -function (cotire_target _target) - set(_options "") - set(_oneValueArgs SOURCE_DIR BINARY_DIR) - set(_multiValueArgs LANGUAGES CONFIGURATIONS) - cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) - if (NOT _option_SOURCE_DIR) - set (_option_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") - endif() - if (NOT _option_BINARY_DIR) - set (_option_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}") - endif() - if (NOT _option_LANGUAGES) - get_property (_option_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) - endif() - if (NOT _option_CONFIGURATIONS) - if (CMAKE_CONFIGURATION_TYPES) - set (_option_CONFIGURATIONS ${CMAKE_CONFIGURATION_TYPES}) - elseif (CMAKE_BUILD_TYPE) - set (_option_CONFIGURATIONS "${CMAKE_BUILD_TYPE}") - else() - set (_option_CONFIGURATIONS "None") - endif() - endif() - # trivial checks - get_target_property(_imported ${_target} IMPORTED) - if (_imported) - message (WARNING "cotire: imported target ${_target} cannot be cotired.") - return() - endif() - # resolve alias - get_target_property(_aliasName ${_target} ALIASED_TARGET) - if (_aliasName) - if (COTIRE_DEBUG) - message (STATUS "${_target} is an alias. Applying cotire to aliased target ${_aliasName} instead.") - endif() - set (_target ${_aliasName}) - endif() - # check if target needs to be cotired for build type - # when using configuration types, the test is performed at build time - cotire_init_cotire_target_properties(${_target}) - if (NOT CMAKE_CONFIGURATION_TYPES) - if (CMAKE_BUILD_TYPE) - list (FIND _option_CONFIGURATIONS "${CMAKE_BUILD_TYPE}" _index) - else() - list (FIND _option_CONFIGURATIONS "None" _index) - endif() - if (_index EQUAL -1) - if (COTIRE_DEBUG) - message (STATUS "CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} not cotired (${_option_CONFIGURATIONS})") - endif() - return() - endif() - endif() - # choose languages that apply to the target - cotire_choose_target_languages("${_option_SOURCE_DIR}" "${_target}" _targetLanguages ${_option_LANGUAGES}) - if (NOT _targetLanguages) - return() - endif() - list (LENGTH _targetLanguages _numberOfLanguages) - if (_numberOfLanguages GREATER 1) - set (_wholeTarget FALSE) - else() - set (_wholeTarget TRUE) - endif() - set (_cmds "") - foreach (_language ${_targetLanguages}) - cotire_process_target_language("${_language}" "${_option_CONFIGURATIONS}" - "${_option_SOURCE_DIR}" "${_option_BINARY_DIR}" ${_target} _wholeTarget _cmd) - if (_cmd) - list (APPEND _cmds ${_cmd}) - endif() - endforeach() - get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD) - if (_targetAddSCU) - cotire_setup_unity_build_target("${_targetLanguages}" "${_option_CONFIGURATIONS}" "${_option_SOURCE_DIR}" ${_target}) - endif() - get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER) - if (_targetUsePCH) - cotire_setup_target_pch_usage("${_targetLanguages}" "${_option_SOURCE_DIR}" ${_target} ${_wholeTarget} ${_cmds}) - cotire_setup_pch_target("${_targetLanguages}" "${_option_CONFIGURATIONS}" ${_target}) - endif() - get_target_property(_targetAddCleanTarget ${_target} COTIRE_ADD_CLEAN) - if (_targetAddCleanTarget) - cotire_setup_clean_target(${_target}) - endif() -endfunction(cotire_target) - -function (cotire_map_libraries _strategy _mappedLibrariesVar) - set (_mappedLibraries "") - foreach (_library ${ARGN}) - if (TARGET "${_library}" AND "${_strategy}" MATCHES "COPY_UNITY") - get_target_property(_libraryUnityTargetName ${_library} COTIRE_UNITY_TARGET_NAME) - if (TARGET "${_libraryUnityTargetName}") - list (APPEND _mappedLibraries "${_libraryUnityTargetName}") - else() - list (APPEND _mappedLibraries "${_library}") - endif() - else() - list (APPEND _mappedLibraries "${_library}") - endif() - endforeach() - list (REMOVE_DUPLICATES _mappedLibraries) - set (${_mappedLibrariesVar} ${_mappedLibraries} PARENT_SCOPE) -endfunction() - -function (cotire_target_link_libraries _target) - get_target_property(_unityTargetName ${_target} COTIRE_UNITY_TARGET_NAME) - if (TARGET "${_unityTargetName}") - get_target_property(_linkLibrariesStrategy ${_target} COTIRE_UNITY_LINK_LIBRARIES_INIT) - if (COTIRE_DEBUG) - message (STATUS "unity target ${_unityTargetName} link strategy: ${_linkLibrariesStrategy}") - endif() - if ("${_linkLibrariesStrategy}" MATCHES "^(COPY|COPY_UNITY)$") - if (CMAKE_VERSION VERSION_LESS "2.8.11") - message (WARNING "cotire: unity target link strategy ${_linkLibrariesStrategy} requires CMake 2.8.11 or later. Defaulting to NONE for ${_target}.") - else() - get_target_property(_linkLibraries ${_target} LINK_LIBRARIES) - get_target_property(_interfaceLinkLibraries ${_target} INTERFACE_LINK_LIBRARIES) - cotire_map_libraries("${_linkLibrariesStrategy}" _unityLinkLibraries ${_linkLibraries} ${_interfaceLinkLibraries}) - if (COTIRE_DEBUG) - message (STATUS "unity target ${_unityTargetName} libraries: ${_unityLinkLibraries}") - endif() - if (_unityLinkLibraries) - target_link_libraries(${_unityTargetName} ${_unityLinkLibraries}) - endif() - endif() - endif() - endif() -endfunction(cotire_target_link_libraries) - -function (cotire_cleanup _binaryDir _cotireIntermediateDirName _targetName) - if (_targetName) - file (GLOB_RECURSE _cotireFiles "${_binaryDir}/${_targetName}*.*") - else() - file (GLOB_RECURSE _cotireFiles "${_binaryDir}/*.*") - endif() - # filter files in intermediate directory - set (_filesToRemove "") - foreach (_file ${_cotireFiles}) - get_filename_component(_dir "${_file}" PATH) - get_filename_component(_dirName "${_dir}" NAME) - if ("${_dirName}" STREQUAL "${_cotireIntermediateDirName}") - list (APPEND _filesToRemove "${_file}") - endif() - endforeach() - if (_filesToRemove) - if (COTIRE_VERBOSE) - message (STATUS "removing ${_filesToRemove}") - endif() - file (REMOVE ${_filesToRemove}) - endif() -endfunction() - -function (cotire_init_target _targetName) - if (COTIRE_TARGETS_FOLDER) - set_target_properties(${_targetName} PROPERTIES FOLDER "${COTIRE_TARGETS_FOLDER}") - endif() - if (MSVC_IDE) - set_target_properties(${_targetName} PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD TRUE) - endif() -endfunction() - -function (cotire_add_to_pch_all_target _pchTargetName) - set (_targetName "${COTIRE_PCH_ALL_TARGET_NAME}") - if (NOT TARGET "${_targetName}") - add_custom_target("${_targetName}" WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" VERBATIM) - cotire_init_target("${_targetName}") - endif() - cotire_setup_clean_all_target() - add_dependencies(${_targetName} ${_pchTargetName}) -endfunction() - -function (cotire_add_to_unity_all_target _unityTargetName) - set (_targetName "${COTIRE_UNITY_BUILD_ALL_TARGET_NAME}") - if (NOT TARGET "${_targetName}") - add_custom_target("${_targetName}" WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" VERBATIM) - cotire_init_target("${_targetName}") - endif() - cotire_setup_clean_all_target() - add_dependencies(${_targetName} ${_unityTargetName}) -endfunction() - -function (cotire_setup_clean_all_target) - set (_targetName "${COTIRE_CLEAN_ALL_TARGET_NAME}") - if (NOT TARGET "${_targetName}") - cotire_set_cmd_to_prologue(_cmds) - list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "cleanup" "${CMAKE_BINARY_DIR}" "${COTIRE_INTDIR}") - add_custom_target(${_targetName} COMMAND ${_cmds} - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" COMMENT "Cleaning up all cotire generated files" VERBATIM) - cotire_init_target("${_targetName}") - endif() -endfunction() - -function (cotire) - set(_options "") - set(_oneValueArgs SOURCE_DIR BINARY_DIR) - set(_multiValueArgs LANGUAGES CONFIGURATIONS) - cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) - set (_targets ${_option_UNPARSED_ARGUMENTS}) - if (NOT _option_SOURCE_DIR) - set (_option_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") - endif() - if (NOT _option_BINARY_DIR) - set (_option_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}") - endif() - foreach (_target ${_targets}) - if (TARGET ${_target}) - cotire_target(${_target} LANGUAGES ${_option_LANGUAGES} CONFIGURATIONS ${_option_CONFIGURATIONS} - SOURCE_DIR "${_option_SOURCE_DIR}" BINARY_DIR "${_option_BINARY_DIR}") - else() - message (WARNING "cotire: ${_target} is not a target.") - endif() - endforeach() - foreach (_target ${_targets}) - if (TARGET ${_target}) - cotire_target_link_libraries(${_target}) - endif() - endforeach() -endfunction() - -if (CMAKE_SCRIPT_MODE_FILE) - - # cotire is being run in script mode - # locate -P on command args - set (COTIRE_ARGC -1) - foreach (_index RANGE ${CMAKE_ARGC}) - if (COTIRE_ARGC GREATER -1) - set (COTIRE_ARGV${COTIRE_ARGC} "${CMAKE_ARGV${_index}}") - math (EXPR COTIRE_ARGC "${COTIRE_ARGC} + 1") - elseif ("${CMAKE_ARGV${_index}}" STREQUAL "-P") - set (COTIRE_ARGC 0) - endif() - endforeach() - - # include target script if available - if ("${COTIRE_ARGV2}" MATCHES "\\.cmake$") - # the included target scripts sets up additional variables relating to the target (e.g., COTIRE_TARGET_SOURCES) - include("${COTIRE_ARGV2}") - endif() - - if (COTIRE_DEBUG) - message (STATUS "${COTIRE_ARGV0} ${COTIRE_ARGV1} ${COTIRE_ARGV2} ${COTIRE_ARGV3} ${COTIRE_ARGV4} ${COTIRE_ARGV5}") - endif() - - if (WIN32) - # for MSVC, compiler IDs may not always be set correctly - if (MSVC) - set (CMAKE_C_COMPILER_ID "MSVC") - set (CMAKE_CXX_COMPILER_ID "MSVC") - endif() - endif() - - if (NOT COTIRE_BUILD_TYPE) - set (COTIRE_BUILD_TYPE "None") - endif() - string (TOUPPER "${COTIRE_BUILD_TYPE}" _upperConfig) - set (_includeDirs ${COTIRE_TARGET_INCLUDE_DIRECTORIES_${_upperConfig}}) - set (_systemIncludeDirs ${COTIRE_TARGET_SYSTEM_INCLUDE_DIRECTORIES_${_upperConfig}}) - set (_compileDefinitions ${COTIRE_TARGET_COMPILE_DEFINITIONS_${_upperConfig}}) - set (_compileFlags ${COTIRE_TARGET_COMPILE_FLAGS_${_upperConfig}}) - # check if target has been cotired for actual build type COTIRE_BUILD_TYPE - list (FIND COTIRE_TARGET_CONFIGURATION_TYPES "${COTIRE_BUILD_TYPE}" _index) - if (_index GREATER -1) - set (_sources ${COTIRE_TARGET_SOURCES}) - set (_sourcesDefinitions ${COTIRE_TARGET_SOURCES_COMPILE_DEFINITIONS_${_upperConfig}}) - else() - if (COTIRE_DEBUG) - message (STATUS "COTIRE_BUILD_TYPE=${COTIRE_BUILD_TYPE} not cotired (${COTIRE_TARGET_CONFIGURATION_TYPES})") - endif() - set (_sources "") - set (_sourcesDefinitions "") - endif() - set (_targetPreUndefs ${COTIRE_TARGET_PRE_UNDEFS}) - set (_targetPostUndefs ${COTIRE_TARGET_POST_UNDEFS}) - set (_sourcesPreUndefs ${COTIRE_TARGET_SOURCES_PRE_UNDEFS}) - set (_sourcesPostUndefs ${COTIRE_TARGET_SOURCES_POST_UNDEFS}) - - if ("${COTIRE_ARGV1}" STREQUAL "unity") - - cotire_select_unity_source_files("${COTIRE_ARGV3}" _sources ${_sources}) - cotire_generate_unity_source( - "${COTIRE_ARGV3}" ${_sources} - LANGUAGE "${COTIRE_TARGET_LANGUAGE}" - DEPENDS "${COTIRE_ARGV0}" "${COTIRE_ARGV2}" - SOURCES_COMPILE_DEFINITIONS ${_sourcesDefinitions} - PRE_UNDEFS ${_targetPreUndefs} - POST_UNDEFS ${_targetPostUndefs} - SOURCES_PRE_UNDEFS ${_sourcesPreUndefs} - SOURCES_POST_UNDEFS ${_sourcesPostUndefs}) - - elseif ("${COTIRE_ARGV1}" STREQUAL "prefix") - - set (_files "") - foreach (_index RANGE 4 ${COTIRE_ARGC}) - if (COTIRE_ARGV${_index}) - list (APPEND _files "${COTIRE_ARGV${_index}}") - endif() - endforeach() - - cotire_generate_prefix_header( - "${COTIRE_ARGV3}" ${_files} - COMPILER_EXECUTABLE "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER}" - COMPILER_ARG1 ${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ARG1} - COMPILER_ID "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ID}" - COMPILER_VERSION "${COTIRE_${COTIRE_TARGET_LANGUAGE}_COMPILER_VERSION}" - LANGUAGE "${COTIRE_TARGET_LANGUAGE}" - DEPENDS "${COTIRE_ARGV0}" "${COTIRE_ARGV4}" ${COTIRE_TARGET_PREFIX_DEPENDS} - IGNORE_PATH "${COTIRE_TARGET_IGNORE_PATH};${COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_PATH}" - INCLUDE_PATH ${COTIRE_TARGET_INCLUDE_PATH} - IGNORE_EXTENSIONS "${CMAKE_${COTIRE_TARGET_LANGUAGE}_SOURCE_FILE_EXTENSIONS};${COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_EXTENSIONS}" - INCLUDE_SYSTEM_FLAG "${COTIRE_INCLUDE_SYSTEM_FLAG}" - INCLUDE_DIRECTORIES ${_includeDirs} - SYSTEM_INCLUDE_DIRECTORIES ${_systemIncludeDirs} - COMPILE_DEFINITIONS ${_compileDefinitions} - COMPILE_FLAGS ${_compileFlags}) - - elseif ("${COTIRE_ARGV1}" STREQUAL "precompile") - - set (_files "") - foreach (_index RANGE 5 ${COTIRE_ARGC}) - if (COTIRE_ARGV${_index}) - list (APPEND _files "${COTIRE_ARGV${_index}}") - endif() - endforeach() - - cotire_precompile_prefix_header( - "${COTIRE_ARGV3}" "${COTIRE_ARGV4}" "${COTIRE_ARGV5}" - COMPILER_EXECUTABLE "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER}" - COMPILER_ARG1 ${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ARG1} - COMPILER_ID "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ID}" - COMPILER_VERSION "${COTIRE_${COTIRE_TARGET_LANGUAGE}_COMPILER_VERSION}" - LANGUAGE "${COTIRE_TARGET_LANGUAGE}" - INCLUDE_SYSTEM_FLAG "${COTIRE_INCLUDE_SYSTEM_FLAG}" - INCLUDE_DIRECTORIES ${_includeDirs} - SYSTEM_INCLUDE_DIRECTORIES ${_systemIncludeDirs} - COMPILE_DEFINITIONS ${_compileDefinitions} - COMPILE_FLAGS ${_compileFlags}) - - elseif ("${COTIRE_ARGV1}" STREQUAL "combine") - - if (COTIRE_TARGET_LANGUAGE) - set (_startIndex 3) - else() - set (_startIndex 2) - endif() - set (_files "") - foreach (_index RANGE ${_startIndex} ${COTIRE_ARGC}) - if (COTIRE_ARGV${_index}) - list (APPEND _files "${COTIRE_ARGV${_index}}") - endif() - endforeach() - if (COTIRE_TARGET_LANGUAGE) - cotire_generate_unity_source(${_files} LANGUAGE "${COTIRE_TARGET_LANGUAGE}") - else() - cotire_generate_unity_source(${_files}) - endif() - - elseif ("${COTIRE_ARGV1}" STREQUAL "cleanup") - - cotire_cleanup("${COTIRE_ARGV2}" "${COTIRE_ARGV3}" "${COTIRE_ARGV4}") - - else() - message (FATAL_ERROR "cotire: unknown command \"${COTIRE_ARGV1}\".") - endif() - -else() - - # cotire is being run in include mode - # set up all variable and property definitions - - unset (COTIRE_C_COMPILER_VERSION CACHE) - unset (COTIRE_CXX_COMPILER_VERSION CACHE) - - if (NOT DEFINED COTIRE_DEBUG_INIT) - if (DEFINED COTIRE_DEBUG) - set (COTIRE_DEBUG_INIT ${COTIRE_DEBUG}) - else() - set (COTIRE_DEBUG_INIT FALSE) - endif() - endif() - option (COTIRE_DEBUG "Enable cotire debugging output?" ${COTIRE_DEBUG_INIT}) - - if (NOT DEFINED COTIRE_VERBOSE_INIT) - if (DEFINED COTIRE_VERBOSE) - set (COTIRE_VERBOSE_INIT ${COTIRE_VERBOSE}) - else() - set (COTIRE_VERBOSE_INIT FALSE) - endif() - endif() - option (COTIRE_VERBOSE "Enable cotire verbose output?" ${COTIRE_VERBOSE_INIT}) - - set (COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_EXTENSIONS "inc;inl;ipp" CACHE STRING - "Ignore headers with the listed file extensions from the generated prefix header.") - - set (COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_PATH "" CACHE STRING - "Ignore headers from these directories when generating the prefix header.") - - set (COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS "m;mm" CACHE STRING - "Ignore sources with the listed file extensions from the generated unity source.") - - set (COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES "3" CACHE STRING - "Minimum number of sources in target required to enable use of precompiled header.") - - 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) - set (COTIRE_PREFIX_HEADER_FILENAME_SUFFIX "_prefix") - endif() - if (NOT COTIRE_UNITY_SOURCE_FILENAME_SUFFIX) - set (COTIRE_UNITY_SOURCE_FILENAME_SUFFIX "_unity") - endif() - if (NOT COTIRE_INTDIR) - set (COTIRE_INTDIR "cotire") - endif() - if (NOT COTIRE_PCH_ALL_TARGET_NAME) - set (COTIRE_PCH_ALL_TARGET_NAME "all_pch") - endif() - if (NOT COTIRE_UNITY_BUILD_ALL_TARGET_NAME) - set (COTIRE_UNITY_BUILD_ALL_TARGET_NAME "all_unity") - endif() - if (NOT COTIRE_CLEAN_ALL_TARGET_NAME) - set (COTIRE_CLEAN_ALL_TARGET_NAME "clean_cotire") - endif() - if (NOT COTIRE_CLEAN_TARGET_SUFFIX) - set (COTIRE_CLEAN_TARGET_SUFFIX "_clean_cotire") - endif() - if (NOT COTIRE_PCH_TARGET_SUFFIX) - set (COTIRE_PCH_TARGET_SUFFIX "_pch") - endif() - if (NOT COTIRE_UNITY_BUILD_TARGET_SUFFIX) - set (COTIRE_UNITY_BUILD_TARGET_SUFFIX "_unity") - endif() - if (NOT DEFINED COTIRE_TARGETS_FOLDER) - set (COTIRE_TARGETS_FOLDER "cotire") - endif() - if (NOT DEFINED COTIRE_UNITY_OUTPUT_DIRECTORY) - if ("${CMAKE_GENERATOR}" MATCHES "Ninja") - # generated Ninja build files do not work if the unity target produces the same output file as the cotired target - set (COTIRE_UNITY_OUTPUT_DIRECTORY "unity") - else() - set (COTIRE_UNITY_OUTPUT_DIRECTORY "") - endif() - endif() - - # define cotire cache variables - - define_property( - CACHED_VARIABLE PROPERTY "COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_PATH" - BRIEF_DOCS "Ignore headers from these directories when generating the prefix header." - FULL_DOCS - "The variable can be set to a semicolon separated list of include directories." - "If a header file is found in one of these directories or sub-directories, it will be excluded from the generated prefix header." - "If not defined, defaults to empty list." - ) - - define_property( - CACHED_VARIABLE PROPERTY "COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_EXTENSIONS" - BRIEF_DOCS "Ignore includes with the listed file extensions from the generated prefix header." - FULL_DOCS - "The variable can be set to a semicolon separated list of file extensions." - "If a header file extension matches one in the list, it will be excluded from the generated prefix header." - "Includes with an extension in CMAKE__SOURCE_FILE_EXTENSIONS are always ignored." - "If not defined, defaults to inc;inl;ipp." - ) - - define_property( - CACHED_VARIABLE PROPERTY "COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS" - BRIEF_DOCS "Exclude sources with the listed file extensions from the generated unity source." - FULL_DOCS - "The variable can be set to a semicolon separated list of file extensions." - "If a source file extension matches one in the list, it will be excluded from the generated unity source file." - "Source files with an extension in CMAKE__IGNORE_EXTENSIONS are always excluded." - "If not defined, defaults to m;mm." - ) - - define_property( - CACHED_VARIABLE PROPERTY "COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES" - BRIEF_DOCS "Minimum number of sources in target required to enable use of precompiled header." - FULL_DOCS - "The variable can be set to an integer > 0." - "If a target contains less than that number of source files, cotire will not enable the use of the precompiled header for the target." - "If not defined, defaults to 3." - ) - - define_property( - 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." - "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." - "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 \"-j\" for the generators Visual Studio, JOM or Ninja. Defaults to 0 otherwise." - ) - - # define cotire directory properties - - define_property( - DIRECTORY PROPERTY "COTIRE_ENABLE_PRECOMPILED_HEADER" - BRIEF_DOCS "Modify build command of cotired targets added in this directory to make use of the generated precompiled header." - FULL_DOCS - "See target property COTIRE_ENABLE_PRECOMPILED_HEADER." - ) - - define_property( - DIRECTORY PROPERTY "COTIRE_ADD_UNITY_BUILD" - BRIEF_DOCS "Add a new target that performs a unity build for cotired targets added in this directory." - FULL_DOCS - "See target property COTIRE_ADD_UNITY_BUILD." - ) - - define_property( - DIRECTORY PROPERTY "COTIRE_ADD_CLEAN" - BRIEF_DOCS "Add a new target that cleans all cotire generated files for cotired targets added in this directory." - FULL_DOCS - "See target property COTIRE_ADD_CLEAN." - ) - - define_property( - DIRECTORY PROPERTY "COTIRE_PREFIX_HEADER_IGNORE_PATH" - BRIEF_DOCS "Ignore headers from these directories when generating the prefix header." - FULL_DOCS - "See target property COTIRE_PREFIX_HEADER_IGNORE_PATH." - ) - - define_property( - DIRECTORY PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PATH" - BRIEF_DOCS "Honor headers from these directories when generating the prefix header." - FULL_DOCS - "See target property COTIRE_PREFIX_HEADER_INCLUDE_PATH." - ) - - define_property( - DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS" - BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of each source file." - FULL_DOCS - "See target property COTIRE_UNITY_SOURCE_PRE_UNDEFS." - ) - - define_property( - DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS" - BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of each source file." - FULL_DOCS - "See target property COTIRE_UNITY_SOURCE_POST_UNDEFS." - ) - - define_property( - DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES" - BRIEF_DOCS "Maximum number of source files to include in a single unity source file." - FULL_DOCS - "See target property COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES." - ) - - define_property( - DIRECTORY PROPERTY "COTIRE_UNITY_LINK_LIBRARIES_INIT" - BRIEF_DOCS "Define strategy for setting up the unity target's link libraries." - FULL_DOCS - "See target property COTIRE_UNITY_LINK_LIBRARIES_INIT." - ) - - # define cotire target properties - - define_property( - TARGET PROPERTY "COTIRE_ENABLE_PRECOMPILED_HEADER" INHERITED - BRIEF_DOCS "Modify this target's build command to make use of the generated precompiled header." - FULL_DOCS - "If this property is set to TRUE, cotire will modify the build command to make use of the generated precompiled header." - "Irrespective of the value of this property, cotire will setup custom commands to generate the unity source and prefix header for the target." - "For makefile based generators cotire will also set up a custom target to manually invoke the generation of the precompiled header." - "The target name will be set to this target's name with the suffix _pch appended." - "Inherited from directory." - "Defaults to TRUE." - ) - - define_property( - TARGET PROPERTY "COTIRE_ADD_UNITY_BUILD" INHERITED - BRIEF_DOCS "Add a new target that performs a unity build for this target." - FULL_DOCS - "If this property is set to TRUE, cotire creates a new target of the same type that uses the generated unity source file instead of the target sources." - "Most of the relevant target properties will be copied from this target to the new unity build target." - "Target dependencies and linked libraries have to be manually set up for the new unity build target." - "The unity target name will be set to this target's name with the suffix _unity appended." - "Inherited from directory." - "Defaults to TRUE." - ) - - define_property( - TARGET PROPERTY "COTIRE_ADD_CLEAN" INHERITED - BRIEF_DOCS "Add a new target that cleans all cotire generated files for this target." - FULL_DOCS - "If this property is set to TRUE, cotire creates a new target that clean all files (unity source, prefix header, precompiled header)." - "The clean target name will be set to this target's name with the suffix _clean_cotire appended." - "Inherited from directory." - "Defaults to FALSE." - ) - - define_property( - TARGET PROPERTY "COTIRE_PREFIX_HEADER_IGNORE_PATH" INHERITED - BRIEF_DOCS "Ignore headers from these directories when generating the prefix header." - FULL_DOCS - "The property can be set to a list of directories." - "If a header file is found in one of these directories or sub-directories, it will be excluded from the generated prefix header." - "Inherited from directory." - "If not set, this property is initialized to \${CMAKE_SOURCE_DIR};\${CMAKE_BINARY_DIR}." - ) - - define_property( - TARGET PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PATH" INHERITED - BRIEF_DOCS "Honor headers from these directories when generating the prefix header." - FULL_DOCS - "The property can be set to a list of directories." - "If a header file is found in one of these directories or sub-directories, it will be included in the generated prefix header." - "If a header file is both selected by COTIRE_PREFIX_HEADER_IGNORE_PATH and COTIRE_PREFIX_HEADER_INCLUDE_PATH," - "the option which yields the closer relative path match wins." - "Inherited from directory." - "If not set, this property is initialized to the empty list." - ) - - define_property( - TARGET PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS" INHERITED - BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of each target source file." - FULL_DOCS - "This may be set to a semicolon-separated list of preprocessor symbols." - "cotire will add corresponding #undef directives to the generated unit source file before each target source file." - "Inherited from directory." - "Defaults to empty string." - ) - - define_property( - TARGET PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS" INHERITED - BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of each target source file." - FULL_DOCS - "This may be set to a semicolon-separated list of preprocessor symbols." - "cotire will add corresponding #undef directives to the generated unit source file after each target source file." - "Inherited from directory." - "Defaults to empty string." - ) - - define_property( - TARGET PROPERTY "COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES" INHERITED - 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." - "If a target contains more than that number of source files, cotire will create multiple unity build files for it." - "If not set, cotire will only create a single unity source file." - "Inherited from directory." - "Defaults to empty." - ) - - define_property( - TARGET PROPERTY "COTIRE__UNITY_SOURCE_INIT" - BRIEF_DOCS "User provided unity source file to be used instead of the automatically generated one." - FULL_DOCS - "If set, cotire will only add the given file(s) to the generated unity source file." - "If not set, cotire will add all the target source files to the generated unity source file." - "The property can be set to a user provided unity source file." - "Defaults to empty." - ) - - define_property( - TARGET PROPERTY "COTIRE__PREFIX_HEADER_INIT" - BRIEF_DOCS "User provided prefix header file to be used instead of the automatically generated one." - FULL_DOCS - "If set, cotire will add the given header file(s) to the generated prefix header file." - "If not set, cotire will generate a prefix header by tracking the header files included by the unity source file." - "The property can be set to a user provided prefix header file (e.g., stdafx.h)." - "Defaults to empty." - ) - - define_property( - TARGET PROPERTY "COTIRE_UNITY_LINK_LIBRARIES_INIT" INHERITED - BRIEF_DOCS "Define strategy for setting up unity target's link libraries." - FULL_DOCS - "If this property is empty, the generated unity target's link libraries have to be set up manually." - "If this property is set to COPY, the unity target's link libraries will be copied from this target." - "If this property is set to COPY_UNITY, the unity target's link libraries will be copied from this target with considering existing unity targets." - "Inherited from directory." - "Defaults to empty." - ) - - define_property( - TARGET PROPERTY "COTIRE__UNITY_SOURCE" - BRIEF_DOCS "Read-only property. The generated unity source file(s)." - FULL_DOCS - "cotire sets this property to the path of the generated single computation unit source file for the target." - "Defaults to empty string." - ) - - define_property( - TARGET PROPERTY "COTIRE__PREFIX_HEADER" - BRIEF_DOCS "Read-only property. The generated prefix header file." - FULL_DOCS - "cotire sets this property to the full path of the generated language prefix header for the target." - "Defaults to empty string." - ) - - define_property( - TARGET PROPERTY "COTIRE__PRECOMPILED_HEADER" - BRIEF_DOCS "Read-only property. The generated precompiled header file." - FULL_DOCS - "cotire sets this property to the full path of the generated language precompiled header binary for the target." - "Defaults to empty string." - ) - - define_property( - TARGET PROPERTY "COTIRE_UNITY_TARGET_NAME" - BRIEF_DOCS "The name of the generated unity build target corresponding to this target." - FULL_DOCS - "This property can be set to the desired name of the unity target that will be created by cotire." - "If not set, the unity target name will be set to this target's name with the suffix _unity appended." - "After this target has been processed by cotire, the property is set to the actual name of the generated unity target." - "Defaults to empty string." - ) - - # define cotire source properties - - define_property( - SOURCE PROPERTY "COTIRE_EXCLUDED" - BRIEF_DOCS "Do not modify source file's build command." - FULL_DOCS - "If this property is set to TRUE, the source file's build command will not be modified to make use of the precompiled header." - "The source file will also be excluded from the generated unity source file." - "Source files that have their COMPILE_FLAGS property set will be excluded by default." - "Defaults to FALSE." - ) - - define_property( - SOURCE PROPERTY "COTIRE_DEPENDENCY" - BRIEF_DOCS "Add this source file to dependencies of the automatically generated prefix header file." - FULL_DOCS - "If this property is set to TRUE, the source file is added to dependencies of the generated prefix header file." - "If the file is modified, cotire will re-generate the prefix header source upon build." - "Defaults to FALSE." - ) - - define_property( - SOURCE PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS" - BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of this source file." - FULL_DOCS - "This may be set to a semicolon-separated list of preprocessor symbols." - "cotire will add corresponding #undef directives to the generated unit source file before this file is included." - "Defaults to empty string." - ) - - define_property( - SOURCE PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS" - BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of this source file." - FULL_DOCS - "This may be set to a semicolon-separated list of preprocessor symbols." - "cotire will add corresponding #undef directives to the generated unit source file after this file is included." - "Defaults to empty string." - ) - - define_property( - SOURCE PROPERTY "COTIRE_START_NEW_UNITY_SOURCE" - BRIEF_DOCS "Start a new unity source file which includes this source file as the first one." - FULL_DOCS - "If this property is set to TRUE, cotire will complete the current unity file and start a new one." - "The new unity source file will include this source file as the first one." - "This property essentially works as a separator for unity source files." - "Defaults to FALSE." - ) - - define_property( - SOURCE PROPERTY "COTIRE_TARGET" - BRIEF_DOCS "Read-only property. Mark this source file as cotired for the given target." - FULL_DOCS - "cotire sets this property to the name of target, that the source file's build command has been altered for." - "Defaults to empty string." - ) - - message (STATUS "cotire ${COTIRE_CMAKE_MODULE_VERSION} loaded.") - -endif() diff --git a/CMakeLists.txt b/CMakeLists.txt index 05c6270c..a0bf1007 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,6 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/CMake") option(DISABLE_WERROR "Build without -Werror" FALSE) option(ENABLE_SIGNALS "Build with UNIX signals" TRUE) option(ENABLE_DECODE "Build with libsigrokdecode" TRUE) -option(ENABLE_COTIRE "Enable cotire" FALSE) option(ENABLE_TESTS "Enable unit tests" FALSE) option(STATIC_PKGDEPS_LIBS "Statically link to (pkg-config) libraries" FALSE) option(FORCE_QT4 "Force use of Qt4 even if Qt5 is available" FALSE) @@ -142,15 +141,15 @@ set(pulseview_SOURCES pv/application.cpp pv/devicemanager.cpp pv/mainwindow.cpp - pv/sigsession.cpp + pv/session.cpp pv/storesession.cpp pv/util.cpp pv/data/analog.cpp - pv/data/analogsnapshot.cpp + pv/data/analogsegment.cpp pv/data/logic.cpp - pv/data/logicsnapshot.cpp + pv/data/logicsegment.cpp pv/data/signaldata.cpp - pv/data/snapshot.cpp + pv/data/segment.cpp pv/dialogs/about.cpp pv/dialogs/connect.cpp pv/dialogs/storeprogress.cpp @@ -174,6 +173,7 @@ set(pulseview_SOURCES pv/view/logicsignal.cpp pv/view/rowitem.cpp pv/view/rowitemowner.cpp + pv/view/rowitempaintparams.cpp pv/view/ruler.cpp pv/view/selectableitem.cpp pv/view/signal.cpp @@ -194,7 +194,7 @@ set(pulseview_SOURCES # This list includes only QObject derived class headers. set(pulseview_HEADERS pv/mainwindow.hpp - pv/sigsession.hpp + pv/session.hpp pv/storesession.hpp pv/dialogs/about.hpp pv/dialogs/connect.hpp @@ -385,11 +385,6 @@ if(WIN32) set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-mwindows") endif() -if(ENABLE_COTIRE) - include(cotire) - cotire(${PROJECT_NAME}) -endif() - #=============================================================================== #= Installation #------------------------------------------------------------------------------- diff --git a/NEWS b/NEWS index 696f13ac..4615e0ad 100644 --- a/NEWS +++ b/NEWS @@ -65,7 +65,7 @@ * Fix an analog data channel interleaving issue (bug #279). * Only show the sample count widget if needed (i.e., hide it for scopes). * SweepTimingWidget: Show a 1-2-5 based list for samplerate and samplecount. - * Fixed a unit test issue with AnalogSnapshotTest (bug #286). + * Fixed a unit test issue with AnalogSegmentTest (bug #286). * Add an extra sample to edges to make the end sample visible (bug #280). * Fix an issue with decoder errors being shown even after the error was fixed. * Add support for SR_CONF_LIMIT_SAMPLES (device-specific limits) (bug #74). diff --git a/pv/data/analog.cpp b/pv/data/analog.cpp index 30cf5013..10a50028 100644 --- a/pv/data/analog.cpp +++ b/pv/data/analog.cpp @@ -21,11 +21,12 @@ #include #include "analog.hpp" -#include "analogsnapshot.hpp" +#include "analogsegment.hpp" using std::deque; using std::max; using std::shared_ptr; +using std::vector; namespace pv { namespace data { @@ -35,25 +36,127 @@ Analog::Analog() : { } -void Analog::push_snapshot(shared_ptr &snapshot) +void Analog::push_segment(shared_ptr &segment) { - snapshots_.push_front(snapshot); + segments_.push_front(segment); } -deque< shared_ptr >& Analog::get_snapshots() +const deque< shared_ptr >& Analog::analog_segments() const { - return snapshots_; + return segments_; +} + +vector< shared_ptr > Analog::segments() const +{ + return vector< shared_ptr >( + segments_.begin(), segments_.end()); } void Analog::clear() { - snapshots_.clear(); + segments_.clear(); +} + +void Analog::remove(double start_time, double end_time) +{ + if (!segments_.size()) + return; + + if (start_time < 0) + start_time = 0; + if (end_time < 0) + end_time = 0; + if (start_time >= end_time) + return; + + erase(start_time, end_time); +} + +void Analog::crop(double start_time, double end_time) +{ + if (!segments_.size()) + return; + + if (start_time < 0) + start_time = 0; + if (end_time < 0) + end_time = 0; + if (start_time >= end_time) + return; + + double total_time = 0; + for (auto segment : segments_) { + double segment_time = segment->time(); + total_time += segment_time; + } + + if (end_time < total_time) + erase(end_time, total_time); + erase(0, start_time); +} + +void Analog::erase(double start_time, double end_time) +{ + double segment_time = 0; + auto iter = segments_.begin(); + + // find start + for (; iter != segments_.end(); ++iter) { + segment_time = (*iter)->time(); + if (start_time < segment_time) + break; + + start_time -= segment_time; + end_time -= segment_time; + } + + // end is also in this segment? + if (end_time < segment_time) { + iter = erase(iter, start_time, end_time); + return; + } + + // end is not in this segment, remove initial samples + iter = erase(iter, start_time, segment_time); + end_time -= segment_time; + + // remove frames till we reach end segment + for (; iter != segments_.end();) { + segment_time = (*iter)->time(); + if (end_time < segment_time) + break; + + iter = segments_.erase(iter); + end_time -= segment_time; + } + + // remove remaining samples + if (iter != segments_.end()) + iter = erase(iter, 0, end_time); +} + +Analog::segment_iterator Analog::erase(Analog::segment_iterator iter, + double start_time, double end_time) +{ + uint64_t sample_count = (*iter)->get_sample_count(); + uint64_t samplerate = (*iter)->samplerate(); + + int64_t start_sample = start_time * samplerate; + int64_t end_sample = end_time * samplerate; + int64_t length = end_sample - start_sample; + + // erase entire segment? + if (length == (int64_t) sample_count) + return segments_.erase(iter); + + (*iter)->remove_samples(start_sample, end_sample); + return ++iter; } uint64_t Analog::get_max_sample_count() const { uint64_t l = 0; - for (const std::shared_ptr s : snapshots_) { + for (const std::shared_ptr s : segments_) { assert(s); l = max(l, s->get_sample_count()); } diff --git a/pv/data/analog.hpp b/pv/data/analog.hpp index cfc964e1..d231432b 100644 --- a/pv/data/analog.hpp +++ b/pv/data/analog.hpp @@ -29,25 +29,36 @@ namespace pv { namespace data { -class AnalogSnapshot; +class AnalogSegment; class Analog : public SignalData { public: Analog(); - void push_snapshot( - std::shared_ptr &snapshot); + void push_segment( + std::shared_ptr &segment); - std::deque< std::shared_ptr >& - get_snapshots(); + const std::deque< std::shared_ptr >& + analog_segments() const; + + std::vector< std::shared_ptr > segments() const; void clear(); + void remove(double start_time, double end_time); + void crop(double start_time, double end_time); uint64_t get_max_sample_count() const; private: - std::deque< std::shared_ptr > snapshots_; + typedef std::deque< std::shared_ptr >::iterator segment_iterator; + + void erase(double start_time, double end_time); + segment_iterator erase(segment_iterator iter, + double start_time, double end_time); + +private: + std::deque< std::shared_ptr > segments_; }; } // namespace data diff --git a/pv/data/analogsnapshot.cpp b/pv/data/analogsegment.cpp similarity index 80% rename from pv/data/analogsnapshot.cpp rename to pv/data/analogsegment.cpp index 589b1aa4..459df6ac 100644 --- a/pv/data/analogsnapshot.cpp +++ b/pv/data/analogsegment.cpp @@ -27,7 +27,7 @@ #include -#include "analogsnapshot.hpp" +#include "analogsegment.hpp" using std::lock_guard; using std::recursive_mutex; @@ -39,14 +39,15 @@ using std::min_element; namespace pv { namespace data { -const int AnalogSnapshot::EnvelopeScalePower = 4; -const int AnalogSnapshot::EnvelopeScaleFactor = 1 << EnvelopeScalePower; -const float AnalogSnapshot::LogEnvelopeScaleFactor = +const int AnalogSegment::EnvelopeScalePower = 4; +const int AnalogSegment::EnvelopeScaleFactor = 1 << EnvelopeScalePower; +const float AnalogSegment::LogEnvelopeScaleFactor = logf(EnvelopeScaleFactor); -const uint64_t AnalogSnapshot::EnvelopeDataUnit = 64*1024; // bytes +const uint64_t AnalogSegment::EnvelopeDataUnit = 64*1024; // bytes -AnalogSnapshot::AnalogSnapshot(const uint64_t expected_num_samples) : - Snapshot(sizeof(float)) +AnalogSegment::AnalogSegment( + uint64_t samplerate, const uint64_t expected_num_samples) : + Segment(samplerate, sizeof(float)) { set_capacity(expected_num_samples); @@ -54,14 +55,14 @@ AnalogSnapshot::AnalogSnapshot(const uint64_t expected_num_samples) : memset(envelope_levels_, 0, sizeof(envelope_levels_)); } -AnalogSnapshot::~AnalogSnapshot() +AnalogSegment::~AnalogSegment() { lock_guard lock(mutex_); for (Envelope &e : envelope_levels_) free(e.samples); } -void AnalogSnapshot::append_interleaved_samples(const float *data, +void AnalogSegment::append_interleaved_samples(const float *data, size_t sample_count, size_t stride) { assert(unit_size_ == sizeof(float)); @@ -84,7 +85,7 @@ void AnalogSnapshot::append_interleaved_samples(const float *data, append_payload_to_envelope_levels(); } -const float* AnalogSnapshot::get_samples( +const float* AnalogSegment::get_samples( int64_t start_sample, int64_t end_sample) const { assert(start_sample >= 0); @@ -101,7 +102,26 @@ const float* AnalogSnapshot::get_samples( return data; } -void AnalogSnapshot::get_envelope_section(EnvelopeSection &s, +void AnalogSegment::remove_samples(int64_t start_sample, int64_t end_sample) +{ + assert(start_sample >= 0); + assert(start_sample <= (int64_t)sample_count_); + assert(end_sample >= 0); + assert(end_sample <= (int64_t)sample_count_); + + lock_guard lock(mutex_); + + memset(envelope_levels_, 0, sizeof(envelope_levels_)); + + auto start_iter = data_.begin() + start_sample * sizeof(float); + auto end_iter = data_.begin() + end_sample * sizeof(float); + data_.erase(start_iter, end_iter); + sample_count_ -= end_sample - start_sample; + + append_payload_to_envelope_levels(); +} + +void AnalogSegment::get_envelope_section(EnvelopeSection &s, uint64_t start, uint64_t end, float min_length) const { assert(end <= get_sample_count()); @@ -125,7 +145,7 @@ void AnalogSnapshot::get_envelope_section(EnvelopeSection &s, s.length * sizeof(EnvelopeSample)); } -void AnalogSnapshot::reallocate_envelope(Envelope &e) +void AnalogSegment::reallocate_envelope(Envelope &e) { const uint64_t new_data_length = ((e.length + EnvelopeDataUnit - 1) / EnvelopeDataUnit) * EnvelopeDataUnit; @@ -137,7 +157,7 @@ void AnalogSnapshot::reallocate_envelope(Envelope &e) } } -void AnalogSnapshot::append_payload_to_envelope_levels() +void AnalogSegment::append_payload_to_envelope_levels() { Envelope &e0 = envelope_levels_[0]; uint64_t prev_length; diff --git a/pv/data/analogsnapshot.hpp b/pv/data/analogsegment.hpp similarity index 87% rename from pv/data/analogsnapshot.hpp rename to pv/data/analogsegment.hpp index 3c6f99c2..c35c4e0a 100644 --- a/pv/data/analogsnapshot.hpp +++ b/pv/data/analogsegment.hpp @@ -21,19 +21,19 @@ #ifndef PULSEVIEW_PV_DATA_ANALOGSNAPSHOT_H #define PULSEVIEW_PV_DATA_ANALOGSNAPSHOT_H -#include "snapshot.hpp" +#include "segment.hpp" #include #include -namespace AnalogSnapshotTest { +namespace AnalogSegmentTest { struct Basic; } namespace pv { namespace data { -class AnalogSnapshot : public Snapshot +class AnalogSegment : public Segment { public: struct EnvelopeSample @@ -66,15 +66,16 @@ class AnalogSnapshot : public Snapshot static const uint64_t EnvelopeDataUnit; public: - AnalogSnapshot(uint64_t expected_num_samples = 0); + AnalogSegment(uint64_t samplerate, uint64_t expected_num_samples = 0); - virtual ~AnalogSnapshot(); + virtual ~AnalogSegment(); void append_interleaved_samples(const float *data, size_t sample_count, size_t stride); const float* get_samples(int64_t start_sample, int64_t end_sample) const; + void remove_samples(int64_t start_sample, int64_t end_sample); void get_envelope_section(EnvelopeSection &s, uint64_t start, uint64_t end, float min_length) const; @@ -87,7 +88,7 @@ class AnalogSnapshot : public Snapshot private: struct Envelope envelope_levels_[ScaleStepCount]; - friend struct AnalogSnapshotTest::Basic; + friend struct AnalogSegmentTest::Basic; }; } // namespace data diff --git a/pv/data/decoderstack.cpp b/pv/data/decoderstack.cpp index da831e3b..482b1564 100644 --- a/pv/data/decoderstack.cpp +++ b/pv/data/decoderstack.cpp @@ -27,10 +27,10 @@ #include "decoderstack.hpp" #include -#include +#include #include #include -#include +#include #include using std::lock_guard; @@ -62,6 +62,8 @@ mutex DecoderStack::global_decode_mutex_; DecoderStack::DecoderStack(pv::Session &session, const srd_decoder *const dec) : session_(session), + start_time_(0), + samplerate_(0), sample_count_(0), frame_complete_(false), samples_decoded_(0) @@ -112,6 +114,16 @@ void DecoderStack::remove(int index) stack_.erase(iter); } +double DecoderStack::samplerate() const +{ + return samplerate_; +} + +double DecoderStack::start_time() const +{ + return start_time_; +} + int64_t DecoderStack::samples_decoded() const { lock_guard decode_lock(output_mutex_); @@ -233,7 +245,7 @@ void DecoderStack::begin_decode() // We get the logic data of the first channel in the list. // This works because we are currently assuming all - // LogicSignals have the same data/snapshot + // LogicSignals have the same data/segment for (const shared_ptr &dec : stack_) if (dec && !dec->channels().empty() && ((logic_signal = (*dec->channels().begin()).second)) && @@ -243,16 +255,16 @@ void DecoderStack::begin_decode() if (!data) return; - // Check we have a snapshot of data - const deque< shared_ptr > &snapshots = - data->get_snapshots(); - if (snapshots.empty()) + // Check we have a segment of data + const deque< shared_ptr > &segments = + data->logic_segments(); + if (segments.empty()) return; - snapshot_ = snapshots.front(); + segment_ = segments.front(); // Get the samplerate and start time - start_time_ = data->get_start_time(); - samplerate_ = data->samplerate(); + start_time_ = segment_->start_time(); + samplerate_ = segment_->samplerate(); if (samplerate_ == 0.0) samplerate_ = 1.0; @@ -289,7 +301,7 @@ void DecoderStack::decode_data( uint8_t chunk[DecodeChunkLength]; const unsigned int chunk_sample_count = - DecodeChunkLength / snapshot_->unit_size(); + DecodeChunkLength / segment_->unit_size(); for (int64_t i = 0; !interrupt_ && i < sample_count; i += chunk_sample_count) @@ -298,7 +310,7 @@ void DecoderStack::decode_data( const int64_t chunk_end = min( i + chunk_sample_count, sample_count); - snapshot_->get_samples(chunk, i, chunk_end); + segment_->get_samples(chunk, i, chunk_end); if (srd_session_send(session, i, i + sample_count, chunk, (chunk_end - i) * unit_size) != SRD_OK) { @@ -324,14 +336,14 @@ void DecoderStack::decode_proc() srd_session *session; srd_decoder_inst *prev_di = NULL; - assert(snapshot_); + assert(segment_); // Create the session srd_session_new(&session); assert(session); // Create the decoders - const unsigned int unit_size = snapshot_->unit_size(); + const unsigned int unit_size = segment_->unit_size(); for (const shared_ptr &dec : stack_) { @@ -353,7 +365,7 @@ void DecoderStack::decode_proc() // Get the intial sample count { unique_lock input_lock(input_mutex_); - sample_count = sample_count_ = snapshot_->get_sample_count(); + sample_count = sample_count_ = segment_->get_sample_count(); } // Start the session @@ -424,8 +436,8 @@ void DecoderStack::on_data_received() { { unique_lock lock(input_mutex_); - if (snapshot_) - sample_count_ = snapshot_->get_sample_count(); + if (segment_) + sample_count_ = segment_->get_sample_count(); } input_cond_.notify_one(); } @@ -434,7 +446,7 @@ void DecoderStack::on_frame_ended() { { unique_lock lock(input_mutex_); - if (snapshot_) + if (segment_) frame_complete_ = true; } input_cond_.notify_one(); diff --git a/pv/data/decoderstack.hpp b/pv/data/decoderstack.hpp index e8aeed10..38310990 100644 --- a/pv/data/decoderstack.hpp +++ b/pv/data/decoderstack.hpp @@ -58,7 +58,7 @@ class LogicSignal; namespace data { -class LogicSnapshot; +class LogicSegment; namespace decode { class Annotation; @@ -67,7 +67,7 @@ class Decoder; class Logic; -class DecoderStack : public QObject, public SignalData +class DecoderStack : public QObject { Q_OBJECT @@ -87,6 +87,10 @@ class DecoderStack : public QObject, public SignalData void push(std::shared_ptr decoder); void remove(int index); + double samplerate() const; + + double start_time() const; + int64_t samples_decoded() const; std::vector get_visible_rows() const; @@ -131,6 +135,9 @@ private Q_SLOTS: private: pv::Session &session_; + double start_time_; + double samplerate_; + /** * This mutex prevents more than one decode operation occuring * concurrently. @@ -141,7 +148,7 @@ private Q_SLOTS: std::list< std::shared_ptr > stack_; - std::shared_ptr snapshot_; + std::shared_ptr segment_; mutable std::mutex input_mutex_; mutable std::condition_variable input_cond_; diff --git a/pv/data/logic.cpp b/pv/data/logic.cpp index 8f1d294d..3b309e5d 100644 --- a/pv/data/logic.cpp +++ b/pv/data/logic.cpp @@ -21,11 +21,12 @@ #include #include "logic.hpp" -#include "logicsnapshot.hpp" +#include "logicsegment.hpp" using std::deque; using std::max; using std::shared_ptr; +using std::vector; namespace pv { namespace data { @@ -42,26 +43,128 @@ int Logic::get_num_channels() const return num_channels_; } -void Logic::push_snapshot( - shared_ptr &snapshot) +void Logic::push_segment( + shared_ptr &segment) { - snapshots_.push_front(snapshot); + segments_.push_front(segment); } -deque< shared_ptr >& Logic::get_snapshots() +const deque< shared_ptr >& Logic::logic_segments() const { - return snapshots_; + return segments_; +} + +vector< shared_ptr > Logic::segments() const +{ + return vector< shared_ptr >( + segments_.begin(), segments_.end()); } void Logic::clear() { - snapshots_.clear(); + segments_.clear(); +} + +void Logic::remove(double start_time, double end_time) +{ + if (!segments_.size()) + return; + + if (start_time < 0) + start_time = 0; + if (end_time < 0) + end_time = 0; + if (start_time >= end_time) + return; + + erase(start_time, end_time); +} + +void Logic::crop(double start_time, double end_time) +{ + if (!segments_.size()) + return; + + if (start_time < 0) + start_time = 0; + if (end_time < 0) + end_time = 0; + if (start_time >= end_time) + return; + + double total_time = 0; + for (auto segment : segments_) { + double segment_time = segment->time(); + total_time += segment_time; + } + + if (end_time < total_time) + erase(end_time, total_time); + erase(0, start_time); +} + +void Logic::erase(double start_time, double end_time) +{ + double segment_time = 0; + auto iter = segments_.begin(); + + // find start + for (; iter != segments_.end(); ++iter) { + segment_time = (*iter)->time(); + if (start_time < segment_time) + break; + + start_time -= segment_time; + end_time -= segment_time; + } + + // end is also in this segment? + if (end_time < segment_time) { + iter = erase(iter, start_time, end_time); + return; + } + + // end is not in this segment, remove initial samples + iter = erase(iter, start_time, segment_time); + end_time -= segment_time; + + // remove frames till we reach end segment + for (; iter != segments_.end();) { + segment_time = (*iter)->time(); + if (end_time < segment_time) + break; + + iter = segments_.erase(iter); + end_time -= segment_time; + } + + // remove remaining samples + if (iter != segments_.end()) + iter = erase(iter, 0, end_time); +} + +Logic::segment_iterator Logic::erase(Logic::segment_iterator iter, + double start_time, double end_time) +{ + uint64_t sample_count = (*iter)->get_sample_count(); + uint64_t samplerate = (*iter)->samplerate(); + + int64_t start_sample = start_time * samplerate; + int64_t end_sample = end_time * samplerate; + int64_t length = end_sample - start_sample; + + // erase entire segment? + if (length == (int64_t) sample_count) + return segments_.erase(iter); + + (*iter)->remove_samples(start_sample, end_sample); + return ++iter; } uint64_t Logic::get_max_sample_count() const { uint64_t l = 0; - for (std::shared_ptr s : snapshots_) { + for (std::shared_ptr s : segments_) { assert(s); l = max(l, s->get_sample_count()); } diff --git a/pv/data/logic.hpp b/pv/data/logic.hpp index 51e12cb9..10face17 100644 --- a/pv/data/logic.hpp +++ b/pv/data/logic.hpp @@ -24,12 +24,11 @@ #include "signaldata.hpp" #include -#include namespace pv { namespace data { -class LogicSnapshot; +class LogicSegment; class Logic : public SignalData { @@ -38,19 +37,30 @@ class Logic : public SignalData int get_num_channels() const; - void push_snapshot( - std::shared_ptr &snapshot); + void push_segment( + std::shared_ptr &segment); - std::deque< std::shared_ptr >& - get_snapshots(); + const std::deque< std::shared_ptr >& + logic_segments() const; + + std::vector< std::shared_ptr > segments() const; void clear(); + void remove(double start_time, double end_time); + void crop(double start_time, double end_time); uint64_t get_max_sample_count() const; +private: + typedef std::deque< std::shared_ptr >::iterator segment_iterator; + + void erase(double start_time, double end_time); + segment_iterator erase(segment_iterator iter, + double start_time, double end_time); + private: const unsigned int num_channels_; - std::deque< std::shared_ptr > snapshots_; + std::deque< std::shared_ptr > segments_; }; } // namespace data diff --git a/pv/data/logicsnapshot.cpp b/pv/data/logicsegment.cpp similarity index 87% rename from pv/data/logicsnapshot.cpp rename to pv/data/logicsegment.cpp index 82d90074..31bb2ac6 100644 --- a/pv/data/logicsnapshot.cpp +++ b/pv/data/logicsegment.cpp @@ -25,7 +25,7 @@ #include #include -#include "logicsnapshot.hpp" +#include "logicsegment.hpp" #include @@ -41,14 +41,14 @@ using sigrok::Logic; namespace pv { namespace data { -const int LogicSnapshot::MipMapScalePower = 4; -const int LogicSnapshot::MipMapScaleFactor = 1 << MipMapScalePower; -const float LogicSnapshot::LogMipMapScaleFactor = logf(MipMapScaleFactor); -const uint64_t LogicSnapshot::MipMapDataUnit = 64*1024; // bytes +const int LogicSegment::MipMapScalePower = 4; +const int LogicSegment::MipMapScaleFactor = 1 << MipMapScalePower; +const float LogicSegment::LogMipMapScaleFactor = logf(MipMapScaleFactor); +const uint64_t LogicSegment::MipMapDataUnit = 64*1024; // bytes -LogicSnapshot::LogicSnapshot(shared_ptr logic, +LogicSegment::LogicSegment(shared_ptr logic, uint64_t samplerate, const uint64_t expected_num_samples) : - Snapshot(logic->unit_size()), + Segment(samplerate, logic->unit_size()), last_append_sample_(0) { set_capacity(expected_num_samples); @@ -58,14 +58,14 @@ LogicSnapshot::LogicSnapshot(shared_ptr logic, append_payload(logic); } -LogicSnapshot::~LogicSnapshot() +LogicSegment::~LogicSegment() { lock_guard lock(mutex_); for (MipMapLevel &l : mip_map_) free(l.data); } -uint64_t LogicSnapshot::unpack_sample(const uint8_t *ptr) const +uint64_t LogicSegment::unpack_sample(const uint8_t *ptr) const { #ifdef HAVE_UNALIGNED_LITTLE_ENDIAN_ACCESS return *(uint64_t*)ptr; @@ -103,7 +103,7 @@ uint64_t LogicSnapshot::unpack_sample(const uint8_t *ptr) const #endif } -void LogicSnapshot::pack_sample(uint8_t *ptr, uint64_t value) +void LogicSegment::pack_sample(uint8_t *ptr, uint64_t value) { #ifdef HAVE_UNALIGNED_LITTLE_ENDIAN_ACCESS *(uint64_t*)ptr = value; @@ -139,7 +139,7 @@ void LogicSnapshot::pack_sample(uint8_t *ptr, uint64_t value) #endif } -void LogicSnapshot::append_payload(shared_ptr logic) +void LogicSegment::append_payload(shared_ptr logic) { assert(unit_size_ == logic->unit_size()); assert((logic->data_length() % unit_size_) == 0); @@ -153,7 +153,7 @@ void LogicSnapshot::append_payload(shared_ptr logic) append_payload_to_mipmap(); } -void LogicSnapshot::get_samples(uint8_t *const data, +void LogicSegment::get_samples(uint8_t *const data, int64_t start_sample, int64_t end_sample) const { assert(data); @@ -169,7 +169,26 @@ void LogicSnapshot::get_samples(uint8_t *const data, memcpy(data, (const uint8_t*)data_.data() + start_sample * unit_size_, size); } -void LogicSnapshot::reallocate_mipmap_level(MipMapLevel &m) +void LogicSegment::remove_samples(int64_t start_sample, int64_t end_sample) +{ + assert(start_sample >= 0); + assert(start_sample <= (int64_t)sample_count_); + assert(end_sample >= 0); + assert(end_sample <= (int64_t)sample_count_); + + lock_guard lock(mutex_); + + memset(mip_map_, 0, sizeof(mip_map_)); + + auto start_iter = data_.begin() + start_sample * unit_size_; + auto end_iter = data_.begin() + end_sample * unit_size_; + data_.erase(start_iter, end_iter); + sample_count_ -= end_sample - start_sample; + + append_payload_to_mipmap(); +} + +void LogicSegment::reallocate_mipmap_level(MipMapLevel &m) { const uint64_t new_data_length = ((m.length + MipMapDataUnit - 1) / MipMapDataUnit) * MipMapDataUnit; @@ -183,7 +202,7 @@ void LogicSnapshot::reallocate_mipmap_level(MipMapLevel &m) } } -void LogicSnapshot::append_payload_to_mipmap() +void LogicSegment::append_payload_to_mipmap() { MipMapLevel &m0 = mip_map_[0]; uint64_t prev_length; @@ -265,14 +284,14 @@ void LogicSnapshot::append_payload_to_mipmap() } } -uint64_t LogicSnapshot::get_sample(uint64_t index) const +uint64_t LogicSegment::get_sample(uint64_t index) const { assert(index < sample_count_); return unpack_sample((uint8_t*)data_.data() + index * unit_size_); } -void LogicSnapshot::get_subsampled_edges( +void LogicSegment::get_subsampled_edges( std::vector &edges, uint64_t start, uint64_t end, float min_length, int sig_index) @@ -451,7 +470,7 @@ void LogicSnapshot::get_subsampled_edges( edges.push_back(pair(end + 1, end_sample)); } -uint64_t LogicSnapshot::get_subsample(int level, uint64_t offset) const +uint64_t LogicSegment::get_subsample(int level, uint64_t offset) const { assert(level >= 0); assert(mip_map_[level].data); @@ -459,7 +478,7 @@ uint64_t LogicSnapshot::get_subsample(int level, uint64_t offset) const unit_size_ * offset); } -uint64_t LogicSnapshot::pow2_ceil(uint64_t x, unsigned int power) +uint64_t LogicSegment::pow2_ceil(uint64_t x, unsigned int power) { const uint64_t p = 1 << power; return (x + p - 1) / p * p; diff --git a/pv/data/logicsnapshot.hpp b/pv/data/logicsegment.hpp similarity index 82% rename from pv/data/logicsnapshot.hpp rename to pv/data/logicsegment.hpp index 619048d8..63254f49 100644 --- a/pv/data/logicsnapshot.hpp +++ b/pv/data/logicsegment.hpp @@ -21,7 +21,7 @@ #ifndef PULSEVIEW_PV_DATA_LOGICSNAPSHOT_H #define PULSEVIEW_PV_DATA_LOGICSNAPSHOT_H -#include "snapshot.hpp" +#include "segment.hpp" #include #include @@ -30,7 +30,7 @@ namespace sigrok { class Logic; } -namespace LogicSnapshotTest { +namespace LogicSegmentTest { struct Pow2; struct Basic; struct LargeData; @@ -41,7 +41,7 @@ struct LongPulses; namespace pv { namespace data { -class LogicSnapshot : public Snapshot +class LogicSegment : public Segment { private: struct MipMapLevel @@ -62,15 +62,16 @@ class LogicSnapshot : public Snapshot typedef std::pair EdgePair; public: - LogicSnapshot(std::shared_ptr logic, - uint64_t expected_num_samples = 0); + LogicSegment(std::shared_ptr logic, + uint64_t samplerate, uint64_t expected_num_samples = 0); - virtual ~LogicSnapshot(); + virtual ~LogicSegment(); void append_payload(std::shared_ptr logic); void get_samples(uint8_t *const data, int64_t start_sample, int64_t end_sample) const; + void remove_samples(int64_t start_sample, int64_t end_sample); private: uint64_t unpack_sample(const uint8_t *ptr) const; @@ -84,7 +85,7 @@ class LogicSnapshot : public Snapshot public: /** - * Parses a logic data snapshot to generate a list of transitions + * Parses a logic data segment to generate a list of transitions * in a time interval to a given level of detail. * @param[out] edges The vector to place the edges into. * @param[in] start The start sample index. @@ -106,11 +107,11 @@ class LogicSnapshot : public Snapshot struct MipMapLevel mip_map_[ScaleStepCount]; uint64_t last_append_sample_; - friend struct LogicSnapshotTest::Pow2; - friend struct LogicSnapshotTest::Basic; - friend struct LogicSnapshotTest::LargeData; - friend struct LogicSnapshotTest::Pulses; - friend struct LogicSnapshotTest::LongPulses; + friend struct LogicSegmentTest::Pow2; + friend struct LogicSegmentTest::Basic; + friend struct LogicSegmentTest::LargeData; + friend struct LogicSegmentTest::Pulses; + friend struct LogicSegmentTest::LongPulses; }; } // namespace data diff --git a/pv/data/snapshot.cpp b/pv/data/segment.cpp similarity index 74% rename from pv/data/snapshot.cpp rename to pv/data/segment.cpp index 58da4dbd..28fd296d 100644 --- a/pv/data/snapshot.cpp +++ b/pv/data/segment.cpp @@ -18,7 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "snapshot.hpp" +#include "segment.hpp" #include #include @@ -30,8 +30,10 @@ using std::recursive_mutex; namespace pv { namespace data { -Snapshot::Snapshot(unsigned int unit_size) : +Segment::Segment(uint64_t samplerate, unsigned int unit_size) : sample_count_(0), + start_time_(0), + samplerate_(samplerate), capacity_(0), unit_size_(unit_size) { @@ -39,23 +41,43 @@ Snapshot::Snapshot(unsigned int unit_size) : assert(unit_size_ > 0); } -Snapshot::~Snapshot() +Segment::~Segment() { lock_guard lock(mutex_); } -uint64_t Snapshot::get_sample_count() const +uint64_t Segment::get_sample_count() const { lock_guard lock(mutex_); return sample_count_; } -unsigned int Snapshot::unit_size() const +double Segment::start_time() const +{ + return start_time_; +} + +double Segment::time() const +{ + return sample_count_ / (double) samplerate_; +} + +double Segment::samplerate() const +{ + return samplerate_; +} + +void Segment::set_samplerate(double samplerate) +{ + samplerate_ = samplerate; +} + +unsigned int Segment::unit_size() const { return unit_size_; } -void Snapshot::set_capacity(const uint64_t new_capacity) +void Segment::set_capacity(const uint64_t new_capacity) { lock_guard lock(mutex_); @@ -66,13 +88,13 @@ void Snapshot::set_capacity(const uint64_t new_capacity) } } -uint64_t Snapshot::capacity() const +uint64_t Segment::capacity() const { lock_guard lock(mutex_); return data_.size(); } -void Snapshot::append_data(void *data, uint64_t samples) +void Segment::append_data(void *data, uint64_t samples) { lock_guard lock(mutex_); diff --git a/pv/data/snapshot.hpp b/pv/data/segment.hpp similarity index 78% rename from pv/data/snapshot.hpp rename to pv/data/segment.hpp index 29d0eed4..ad155114 100644 --- a/pv/data/snapshot.hpp +++ b/pv/data/segment.hpp @@ -28,41 +28,47 @@ namespace pv { namespace data { -class Snapshot +class Segment { public: - Snapshot(unsigned int unit_size); + Segment(uint64_t samplerate, unsigned int unit_size); - virtual ~Snapshot(); + virtual ~Segment(); uint64_t get_sample_count() const; + double start_time() const; + double time() const; + + double samplerate() const; + void set_samplerate(double samplerate); + unsigned int unit_size() const; /** - * @brief Increase the capacity of the snapshot. + * @brief Increase the capacity of the segment. * * Increasing the capacity allows samples to be appended without needing * to reallocate memory. * * For the best efficiency @c set_capacity() should be called once before - * @c append_data() is called to set up the snapshot with the expected number + * @c append_data() is called to set up the segment with the expected number * of samples that will be appended in total. * * @note The capacity will automatically be increased when @c append_data() * is called if there is not enough capacity in the buffer to store the samples. * - * @param[in] new_capacity The new capacity of the snapshot. If this value is + * @param[in] new_capacity The new capacity of the segment. If this value is * smaller or equal than the current capacity then the method has no effect. */ void set_capacity(uint64_t new_capacity); /** - * @brief Get the current capacity of the snapshot. + * @brief Get the current capacity of the segment. * * The capacity can be increased by calling @c set_capacity(). * - * @return The current capacity of the snapshot. + * @return The current capacity of the segment. */ uint64_t capacity() const; @@ -73,6 +79,8 @@ class Snapshot mutable std::recursive_mutex mutex_; std::vector data_; uint64_t sample_count_; + double start_time_; + double samplerate_; uint64_t capacity_; unsigned int unit_size_; }; diff --git a/pv/data/signaldata.cpp b/pv/data/signaldata.cpp index 42409b82..6a4c6d92 100644 --- a/pv/data/signaldata.cpp +++ b/pv/data/signaldata.cpp @@ -23,27 +23,9 @@ namespace pv { namespace data { -SignalData::SignalData() : - start_time_(0), - samplerate_(0) +SignalData::SignalData() { } -double SignalData::samplerate() const -{ - return samplerate_; -} - -void SignalData::set_samplerate(double samplerate) -{ - samplerate_ = samplerate; - clear(); -} - -double SignalData::get_start_time() const -{ - return start_time_; -} - } // namespace data } // namespace pv diff --git a/pv/data/signaldata.hpp b/pv/data/signaldata.hpp index 885f8435..c49cb5c0 100644 --- a/pv/data/signaldata.hpp +++ b/pv/data/signaldata.hpp @@ -21,11 +21,15 @@ #ifndef PULSEVIEW_PV_DATA_SIGNALDATA_H #define PULSEVIEW_PV_DATA_SIGNALDATA_H -#include +#include +#include +#include namespace pv { namespace data { +class Segment; + class SignalData { public: @@ -33,18 +37,11 @@ class SignalData virtual ~SignalData() {} public: - double samplerate() const; - void set_samplerate(double samplerate); - - double get_start_time() const; + virtual std::vector< std::shared_ptr > segments() const = 0; virtual void clear() = 0; virtual uint64_t get_max_sample_count() const = 0; - -protected: - double start_time_; - double samplerate_; }; } // namespace data diff --git a/pv/devicemanager.cpp b/pv/devicemanager.cpp index 7a016d1b..9976d3e6 100644 --- a/pv/devicemanager.cpp +++ b/pv/devicemanager.cpp @@ -19,7 +19,7 @@ */ #include "devicemanager.hpp" -#include "sigsession.hpp" +#include "session.hpp" #include #include diff --git a/pv/mainwindow.cpp b/pv/mainwindow.cpp index cc0e0d25..b3649ded 100644 --- a/pv/mainwindow.cpp +++ b/pv/mainwindow.cpp @@ -238,6 +238,20 @@ void MainWindow::setup_ui() action_view_show_cursors->setText(tr("Show &Cursors")); menu_view->addAction(action_view_show_cursors); + QAction *action_view_delete = new QAction(this); + action_view_delete->setShortcut(QKeySequence::Delete); + action_view_delete->setObjectName( + QString::fromUtf8("actionViewDelete")); + action_view_delete->setText(tr("Delete under cursor")); + menu_view->addAction(action_view_delete); + + QAction *action_view_crop = new QAction(this); + action_view_crop->setShortcut(QKeySequence(Qt::SHIFT + Qt::Key_Delete)); + action_view_crop->setObjectName( + QString::fromUtf8("actionViewCrop")); + action_view_crop->setText(tr("Crop around cursor")); + menu_view->addAction(action_view_crop); + // Decoders Menu #ifdef ENABLE_DECODE QMenu *const menu_decoders = new QMenu; @@ -552,6 +566,35 @@ void MainWindow::on_actionViewShowCursors_triggered() view_->show_cursors(show); } +void MainWindow::on_actionViewDelete_triggered() +{ + assert(view_); + + if (!view_->cursors_shown()) + return; + + double start_time = view_->cursors().first()->time(); + double end_time = view_->cursors().second()->time(); + + session_.remove_samples(start_time, end_time); + view_->show_cursors(false); +} + +void MainWindow::on_actionViewCrop_triggered() +{ + assert(view_); + + if (!view_->cursors_shown()) + return; + + double start_time = view_->cursors().first()->time(); + double end_time = view_->cursors().second()->time(); + + session_.crop_samples(start_time, end_time); + view_->cursors().first()->set_time(0); + view_->cursors().second()->set_time(end_time - start_time); +} + void MainWindow::on_actionAbout_triggered() { dialogs::About dlg(device_manager_.context(), this); diff --git a/pv/mainwindow.hpp b/pv/mainwindow.hpp index 8a67c615..a8172b28 100644 --- a/pv/mainwindow.hpp +++ b/pv/mainwindow.hpp @@ -26,7 +26,7 @@ #include -#include "sigsession.hpp" +#include "session.hpp" struct srd_decoder; @@ -105,6 +105,8 @@ private Q_SLOTS: void on_actionViewShowCursors_triggered(); void on_actionAbout_triggered(); + void on_actionViewDelete_triggered(); + void on_actionViewCrop_triggered(); void add_decoder(srd_decoder *decoder); diff --git a/pv/popups/channels.cpp b/pv/popups/channels.cpp index f8061d9a..f30ce627 100644 --- a/pv/popups/channels.cpp +++ b/pv/popups/channels.cpp @@ -28,7 +28,7 @@ #include "channels.hpp" #include -#include +#include #include #include diff --git a/pv/sigsession.cpp b/pv/session.cpp similarity index 82% rename from pv/sigsession.cpp rename to pv/session.cpp index 84c75896..952da843 100644 --- a/pv/sigsession.cpp +++ b/pv/session.cpp @@ -22,15 +22,15 @@ #include #endif -#include "sigsession.hpp" +#include "session.hpp" #include "devicemanager.hpp" #include "data/analog.hpp" -#include "data/analogsnapshot.hpp" +#include "data/analogsegment.hpp" #include "data/decoderstack.hpp" #include "data/logic.hpp" -#include "data/logicsnapshot.hpp" +#include "data/logicsegment.hpp" #include "data/decode/decoder.hpp" #include "view/analogsignal.hpp" @@ -85,7 +85,8 @@ namespace pv { Session::Session(DeviceManager &device_manager) : device_manager_(device_manager), session_(device_manager.context()->create_session()), - capture_state_(Stopped) + capture_state_(Stopped), + cur_samplerate_(0) { set_default_device(); } @@ -242,6 +243,74 @@ void Session::stop_capture() sampling_thread_.join(); } +void Session::remove_samples(double start_time, double end_time) +{ + stop_capture(); + + { + // remove logic data + lock_guard data_lock(data_mutex_); + if (logic_data_) + logic_data_->remove(start_time, end_time); + } + + { + // remove analog data + lock_guard lock(signals_mutex_); + for (auto signal : signals_) { + auto analog = dynamic_pointer_cast(signal); + if (analog) + analog->analog_data()->remove(start_time, end_time); + } + } + + data_received(); + +#ifdef ENABLE_DECODE + { + // refresh decoders + lock_guard lock(signals_mutex_); + for (auto trace : decode_traces_) { + trace->decoder()->begin_decode(); + } + } +#endif +} + +void Session::crop_samples(double start_time, double end_time) +{ + stop_capture(); + + { + // crop logic data + lock_guard data_lock(data_mutex_); + if (logic_data_) + logic_data_->crop(start_time, end_time); + } + + { + // crop analog data + lock_guard lock(signals_mutex_); + for (auto signal : signals_) { + auto analog = dynamic_pointer_cast(signal); + if (analog) + analog->analog_data()->crop(start_time, end_time); + } + } + + data_received(); + +#ifdef ENABLE_DECODE + { + // refresh decoders + lock_guard lock(signals_mutex_); + for (auto trace : decode_traces_) { + trace->decoder()->begin_decode(); + } + } +#endif +} + set< shared_ptr > Session::get_data() const { shared_lock lock(signals_mutex_); @@ -363,7 +432,7 @@ void Session::update_signals(shared_ptr device) [] (shared_ptr channel) { return channel->type() == ChannelType::LOGIC; }); - // Create data containers for the logic data snapshots + // Create data containers for the logic data segments { lock_guard data_lock(data_mutex_); @@ -431,17 +500,10 @@ void Session::read_sample_rate(shared_ptr device) { const auto keys = device_->config_keys(ConfigKey::DEVICE_OPTIONS); const auto iter = keys.find(ConfigKey::SAMPLERATE); - const uint64_t sample_rate = (iter != keys.end() && + cur_samplerate_ = (iter != keys.end() && (*iter).second.find(sigrok::GET) != (*iter).second.end()) ? VariantBase::cast_dynamic>( device->config_get(ConfigKey::SAMPLERATE)).get() : 0; - - // Set the sample rate of all data - const set< shared_ptr > data_set = get_data(); - for (shared_ptr data : data_set) { - assert(data); - data->set_samplerate(sample_rate); - } } void Session::sample_thread_proc(shared_ptr device, @@ -466,7 +528,7 @@ void Session::sample_thread_proc(shared_ptr device, set_capture_state(Stopped); // Confirm that SR_DF_END was received - if (cur_logic_snapshot_) + if (cur_logic_segment_) { qDebug("SR_DF_END was not received."); assert(0); @@ -499,7 +561,7 @@ void Session::feed_in_meta(shared_ptr device, void Session::feed_in_frame_begin() { - if (cur_logic_snapshot_ || !cur_analog_snapshots_.empty()) + if (cur_logic_segment_ || !cur_analog_segments_.empty()) frame_began(); } @@ -513,7 +575,7 @@ void Session::feed_in_logic(shared_ptr logic) return; } - if (!cur_logic_snapshot_) + if (!cur_logic_segment_) { // This could be the first packet after a trigger set_capture_state(Running); @@ -528,10 +590,11 @@ void Session::feed_in_logic(shared_ptr logic) VariantBase::cast_dynamic>( device_->config_get(ConfigKey::LIMIT_SAMPLES)).get() : 0; - // Create a new data snapshot - cur_logic_snapshot_ = shared_ptr( - new data::LogicSnapshot(logic, sample_limit)); - logic_data_->push_snapshot(cur_logic_snapshot_); + // Create a new data segment + cur_logic_segment_ = shared_ptr( + new data::LogicSegment( + logic, cur_samplerate_, sample_limit)); + logic_data_->push_segment(cur_logic_segment_); // @todo Putting this here means that only listeners querying // for logic will be notified. Currently the only user of @@ -541,8 +604,8 @@ void Session::feed_in_logic(shared_ptr logic) } else { - // Append to the existing data snapshot - cur_logic_snapshot_->append_payload(logic); + // Append to the existing data segment + cur_logic_segment_->append_payload(logic); } data_received(); @@ -560,18 +623,18 @@ void Session::feed_in_analog(shared_ptr analog) for (auto channel : channels) { - shared_ptr snapshot; + shared_ptr segment; - // Try to get the snapshot of the channel - const map< shared_ptr, shared_ptr >:: - iterator iter = cur_analog_snapshots_.find(channel); - if (iter != cur_analog_snapshots_.end()) - snapshot = (*iter).second; + // Try to get the segment of the channel + const map< shared_ptr, shared_ptr >:: + iterator iter = cur_analog_segments_.find(channel); + if (iter != cur_analog_segments_.end()) + segment = (*iter).second; else { - // If no snapshot was found, this means we havn't + // If no segment was found, this means we havn't // created one yet. i.e. this is the first packet - // in the sweep containing this snapshot. + // in the sweep containing this segment. sweep_beginning = true; // Get sample limit. @@ -583,10 +646,11 @@ void Session::feed_in_analog(shared_ptr analog) sample_limit = 0; } - // Create a snapshot, keep it in the maps of channels - snapshot = shared_ptr( - new data::AnalogSnapshot(sample_limit)); - cur_analog_snapshots_[channel] = snapshot; + // Create a segment, keep it in the maps of channels + segment = shared_ptr( + new data::AnalogSegment( + cur_samplerate_, sample_limit)); + cur_analog_segments_[channel] = segment; // Find the annalog data associated with the channel shared_ptr sig = @@ -597,14 +661,14 @@ void Session::feed_in_analog(shared_ptr analog) shared_ptr data(sig->analog_data()); assert(data); - // Push the snapshot into the analog data. - data->push_snapshot(snapshot); + // Push the segment into the analog data. + data->push_segment(segment); } - assert(snapshot); + assert(segment); - // Append the samples in the snapshot - snapshot->append_interleaved_samples(data++, sample_count, + // Append the samples in the segment + segment->append_interleaved_samples(data++, sample_count, channel_count); } @@ -646,8 +710,8 @@ void Session::data_feed_in(shared_ptr device, shared_ptr packet) { { lock_guard lock(data_mutex_); - cur_logic_snapshot_.reset(); - cur_analog_snapshots_.clear(); + cur_logic_segment_.reset(); + cur_analog_segments_.clear(); } frame_ended(); break; diff --git a/pv/sigsession.hpp b/pv/session.hpp similarity index 93% rename from pv/sigsession.hpp rename to pv/session.hpp index c6a317de..cf8e79a7 100644 --- a/pv/sigsession.hpp +++ b/pv/session.hpp @@ -53,9 +53,9 @@ class DeviceManager; namespace data { class Analog; -class AnalogSnapshot; +class AnalogSegment; class Logic; -class LogicSnapshot; +class LogicSegment; class SignalData; } @@ -104,6 +104,9 @@ class Session : public QObject void stop_capture(); + void remove_samples(double start_time, double end_time); + void crop_samples(double start_time, double end_time); + std::set< std::shared_ptr > get_data() const; boost::shared_mutex& signals_mutex() const; @@ -166,9 +169,10 @@ class Session : public QObject mutable std::mutex data_mutex_; std::shared_ptr logic_data_; - std::shared_ptr cur_logic_snapshot_; - std::map< std::shared_ptr, std::shared_ptr > - cur_analog_snapshots_; + uint64_t cur_samplerate_; + std::shared_ptr cur_logic_segment_; + std::map< std::shared_ptr, std::shared_ptr > + cur_analog_segments_; std::thread sampling_thread_; diff --git a/pv/storesession.cpp b/pv/storesession.cpp index 221804c4..6ecde13a 100644 --- a/pv/storesession.cpp +++ b/pv/storesession.cpp @@ -22,9 +22,9 @@ #include "storesession.hpp" -#include +#include #include -#include +#include #include #include @@ -106,17 +106,17 @@ bool StoreSession::start() return false; } - // Get the snapshot - const deque< shared_ptr > &snapshots = - data->get_snapshots(); + // Get the segment + const deque< shared_ptr > &segments = + data->logic_segments(); - if (snapshots.empty()) { - error_ = tr("No snapshots to save."); + if (segments.empty()) { + error_ = tr("No segments to save."); return false; } - const shared_ptr snapshot(snapshots.front()); - assert(snapshot); + const shared_ptr segment(segments.front()); + assert(segment); // Begin storing try { @@ -127,15 +127,15 @@ bool StoreSession::start() {{"filename", Glib::Variant::create(file_name_)}}); auto meta = context->create_meta_packet( - {{ConfigKey::SAMPLERATE, - Glib::Variant::create(data->samplerate())}}); + {{ConfigKey::SAMPLERATE, Glib::Variant::create( + segment->samplerate())}}); output_->receive(meta); } catch (Error error) { error_ = tr("Error while saving."); return false; } - thread_ = std::thread(&StoreSession::store_proc, this, snapshot); + thread_ = std::thread(&StoreSession::store_proc, this, segment); return true; } @@ -150,9 +150,9 @@ void StoreSession::cancel() interrupt_ = true; } -void StoreSession::store_proc(shared_ptr snapshot) +void StoreSession::store_proc(shared_ptr segment) { - assert(snapshot); + assert(segment); uint64_t start_sample = 0, sample_count; unsigned progress_scale = 0; @@ -161,10 +161,10 @@ void StoreSession::store_proc(shared_ptr snapshot) uint8_t *const data = new uint8_t[BlockSize]; assert(data); - const int unit_size = snapshot->unit_size(); + const int unit_size = segment->unit_size(); assert(unit_size != 0); - sample_count = snapshot->get_sample_count(); + sample_count = segment->get_sample_count(); // Qt needs the progress values to fit inside an int. If they would // not, scale the current and max values down until they do. @@ -181,7 +181,7 @@ void StoreSession::store_proc(shared_ptr snapshot) const uint64_t end_sample = min( start_sample + samples_per_block, sample_count); - snapshot->get_samples(data, start_sample, end_sample); + segment->get_samples(data, start_sample, end_sample); size_t length = end_sample - start_sample; diff --git a/pv/storesession.hpp b/pv/storesession.hpp index 62cf1895..9094ca12 100644 --- a/pv/storesession.hpp +++ b/pv/storesession.hpp @@ -39,7 +39,7 @@ namespace pv { class Session; namespace data { -class LogicSnapshot; +class LogicSegment; } class StoreSession : public QObject @@ -66,7 +66,7 @@ class StoreSession : public QObject void cancel(); private: - void store_proc(std::shared_ptr snapshot); + void store_proc(std::shared_ptr segment); Q_SIGNALS: void progress_updated(); diff --git a/pv/toolbars/samplingbar.hpp b/pv/toolbars/samplingbar.hpp index 25ce23ae..436304bc 100644 --- a/pv/toolbars/samplingbar.hpp +++ b/pv/toolbars/samplingbar.hpp @@ -31,7 +31,7 @@ #include #include -#include +#include #include #include diff --git a/pv/view/analogsignal.cpp b/pv/view/analogsignal.cpp index 8a19cc21..5b6d8a50 100644 --- a/pv/view/analogsignal.cpp +++ b/pv/view/analogsignal.cpp @@ -25,7 +25,7 @@ #include "analogsignal.hpp" #include "pv/data/analog.hpp" -#include "pv/data/analogsnapshot.hpp" +#include "pv/data/analogsegment.hpp" #include "pv/view/view.hpp" #include @@ -87,46 +87,37 @@ std::pair AnalogSignal::v_extents() const return make_pair(-NominalHeight / 2, NominalHeight / 2); } -void AnalogSignal::paint_back(QPainter &p, int left, int right) +void AnalogSignal::paint_back(QPainter &p, const RowItemPaintParams &pp) { if (channel_->enabled()) - paint_axis(p, get_visual_y(), left, right); + paint_axis(p, pp, get_visual_y()); } -void AnalogSignal::paint_mid(QPainter &p, int left, int right) +void AnalogSignal::paint_mid(QPainter &p, const RowItemPaintParams &pp) { assert(data_); - assert(right >= left); assert(owner_); const int y = get_visual_y(); - const View *const view = owner_->view(); - assert(view); - - const double scale = view->scale(); - assert(scale > 0); - - const double offset = view->offset(); - if (!channel_->enabled()) return; - const deque< shared_ptr > &snapshots = - data_->get_snapshots(); - if (snapshots.empty()) + const deque< shared_ptr > &segments = + data_->analog_segments(); + if (segments.empty()) return; - const shared_ptr &snapshot = - snapshots.front(); + const shared_ptr &segment = + segments.front(); - const double pixels_offset = offset / scale; - const double samplerate = data_->samplerate(); - const double start_time = data_->get_start_time(); - const int64_t last_sample = snapshot->get_sample_count() - 1; - const double samples_per_pixel = samplerate * scale; - const double start = samplerate * (offset - start_time); - const double end = start + samples_per_pixel * (right - left); + const double pixels_offset = pp.pixels_offset(); + const double samplerate = segment->samplerate(); + const double start_time = segment->start_time(); + const int64_t last_sample = segment->get_sample_count() - 1; + const double samples_per_pixel = samplerate * pp.scale(); + const double start = samplerate * (pp.offset() - start_time); + const double end = start + samples_per_pixel * pp.width(); const int64_t start_sample = min(max((int64_t)floor(start), (int64_t)0), last_sample); @@ -134,23 +125,23 @@ void AnalogSignal::paint_mid(QPainter &p, int left, int right) (int64_t)0), last_sample); if (samples_per_pixel < EnvelopeThreshold) - paint_trace(p, snapshot, y, left, + paint_trace(p, segment, y, pp.left(), start_sample, end_sample, pixels_offset, samples_per_pixel); else - paint_envelope(p, snapshot, y, left, + paint_envelope(p, segment, y, pp.left(), start_sample, end_sample, pixels_offset, samples_per_pixel); } void AnalogSignal::paint_trace(QPainter &p, - const shared_ptr &snapshot, + const shared_ptr &segment, int y, int left, const int64_t start, const int64_t end, const double pixels_offset, const double samples_per_pixel) { const int64_t sample_count = end - start; - const float *const samples = snapshot->get_samples(start, end); + const float *const samples = segment->get_samples(start, end); assert(samples); p.setPen(colour_); @@ -172,14 +163,14 @@ void AnalogSignal::paint_trace(QPainter &p, } void AnalogSignal::paint_envelope(QPainter &p, - const shared_ptr &snapshot, + const shared_ptr &segment, int y, int left, const int64_t start, const int64_t end, const double pixels_offset, const double samples_per_pixel) { - using pv::data::AnalogSnapshot; + using pv::data::AnalogSegment; - AnalogSnapshot::EnvelopeSection e; - snapshot->get_envelope_section(e, start, end, samples_per_pixel); + AnalogSegment::EnvelopeSection e; + segment->get_envelope_section(e, start, end, samples_per_pixel); if (e.length < 2) return; @@ -193,7 +184,7 @@ void AnalogSignal::paint_envelope(QPainter &p, for(uint64_t sample = 0; sample < e.length-1; sample++) { const float x = ((e.scale * sample + e.start) / samples_per_pixel - pixels_offset) + left; - const AnalogSnapshot::EnvelopeSample *const s = + const AnalogSegment::EnvelopeSample *const s = e.samples + sample; // We overlap this sample with the next so that vertical diff --git a/pv/view/analogsignal.hpp b/pv/view/analogsignal.hpp index 5295fe32..ad2b25ae 100644 --- a/pv/view/analogsignal.hpp +++ b/pv/view/analogsignal.hpp @@ -29,7 +29,7 @@ namespace pv { namespace data { class Analog; -class AnalogSnapshot; +class AnalogSegment; } namespace view { @@ -64,27 +64,25 @@ class AnalogSignal : public Signal /** * Paints the background layer of the signal with a QPainter * @param p the QPainter to paint into. - * @param left the x-coordinate of the left edge of the signal. - * @param right the x-coordinate of the right edge of the signal. + * @param pp the painting parameters object to paint with.. **/ - void paint_back(QPainter &p, int left, int right); + void paint_back(QPainter &p, const RowItemPaintParams &pp); /** * Paints the mid-layer of the signal with a QPainter * @param p the QPainter to paint into. - * @param left the x-coordinate of the left edge of the signal. - * @param right the x-coordinate of the right edge of the signal. + * @param pp the painting parameters object to paint with.. **/ - void paint_mid(QPainter &p, int left, int right); + void paint_mid(QPainter &p, const RowItemPaintParams &pp); private: void paint_trace(QPainter &p, - const std::shared_ptr &snapshot, + const std::shared_ptr &segment, int y, int left, const int64_t start, const int64_t end, const double pixels_offset, const double samples_per_pixel); void paint_envelope(QPainter &p, - const std::shared_ptr &snapshot, + const std::shared_ptr &segment, int y, int left, const int64_t start, const int64_t end, const double pixels_offset, const double samples_per_pixel); diff --git a/pv/view/cursor.cpp b/pv/view/cursor.cpp index 03df0543..d5b0a641 100644 --- a/pv/view/cursor.cpp +++ b/pv/view/cursor.cpp @@ -23,6 +23,7 @@ #include "view.hpp" #include "pv/util.hpp" +#include #include #include #include @@ -32,24 +33,15 @@ #include #include -#include - using std::shared_ptr; namespace pv { namespace view { -const QColor Cursor::LineColour(32, 74, 135); const QColor Cursor::FillColour(52, 101, 164); -const QColor Cursor::HighlightColour(83, 130, 186); -const QColor Cursor::TextColour(Qt::white); - -const int Cursor::Offset = 1; - -const int Cursor::ArrowSize = 4; Cursor::Cursor(View &view, double time) : - TimeMarker(view, LineColour, time) + TimeMarker(view, FillColour, time) { } @@ -60,11 +52,15 @@ QRectF Cursor::get_label_rect(const QRect &rect) const const float x = (time_ - view_.offset()) / view_.scale(); + QFontMetrics m(QApplication::font()); + QSize text_size = m.boundingRect( + pv::util::format_time(time_, view_.tick_prefix(), 2)).size(); + const QSizeF label_size( - text_size_.width() + View::LabelPadding.width() * 2, - text_size_.height() + View::LabelPadding.height() * 2); + text_size.width() + View::LabelPadding.width() * 2, + text_size.height() + View::LabelPadding.height() * 2); const float top = rect.height() - label_size.height() - - Cursor::Offset - Cursor::ArrowSize - 0.5f; + TimeMarker::Offset - TimeMarker::ArrowSize - 0.5f; const float height = label_size.height(); if (time_ > other->time()) @@ -74,81 +70,6 @@ QRectF Cursor::get_label_rect(const QRect &rect) const label_size.width(), height); } -void Cursor::paint_label(QPainter &p, const QRect &rect, - unsigned int prefix) -{ - const shared_ptr other(get_other_cursor()); - assert(other); - - compute_text_size(p, prefix); - const QRectF r(get_label_rect(rect)); - - const QPointF left_points[] = { - r.topLeft(), - r.topRight(), - r.bottomRight(), - QPointF(r.left() + ArrowSize, r.bottom()), - QPointF(r.left(), rect.bottom()), - }; - - const QPointF right_points[] = { - r.topRight(), - r.topLeft(), - r.bottomLeft(), - QPointF(r.right() - ArrowSize, r.bottom()), - QPointF(r.right(), rect.bottom()), - }; - - const QPointF left_highlight_points[] = { - QPointF(r.left() + 1, r.top() + 1), - QPointF(r.right() - 1, r.top() + 1), - QPointF(r.right() - 1, r.bottom() - 1), - QPointF(r.left() + ArrowSize - 1, r.bottom() - 1), - QPointF(r.left() + 1, rect.bottom() - 1), - }; - - const QPointF right_highlight_points[] = { - QPointF(r.right() - 1, r.top() + 1), - QPointF(r.left() + 1, r.top() + 1), - QPointF(r.left() + 1, r.bottom() - 1), - QPointF(r.right() - ArrowSize + 1, r.bottom() - 1), - QPointF(r.right() - 1, rect.bottom() - 1), - }; - - const QPointF *const points = (time_ > other->time()) ? - left_points : right_points; - const QPointF *const highlight_points = (time_ > other->time()) ? - left_highlight_points : right_highlight_points; - - if (selected()) { - p.setPen(highlight_pen()); - p.setBrush(Qt::transparent); - p.drawPolygon(points, countof(left_points)); - } - - p.setPen(Qt::transparent); - p.setBrush(FillColour); - p.drawPolygon(points, countof(left_points)); - - p.setPen(HighlightColour); - p.setBrush(Qt::transparent); - p.drawPolygon(highlight_points, countof(left_highlight_points)); - - p.setPen(LineColour); - p.setBrush(Qt::transparent); - p.drawPolygon(points, countof(left_points)); - - p.setPen(TextColour); - p.drawText(r, Qt::AlignCenter | Qt::AlignVCenter, - pv::util::format_time(time_, prefix, 2)); -} - -void Cursor::compute_text_size(QPainter &p, unsigned int prefix) -{ - text_size_ = p.boundingRect(QRectF(), 0, - pv::util::format_time(time_, prefix, 2)).size(); -} - shared_ptr Cursor::get_other_cursor() const { const CursorPair &cursors = view_.cursors(); diff --git a/pv/view/cursor.hpp b/pv/view/cursor.hpp index 8679a286..9f0adedd 100644 --- a/pv/view/cursor.hpp +++ b/pv/view/cursor.hpp @@ -37,14 +37,7 @@ class Cursor : public TimeMarker Q_OBJECT public: - static const QColor LineColour; static const QColor FillColour; - static const QColor HighlightColour; - static const QColor TextColour; - - static const int Offset; - - static const int ArrowSize; public: /** @@ -62,22 +55,8 @@ class Cursor : public TimeMarker */ QRectF get_label_rect(const QRect &rect) const; - /** - * Paints the cursor's label to the ruler. - * @param p The painter to draw with. - * @param rect The rectangle of the ruler client area. - * @param prefix The index of the SI prefix to use. - */ - void paint_label(QPainter &p, const QRect &rect, - unsigned int prefix); - private: - void compute_text_size(QPainter &p, unsigned int prefix); - std::shared_ptr get_other_cursor() const; - -private: - QSizeF text_size_; }; } // namespace view diff --git a/pv/view/cursorheader.cpp b/pv/view/cursorheader.cpp index 3fa0b0c5..3e2944e0 100644 --- a/pv/view/cursorheader.cpp +++ b/pv/view/cursorheader.cpp @@ -70,16 +70,13 @@ void CursorHeader::paintEvent(QPaintEvent*) QPainter p(this); p.setRenderHint(QPainter::Antialiasing); - unsigned int prefix = pv::view::Ruler::calculate_tick_spacing( - p, view_.scale(), view_.offset()).second; - // Draw the cursors if (view_.cursors_shown()) { // The cursor labels are not drawn with the arrows exactly on the // bottom line of the widget, because then the selection shadow // would be clipped away. const QRect r = rect().adjusted(0, 0, 0, -BaselineOffset); - view_.cursors().draw_markers(p, r, prefix); + view_.cursors().draw_markers(p, r); } } diff --git a/pv/view/cursorpair.cpp b/pv/view/cursorpair.cpp index 0fb0d8d1..12b7bc34 100644 --- a/pv/view/cursorpair.cpp +++ b/pv/view/cursorpair.cpp @@ -70,16 +70,17 @@ QRectF CursorPair::get_label_rect(const QRect &rect) const (float)rect.width() + height); return QRectF(left, rect.height() - label_size.height() - - Cursor::ArrowSize - Cursor::Offset - 0.5f, + TimeMarker::ArrowSize - TimeMarker::Offset - 0.5f, right - left, height); } -void CursorPair::draw_markers(QPainter &p, - const QRect &rect, unsigned int prefix) +void CursorPair::draw_markers(QPainter &p, const QRect &rect) { assert(first_); assert(second_); + const unsigned int prefix = view_.tick_prefix(); + compute_text_size(p, prefix); QRectF delta_rect(get_label_rect(rect)); @@ -91,21 +92,22 @@ void CursorPair::draw_markers(QPainter &p, const int highlight_radius = delta_rect.height() / 2 - 2; p.setBrush(Cursor::FillColour); - p.setPen(Cursor::LineColour); + p.setPen(Cursor::FillColour.darker()); p.drawRoundedRect(delta_rect, radius, radius); delta_rect.adjust(1, 1, -1, -1); - p.setPen(Cursor::HighlightColour); + p.setPen(Cursor::FillColour.lighter()); p.drawRoundedRect(delta_rect, highlight_radius, highlight_radius); - p.setPen(Cursor::TextColour); + p.setPen(SelectableItem::select_text_colour( + Cursor::FillColour)); p.drawText(text_rect, Qt::AlignCenter | Qt::AlignVCenter, pv::util::format_time(second_->time() - first_->time(), prefix, 2)); } // Paint the cursor markers - first_->paint_label(p, rect, prefix); - second_->paint_label(p, rect, prefix); + first_->paint_label(p, rect); + second_->paint_label(p, rect); } void CursorPair::draw_viewport_background(QPainter &p, diff --git a/pv/view/cursorpair.hpp b/pv/view/cursorpair.hpp index dd37b0ed..84737d21 100644 --- a/pv/view/cursorpair.hpp +++ b/pv/view/cursorpair.hpp @@ -57,8 +57,7 @@ class CursorPair public: QRectF get_label_rect(const QRect &rect) const; - void draw_markers(QPainter &p, - const QRect &rect, unsigned int prefix); + void draw_markers(QPainter &p, const QRect &rect); void draw_viewport_background(QPainter &p, const QRect &rect); diff --git a/pv/view/decodetrace.cpp b/pv/view/decodetrace.cpp index 79058956..193967e2 100644 --- a/pv/view/decodetrace.cpp +++ b/pv/view/decodetrace.cpp @@ -41,11 +41,11 @@ extern "C" { #include "decodetrace.hpp" -#include +#include #include #include #include -#include +#include #include #include #include @@ -156,28 +156,30 @@ const std::shared_ptr& DecodeTrace::decoder() const return decoder_stack_; } +std::shared_ptr& DecodeTrace::decoder() +{ + return decoder_stack_; +} + pair DecodeTrace::v_extents() const { /// @todo Replace this with an implementation that knows the true /// height of the trace - QFontMetrics m(QApplication::font()); - const int text_height = m.boundingRect(QRect(), 0, "Tg").height(); - const int row_height = (text_height * 6) / 4; + const int row_height = (RowItemPaintParams::text_height() * 6) / 4; return make_pair(-row_height / 2, row_height * 7 / 2); } -void DecodeTrace::paint_back(QPainter &p, int left, int right) +void DecodeTrace::paint_back(QPainter &p, const RowItemPaintParams &pp) { - Trace::paint_back(p, left, right); - paint_axis(p, get_visual_y(), left, right); + Trace::paint_back(p, pp); + paint_axis(p, pp, get_visual_y()); } -void DecodeTrace::paint_mid(QPainter &p, int left, int right) +void DecodeTrace::paint_mid(QPainter &p, const RowItemPaintParams &pp) { using namespace pv::data::decode; - QFontMetrics m(QApplication::font()); - text_height_ = m.boundingRect(QRect(), 0, "Tg").height(); + text_height_ = RowItemPaintParams::text_height(); row_height_ = (text_height_ * 6) / 4; const int annotation_height = (text_height_ * 5) / 4; @@ -185,14 +187,16 @@ void DecodeTrace::paint_mid(QPainter &p, int left, int right) const QString err = decoder_stack_->error_message(); if (!err.isEmpty()) { - draw_unresolved_period(p, annotation_height, left, right); - draw_error(p, err, left, right); + draw_unresolved_period( + p, annotation_height, pp.left(), pp.right()); + draw_error(p, err, pp); return; } // Iterate through the rows int y = get_visual_y(); - pair sample_range = get_sample_range(left, right); + pair sample_range = get_sample_range( + pp.left(), pp.right()); assert(decoder_stack_); const vector rows(decoder_stack_->get_visible_rows()); @@ -213,9 +217,8 @@ void DecodeTrace::paint_mid(QPainter &p, int left, int right) sample_range.first, sample_range.second); if (!annotations.empty()) { for (const Annotation &a : annotations) - draw_annotation(a, p, get_text_colour(), - annotation_height, left, right, y, - base_colour); + draw_annotation(a, p, annotation_height, + pp, y, base_colour); y += row_height_; visible_rows_.push_back(rows[i]); @@ -223,15 +226,13 @@ void DecodeTrace::paint_mid(QPainter &p, int left, int right) } // Draw the hatching - draw_unresolved_period(p, annotation_height, left, right); + draw_unresolved_period(p, annotation_height, pp.left(), pp.right()); } -void DecodeTrace::paint_fore(QPainter &p, int left, int right) +void DecodeTrace::paint_fore(QPainter &p, const RowItemPaintParams &pp) { using namespace pv::data::decode; - (void)right; - assert(row_height_); for (size_t i = 0; i < visible_rows_.size(); i++) @@ -244,15 +245,15 @@ void DecodeTrace::paint_fore(QPainter &p, int left, int right) if (i != 0) { const QPointF points[] = { - QPointF(left, y - ArrowSize), - QPointF(left + ArrowSize, y), - QPointF(left, y + ArrowSize) + QPointF(pp.left(), y - ArrowSize), + QPointF(pp.left() + ArrowSize, y), + QPointF(pp.left(), y + ArrowSize) }; p.drawPolygon(points, countof(points)); } - const QRect r(left + ArrowSize * 2, y - row_height_ / 2, - right - left, row_height_); + const QRect r(pp.left() + ArrowSize * 2, y - row_height_ / 2, + pp.right() - pp.left(), row_height_); const QString h(visible_rows_[i].title()); const int f = Qt::AlignLeft | Qt::AlignVCenter | Qt::TextDontClip; @@ -337,7 +338,7 @@ QMenu* DecodeTrace::create_context_menu(QWidget *parent) } void DecodeTrace::draw_annotation(const pv::data::decode::Annotation &a, - QPainter &p, QColor text_color, int h, int left, int right, int y, + QPainter &p, int h, const RowItemPaintParams &pp, int y, size_t base_colour) const { double samples_per_pixel, pixels_offset; @@ -353,19 +354,17 @@ void DecodeTrace::draw_annotation(const pv::data::decode::Annotation &a, const QColor &fill = Colours[colour]; const QColor &outline = OutlineColours[colour]; - if (start > right + DrawPadding || end < left - DrawPadding) + if (start > pp.right() + DrawPadding || end < pp.left() - DrawPadding) return; if (a.start_sample() == a.end_sample()) - draw_instant(a, p, fill, outline, text_color, h, - start, y); + draw_instant(a, p, fill, outline, h, start, y); else - draw_range(a, p, fill, outline, text_color, h, - start, end, y); + draw_range(a, p, fill, outline, h, start, end, y); } void DecodeTrace::draw_instant(const pv::data::decode::Annotation &a, QPainter &p, - QColor fill, QColor outline, QColor text_color, int h, double x, int y) const + QColor fill, QColor outline, int h, double x, int y) const { const QString text = a.annotations().empty() ? QString() : a.annotations().back(); @@ -377,12 +376,12 @@ void DecodeTrace::draw_instant(const pv::data::decode::Annotation &a, QPainter & p.setBrush(fill); p.drawRoundedRect(rect, h / 2, h / 2); - p.setPen(text_color); + p.setPen(Qt::black); p.drawText(rect, Qt::AlignCenter | Qt::AlignVCenter, text); } void DecodeTrace::draw_range(const pv::data::decode::Annotation &a, QPainter &p, - QColor fill, QColor outline, QColor text_color, int h, double start, + QColor fill, QColor outline, int h, double start, double end, int y) const { const double top = y + .5 - h / 2; @@ -420,7 +419,7 @@ void DecodeTrace::draw_range(const pv::data::decode::Annotation &a, QPainter &p, if (rect.width() <= 4) return; - p.setPen(text_color); + p.setPen(Qt::black); // Try to find an annotation that will fit QString best_annotation; @@ -441,7 +440,7 @@ void DecodeTrace::draw_range(const pv::data::decode::Annotation &a, QPainter &p, } void DecodeTrace::draw_error(QPainter &p, const QString &message, - int left, int right) + const RowItemPaintParams &pp) { const int y = get_visual_y(); @@ -449,7 +448,7 @@ void DecodeTrace::draw_error(QPainter &p, const QString &message, p.setBrush(ErrorBgColour); const QRectF bounding_rect = - QRectF(left, INT_MIN / 2 + y, right - left, INT_MAX); + QRectF(pp.width(), INT_MIN / 2 + y, pp.width(), INT_MAX); const QRectF text_rect = p.boundingRect(bounding_rect, Qt::AlignCenter, message); const float r = text_rect.height() / 4; @@ -457,7 +456,7 @@ void DecodeTrace::draw_error(QPainter &p, const QString &message, p.drawRoundedRect(text_rect.adjusted(-r, -r, r, r), r, r, Qt::AbsoluteSize); - p.setPen(get_text_colour()); + p.setPen(Qt::black); p.drawText(text_rect, message); } @@ -478,20 +477,20 @@ void DecodeTrace::draw_unresolved_period(QPainter &p, int h, int left, // We get the logic data of the first channel in the list. // This works because we are currently assuming all - // LogicSignals have the same data/snapshot + // LogicSignals have the same data/segment for (const shared_ptr &dec : stack) if (dec && !dec->channels().empty() && ((logic_signal = (*dec->channels().begin()).second)) && ((data = logic_signal->logic_data()))) break; - if (!data || data->get_snapshots().empty()) + if (!data || data->logic_segments().empty()) return; - const shared_ptr snapshot = - data->get_snapshots().front(); - assert(snapshot); - const int64_t sample_count = (int64_t)snapshot->get_sample_count(); + const shared_ptr segment = + data->logic_segments().front(); + assert(segment); + const int64_t sample_count = (int64_t)segment->get_sample_count(); if (sample_count == 0) return; @@ -531,7 +530,7 @@ pair DecodeTrace::get_pixels_offset_samples_per_pixel() const assert(scale > 0); const double pixels_offset = - (view->offset() - decoder_stack_->get_start_time()) / scale; + (view->offset() - decoder_stack_->start_time()) / scale; double samplerate = decoder_stack_->samplerate(); diff --git a/pv/view/decodetrace.hpp b/pv/view/decodetrace.hpp index e3d8d68c..1bedf343 100644 --- a/pv/view/decodetrace.hpp +++ b/pv/view/decodetrace.hpp @@ -89,6 +89,7 @@ class DecodeTrace : public Trace bool enabled() const; const std::shared_ptr& decoder() const; + std::shared_ptr& decoder(); /** * Computes the vertical extents of the contents of this row item. @@ -99,26 +100,23 @@ class DecodeTrace : public Trace /** * Paints the background layer of the trace with a QPainter * @param p the QPainter to paint into. - * @param left the x-coordinate of the left edge of the signal. - * @param right the x-coordinate of the right edge of the signal. + * @param pp the painting parameters object to paint with.. **/ - void paint_back(QPainter &p, int left, int right); + void paint_back(QPainter &p, const RowItemPaintParams &pp); /** * Paints the mid-layer of the trace with a QPainter * @param p the QPainter to paint into. - * @param left the x-coordinate of the left edge of the signal - * @param right the x-coordinate of the right edge of the signal + * @param pp the painting parameters object to paint with. **/ - void paint_mid(QPainter &p, int left, int right); + void paint_mid(QPainter &p, const RowItemPaintParams &pp); /** * Paints the foreground layer of the trace with a QPainter * @param p the QPainter to paint into. - * @param left the x-coordinate of the left edge of the signal - * @param right the x-coordinate of the right edge of the signal + * @param pp the painting parameters object to paint with. **/ - void paint_fore(QPainter &p, int left, int right); + void paint_fore(QPainter &p, const RowItemPaintParams &pp); void populate_popup_form(QWidget *parent, QFormLayout *form); @@ -128,19 +126,18 @@ class DecodeTrace : public Trace private: void draw_annotation(const pv::data::decode::Annotation &a, QPainter &p, - QColor text_colour, int text_height, int left, int right, int y, + int text_height, const RowItemPaintParams &pp, int y, size_t base_colour) const; void draw_instant(const pv::data::decode::Annotation &a, QPainter &p, - QColor fill, QColor outline, QColor text_color, int h, double x, - int y) const; + QColor fill, QColor outline, int h, double x, int y) const; void draw_range(const pv::data::decode::Annotation &a, QPainter &p, - QColor fill, QColor outline, QColor text_color, int h, double start, + QColor fill, QColor outline, int h, double start, double end, int y) const; void draw_error(QPainter &p, const QString &message, - int left, int right); + const RowItemPaintParams &pp); void draw_unresolved_period(QPainter &p, int h, int left, int right) const; diff --git a/pv/view/header.cpp b/pv/view/header.cpp index 08b3fdd2..2269849c 100644 --- a/pv/view/header.cpp +++ b/pv/view/header.cpp @@ -35,7 +35,7 @@ #include #include -#include +#include #include using boost::make_filter_iterator; diff --git a/pv/view/logicsignal.cpp b/pv/view/logicsignal.cpp index 22b39bbb..48d2debc 100644 --- a/pv/view/logicsignal.cpp +++ b/pv/view/logicsignal.cpp @@ -31,10 +31,10 @@ #include "logicsignal.hpp" #include "view.hpp" -#include +#include #include #include -#include +#include #include #include @@ -145,63 +145,52 @@ std::pair LogicSignal::v_extents() const return make_pair(-SignalHeight - SignalMargin, SignalMargin); } -void LogicSignal::paint_back(QPainter &p, int left, int right) +void LogicSignal::paint_back(QPainter &p, const RowItemPaintParams &pp) { if (channel_->enabled()) - paint_axis(p, get_visual_y(), left, right); + paint_axis(p, pp, get_visual_y()); } -void LogicSignal::paint_mid(QPainter &p, int left, int right) +void LogicSignal::paint_mid(QPainter &p, const RowItemPaintParams &pp) { - using pv::view::View; - QLineF *line; vector< pair > edges; assert(channel_); assert(data_); - assert(right >= left); assert(owner_); const int y = get_visual_y(); - const View *const view = owner_->view(); - assert(view); - - const double scale = view->scale(); - assert(scale > 0); - - const double offset = view->offset(); - if (!channel_->enabled()) return; const float high_offset = y - SignalHeight + 0.5f; const float low_offset = y + 0.5f; - const deque< shared_ptr > &snapshots = - data_->get_snapshots(); - if (snapshots.empty()) + const deque< shared_ptr > &segments = + data_->logic_segments(); + if (segments.empty()) return; - const shared_ptr &snapshot = - snapshots.front(); + const shared_ptr &segment = + segments.front(); - double samplerate = data_->samplerate(); + double samplerate = segment->samplerate(); // Show sample rate as 1Hz when it is unknown if (samplerate == 0.0) samplerate = 1.0; - const double pixels_offset = offset / scale; - const double start_time = data_->get_start_time(); - const int64_t last_sample = snapshot->get_sample_count() - 1; - const double samples_per_pixel = samplerate * scale; - const double start = samplerate * (offset - start_time); - const double end = start + samples_per_pixel * (right - left); + const double pixels_offset = pp.pixels_offset(); + const double start_time = segment->start_time(); + const int64_t last_sample = segment->get_sample_count() - 1; + const double samples_per_pixel = samplerate * pp.scale(); + const double start = samplerate * (pp.offset() - start_time); + const double end = start + samples_per_pixel * pp.width(); - snapshot->get_subsampled_edges(edges, + segment->get_subsampled_edges(edges, min(max((int64_t)floor(start), (int64_t)0), last_sample), min(max((int64_t)ceil(end), (int64_t)0), last_sample), samples_per_pixel / Oversampling, channel_->index()); @@ -214,7 +203,7 @@ void LogicSignal::paint_mid(QPainter &p, int left, int right) for (auto i = edges.cbegin() + 1; i != edges.cend() - 1; i++) { const float x = ((*i).first / samples_per_pixel - - pixels_offset) + left; + pixels_offset) + pp.left(); *line++ = QLineF(x, high_offset, x, low_offset); } @@ -228,18 +217,16 @@ void LogicSignal::paint_mid(QPainter &p, int left, int right) p.setPen(HighColour); paint_caps(p, cap_lines, edges, true, samples_per_pixel, - pixels_offset, left, high_offset); + pixels_offset, pp.left(), high_offset); p.setPen(LowColour); paint_caps(p, cap_lines, edges, false, samples_per_pixel, - pixels_offset, left, low_offset); + pixels_offset, pp.left(), low_offset); delete[] cap_lines; } -void LogicSignal::paint_fore(QPainter &p, int left, int right) +void LogicSignal::paint_fore(QPainter &p, const RowItemPaintParams &pp) { - (void)left; - // Draw the trigger marker if (!trigger_match_) return; @@ -262,7 +249,7 @@ void LogicSignal::paint_fore(QPainter &p, int left, int right) const int pad = TriggerMarkerPadding; const QSize size = pixmap->size(); const QPoint point( - right - size.width() - pad * 2, + pp.right() - size.width() - pad * 2, y - (SignalHeight + size.height()) / 2); p.setPen(QPen(Qt::NoPen)); diff --git a/pv/view/logicsignal.hpp b/pv/view/logicsignal.hpp index 11f81770..c4588903 100644 --- a/pv/view/logicsignal.hpp +++ b/pv/view/logicsignal.hpp @@ -84,26 +84,23 @@ class LogicSignal : public Signal /** * Paints the background layer of the signal with a QPainter * @param p the QPainter to paint into. - * @param left the x-coordinate of the left edge of the signal. - * @param right the x-coordinate of the right edge of the signal. + * @param pp the painting parameters object to paint with.. **/ - void paint_back(QPainter &p, int left, int right); + void paint_back(QPainter &p, const RowItemPaintParams &pp); /** * Paints the mid-layer of the signal with a QPainter * @param p the QPainter to paint into. - * @param left the x-coordinate of the left edge of the signal. - * @param right the x-coordinate of the right edge of the signal. + * @param pp the painting parameters object to paint with.. **/ - void paint_mid(QPainter &p, int left, int right); + void paint_mid(QPainter &p, const RowItemPaintParams &pp); /** * Paints the foreground layer of the signal with a QPainter * @param p the QPainter to paint into. - * @param left the x-coordinate of the left edge of the signal - * @param right the x-coordinate of the right edge of the signal + * @param pp the painting parameters object to paint with. **/ - virtual void paint_fore(QPainter &p, int left, int right); + virtual void paint_fore(QPainter &p, const RowItemPaintParams &pp); private: void paint_caps(QPainter &p, QLineF *const lines, diff --git a/pv/view/rowitem.cpp b/pv/view/rowitem.cpp index 6e87de10..597c4a13 100644 --- a/pv/view/rowitem.cpp +++ b/pv/view/rowitem.cpp @@ -120,25 +120,22 @@ QPoint RowItem::point() const return QPoint(0, visual_v_offset()); } -void RowItem::paint_back(QPainter &p, int left, int right) +void RowItem::paint_back(QPainter &p, const RowItemPaintParams &pp) { (void)p; - (void)left; - (void)right; + (void)pp; } -void RowItem::paint_mid(QPainter &p, int left, int right) +void RowItem::paint_mid(QPainter &p, const RowItemPaintParams &pp) { (void)p; - (void)left; - (void)right; + (void)pp; } -void RowItem::paint_fore(QPainter &p, int left, int right) +void RowItem::paint_fore(QPainter &p, const RowItemPaintParams &pp) { (void)p; - (void)left; - (void)right; + (void)pp; } void RowItem::hover_point_changed() diff --git a/pv/view/rowitem.hpp b/pv/view/rowitem.hpp index d6233e8c..39c6f040 100644 --- a/pv/view/rowitem.hpp +++ b/pv/view/rowitem.hpp @@ -25,6 +25,7 @@ #include +#include "rowitempaintparams.hpp" #include "selectableitem.hpp" namespace pv { @@ -112,26 +113,23 @@ class RowItem : public SelectableItem, /** * Paints the background layer of the trace with a QPainter * @param p the QPainter to paint into. - * @param left the x-coordinate of the left edge of the signal - * @param right the x-coordinate of the right edge of the signal + * @param pp the painting parameters object to paint with. **/ - virtual void paint_back(QPainter &p, int left, int right); + virtual void paint_back(QPainter &p, const RowItemPaintParams &pp); /** * Paints the mid-layer of the trace with a QPainter * @param p the QPainter to paint into. - * @param left the x-coordinate of the left edge of the signal - * @param right the x-coordinate of the right edge of the signal + * @param pp the painting parameters object to paint with. **/ - virtual void paint_mid(QPainter &p, int left, int right); + virtual void paint_mid(QPainter &p, const RowItemPaintParams &pp); /** * Paints the foreground layer of the trace with a QPainter * @param p the QPainter to paint into. - * @param left the x-coordinate of the left edge of the signal - * @param right the x-coordinate of the right edge of the signal + * @param pp the painting parameters object to paint with. **/ - virtual void paint_fore(QPainter &p, int left, int right); + virtual void paint_fore(QPainter &p, const RowItemPaintParams &pp); /** * Paints the signal label. diff --git a/pv/view/rowitemiterator.hpp b/pv/view/rowitemiterator.hpp index 110dc574..577b4713 100644 --- a/pv/view/rowitemiterator.hpp +++ b/pv/view/rowitemiterator.hpp @@ -31,7 +31,7 @@ #include -#include +#include namespace pv { namespace view { diff --git a/pv/view/rowitempaintparams.cpp b/pv/view/rowitempaintparams.cpp new file mode 100644 index 00000000..c46d715b --- /dev/null +++ b/pv/view/rowitempaintparams.cpp @@ -0,0 +1,52 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2014 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include +#include + +#include "rowitempaintparams.hpp" + +namespace pv { +namespace view { + +RowItemPaintParams::RowItemPaintParams( + int left, int right, double scale, double offset) : + left_(left), + right_(right), + scale_(scale), + offset_(offset) { + assert(left <= right); + assert(scale > 0.0); +} + +QFont RowItemPaintParams::font() +{ + return QApplication::font(); +} + +int RowItemPaintParams::text_height() { + QFontMetrics m(font()); + return m.boundingRect(QRect(), 0, "Tg").height(); +} + +} // namespace view +} // namespace pv diff --git a/pv/view/rowitempaintparams.hpp b/pv/view/rowitempaintparams.hpp new file mode 100644 index 00000000..ec66076b --- /dev/null +++ b/pv/view/rowitempaintparams.hpp @@ -0,0 +1,73 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2014 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef PULSEVIEW_PV_VIEW_ROWITEMPAINTPARAMS_H +#define PULSEVIEW_PV_VIEW_ROWITEMPAINTPARAMS_H + +#include + +namespace pv { +namespace view { + +class RowItemPaintParams +{ +public: + RowItemPaintParams(int left, int right, double scale, double offset); + + int left() const { + return left_; + } + + int right() const { + return right_; + } + + double scale() const { + return scale_; + } + + double offset() const { + return offset_; + } + + int width() const { + return right_ - left_; + } + + double pixels_offset() const { + return offset_ / scale_; + } + +public: + static QFont font(); + + static int text_height(); + +private: + int left_; + int right_; + double scale_; + double offset_; +}; + +} // namespace view +} // namespace pv + +#endif // PULSEVIEW_PV_VIEW_ROWITEMPAINTPARAMS_H diff --git a/pv/view/ruler.cpp b/pv/view/ruler.cpp index 56651169..ee521f0e 100644 --- a/pv/view/ruler.cpp +++ b/pv/view/ruler.cpp @@ -32,7 +32,6 @@ namespace view { const int Ruler::RulerHeight = 30; const int Ruler::MinorTickSubdivision = 4; -const int Ruler::ScaleUnits[3] = {1, 2, 5}; const int Ruler::HoverArrowSize = 5; @@ -57,11 +56,8 @@ void Ruler::paintEvent(QPaintEvent*) QPainter p(this); p.setRenderHint(QPainter::Antialiasing); - std::pair spacing = - calculate_tick_spacing(p, view_.scale(), view_.offset()); - - double tick_period = spacing.first; - unsigned int prefix = spacing.second; + const double tick_period = view_.tick_period(); + const unsigned int prefix = view_.tick_prefix(); const int text_height = p.boundingRect(0, 0, INT_MAX, INT_MAX, AlignLeft | AlignTop, "8").height(); @@ -137,41 +133,5 @@ void Ruler::hover_point_changed() update(); } -std::pair Ruler::calculate_tick_spacing( - QPainter& p, double scale, double offset) -{ - const double SpacingIncrement = 32.0f; - const double MinValueSpacing = 32.0f; - - double min_width = SpacingIncrement, typical_width; - - double tick_period; - unsigned int prefix; - - do { - const double min_period = scale * min_width; - - const int order = (int)floorf(log10f(min_period)); - const double order_decimal = pow(10.0, order); - - unsigned int unit = 0; - - do { - tick_period = order_decimal * ScaleUnits[unit++]; - } while (tick_period < min_period && unit < countof(ScaleUnits)); - - prefix = (order - pv::util::FirstSIPrefixPower) / 3; - - typical_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, - AlignLeft | AlignTop, pv::util::format_time(offset, - prefix)).width() + MinValueSpacing; - - min_width += SpacingIncrement; - - } while(typical_width > tick_period / scale); - - return std::make_pair(tick_period, prefix); -} - } // namespace view } // namespace pv diff --git a/pv/view/ruler.hpp b/pv/view/ruler.hpp index 438b862c..073c86c9 100644 --- a/pv/view/ruler.hpp +++ b/pv/view/ruler.hpp @@ -35,25 +35,12 @@ class Ruler : public MarginWidget private: static const int RulerHeight; static const int MinorTickSubdivision; - static const int ScaleUnits[3]; static const int HoverArrowSize; public: Ruler(View &parent); - /** - * Find a tick spacing and number formatting that does not cause - * the values to collide. - * @param p A QPainter used to determine the needed space for the values. - * @param scale A pv::view::View's scale. - * @param offset A pv::view::View's offset. - * - * @return The tick period to use in 'first' and the prefix in 'second'. - */ - static std::pair calculate_tick_spacing( - QPainter& p, double scale, double offset); - public: QSize sizeHint() const; diff --git a/pv/view/selectableitem.cpp b/pv/view/selectableitem.cpp index b699005f..6921f19a 100644 --- a/pv/view/selectableitem.cpp +++ b/pv/view/selectableitem.cpp @@ -85,5 +85,10 @@ QPen SelectableItem::highlight_pen() Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); } +QColor SelectableItem::select_text_colour(QColor background) +{ + return (background.lightness() > 64) ? Qt::black : Qt::white; +} + } // namespace view } // namespace pv diff --git a/pv/view/selectableitem.hpp b/pv/view/selectableitem.hpp index 36ff0dbc..1f594490 100644 --- a/pv/view/selectableitem.hpp +++ b/pv/view/selectableitem.hpp @@ -83,6 +83,15 @@ class SelectableItem : public QObject */ virtual QPoint point() const = 0; +public: + /** + * Gets the text colour. + * @remarks This colour is computed by comparing the lightness + * of the trace colour against a threshold to determine whether + * white or black would be more visible. + */ + static QColor select_text_colour(QColor background); + public: virtual QMenu* create_context_menu(QWidget *parent); diff --git a/pv/view/timemarker.cpp b/pv/view/timemarker.cpp index 6571bea9..9d6e7fde 100644 --- a/pv/view/timemarker.cpp +++ b/pv/view/timemarker.cpp @@ -18,6 +18,10 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + +#include + #include "timemarker.hpp" #include "view.hpp" @@ -25,11 +29,18 @@ #include #include +#include #include +using std::max; +using std::min; + namespace pv { namespace view { +const int TimeMarker::ArrowSize = 4; +const int TimeMarker::Offset = 1; + TimeMarker::TimeMarker(View &view, const QColor &colour, double time) : view_(view), colour_(colour), @@ -71,10 +82,59 @@ void TimeMarker::set_time(double time) void TimeMarker::paint(QPainter &p, const QRect &rect) { const float x = get_x(); - p.setPen(colour_); + p.setPen(colour_.darker()); p.drawLine(QPointF(x, rect.top()), QPointF(x, rect.bottom())); } +void TimeMarker::paint_label(QPainter &p, const QRect &rect) +{ + const qreal x = (time_ - view_.offset()) / view_.scale(); + const QRectF r(get_label_rect(rect)); + + const QPointF points[] = { + r.topLeft(), + r.bottomLeft(), + QPointF(max(r.left(), x - ArrowSize), r.bottom()), + QPointF(x, rect.bottom()), + QPointF(min(r.right(), x + ArrowSize), r.bottom()), + r.bottomRight(), + r.topRight() + }; + + const QPointF highlight_points[] = { + QPointF(r.left() + 1, r.top() + 1), + QPointF(r.left() + 1, r.bottom() - 1), + QPointF(max(r.left() + 1, x - ArrowSize), r.bottom() - 1), + QPointF(min(max(r.left() + 1, x), r.right() - 1), + rect.bottom() - 1), + QPointF(min(r.right() - 1, x + ArrowSize), r.bottom() - 1), + QPointF(r.right() - 1, r.bottom() - 1), + QPointF(r.right() - 1, r.top() + 1), + }; + + if (selected()) { + p.setPen(highlight_pen()); + p.setBrush(Qt::transparent); + p.drawPolygon(points, countof(points)); + } + + p.setPen(Qt::transparent); + p.setBrush(colour_); + p.drawPolygon(points, countof(points)); + + p.setPen(colour_.lighter()); + p.setBrush(Qt::transparent); + p.drawPolygon(highlight_points, countof(highlight_points)); + + p.setPen(colour_.darker()); + p.setBrush(Qt::transparent); + p.drawPolygon(points, countof(points)); + + p.setPen(select_text_colour(colour_)); + p.drawText(r, Qt::AlignCenter | Qt::AlignVCenter, + pv::util::format_time(time_, view_.tick_prefix(), 2)); +} + pv::widgets::Popup* TimeMarker::create_popup(QWidget *parent) { using pv::widgets::Popup; diff --git a/pv/view/timemarker.hpp b/pv/view/timemarker.hpp index 0103fb04..21de2625 100644 --- a/pv/view/timemarker.hpp +++ b/pv/view/timemarker.hpp @@ -41,6 +41,10 @@ class TimeMarker : public SelectableItem { Q_OBJECT +public: + static const int ArrowSize; + static const int Offset; + protected: /** * Constructor. @@ -86,10 +90,8 @@ class TimeMarker : public SelectableItem * Paints the marker's label to the ruler. * @param p The painter to draw with. * @param rect The rectangle of the ruler client area. - * @param prefix The SI prefix to paint time value with. */ - virtual void paint_label(QPainter &p, const QRect &rect, - unsigned int prefix) = 0; + void paint_label(QPainter &p, const QRect &rect); pv::widgets::Popup* create_popup(QWidget *parent); diff --git a/pv/view/trace.cpp b/pv/view/trace.cpp index 1734921a..e9235e56 100644 --- a/pv/view/trace.cpp +++ b/pv/view/trace.cpp @@ -115,7 +115,7 @@ void Trace::paint_label(QPainter &p, int right, bool hover) p.drawPolygon(points, countof(points)); // Paint the text - p.setPen(get_text_colour()); + p.setPen(select_text_colour(colour_)); p.setFont(QApplication::font()); p.drawText(QRectF(r.x(), r.y(), r.width() - label_arrow_length, r.height()), @@ -162,15 +162,10 @@ QRectF Trace::label_rect(int right) const label_size.height()); } -QColor Trace::get_text_colour() const -{ - return (colour_.lightness() > 64) ? Qt::black : Qt::white; -} - -void Trace::paint_axis(QPainter &p, int y, int left, int right) +void Trace::paint_axis(QPainter &p, const RowItemPaintParams &pp, int y) { p.setPen(AxisPen); - p.drawLine(QPointF(left, y + 0.5f), QPointF(right, y + 0.5f)); + p.drawLine(QPointF(pp.left(), y + 0.5f), QPointF(pp.right(), y + 0.5f)); } void Trace::add_colour_option(QWidget *parent, QFormLayout *form) diff --git a/pv/view/trace.hpp b/pv/view/trace.hpp index 88df33ea..a82520cc 100644 --- a/pv/view/trace.hpp +++ b/pv/view/trace.hpp @@ -95,23 +95,13 @@ class Trace : public RowItem QRectF label_rect(int right) const; protected: - - /** - * Gets the text colour. - * @remarks This colour is computed by comparing the lightness - * of the trace colour against a threshold to determine whether - * white or black would be more visible. - */ - QColor get_text_colour() const; - /** * Paints a zero axis across the viewport. * @param p the QPainter to paint into. + * @param pp the painting parameters object to paint with. * @param y the y-offset of the axis. - * @param left the x-coordinate of the left edge of the view. - * @param right the x-coordinate of the right edge of the view. */ - void paint_axis(QPainter &p, int y, int left, int right); + void paint_axis(QPainter &p, const RowItemPaintParams &pp, int y); void add_colour_option(QWidget *parent, QFormLayout *form); diff --git a/pv/view/view.cpp b/pv/view/view.cpp index c9606353..d502acfc 100644 --- a/pv/view/view.cpp +++ b/pv/view/view.cpp @@ -22,13 +22,17 @@ #include #endif +#include + #include #include #include #include #include +#include #include +#include #include #include @@ -44,13 +48,18 @@ #include "view.hpp" #include "viewport.hpp" -#include "pv/sigsession.hpp" +#include "pv/session.hpp" #include "pv/data/logic.hpp" -#include "pv/data/logicsnapshot.hpp" +#include "pv/data/logicsegment.hpp" +#include "pv/util.hpp" using boost::shared_lock; using boost::shared_mutex; + using pv::data::SignalData; +using pv::data::Segment; +using pv::util::format_time; + using std::back_inserter; using std::deque; using std::dynamic_pointer_cast; @@ -75,6 +84,8 @@ const double View::MinScale = 1e-15; const int View::MaxScrollValue = INT_MAX / 2; +const int View::ScaleUnits[3] = {1, 2, 5}; + const QColor View::CursorAreaColour(220, 231, 243); const QSizeF View::LabelPadding(4, 0); @@ -90,6 +101,8 @@ View::View(Session &session, QWidget *parent) : offset_(0), v_offset_(0), updating_scroll_(false), + tick_period_(0.0), + tick_prefix_(0), show_cursors_(false), cursors_(*this), hover_point_(-1, -1) @@ -147,6 +160,9 @@ View::View(Session &session, QWidget *parent) : // make sure the transparent widgets are on the top cursorheader_->raise(); header_->raise(); + + // Update the zoom state + calculate_tick_spacing(); } Session& View::session() @@ -199,6 +215,16 @@ unsigned int View::depth() const return 0; } +unsigned int View::tick_prefix() const +{ + return tick_prefix_; +} + +double View::tick_period() const +{ + return tick_period_; +} + void View::zoom(double steps) { zoom(steps, viewport_->width() / 2); @@ -237,7 +263,10 @@ void View::zoom_one_to_one() double samplerate = 0.0; for (const shared_ptr d : visible_data) { assert(d); - samplerate = max(samplerate, d->samplerate()); + const vector< shared_ptr > segments = + d->segments(); + for (const shared_ptr &s : segments) + samplerate = max(samplerate, s->samplerate()); } if (samplerate == 0.0) @@ -256,6 +285,8 @@ void View::set_scale_offset(double scale, double offset) scale_ = scale; offset_ = offset; + calculate_tick_spacing(); + update_scroll(); ruler_->update(); cursorheader_->update(); @@ -279,22 +310,26 @@ set< shared_ptr > View::get_visible_data() const pair View::get_time_extents() const { - const set< shared_ptr > visible_data = get_visible_data(); - if (visible_data.empty()) - return make_pair(0.0, 0.0); - double left_time = DBL_MAX, right_time = DBL_MIN; + const set< shared_ptr > visible_data = get_visible_data(); for (const shared_ptr d : visible_data) { - const double start_time = d->get_start_time(); - double samplerate = d->samplerate(); - samplerate = (samplerate <= 0.0) ? 1.0 : samplerate; - - left_time = min(left_time, start_time); - right_time = max(right_time, start_time + - d->get_max_sample_count() / samplerate); + const vector< shared_ptr > segments = + d->segments(); + for (const shared_ptr &s : segments) { + double samplerate = s->samplerate(); + samplerate = (samplerate <= 0.0) ? 1.0 : samplerate; + + const double start_time = s->start_time(); + left_time = min(left_time, start_time); + right_time = max(right_time, start_time + + d->get_max_sample_count() / samplerate); + } } + if (left_time == DBL_MAX && right_time == DBL_MIN) + return make_pair(0.0, 0.0); + assert(left_time < right_time); return make_pair(left_time, right_time); } @@ -379,6 +414,40 @@ void View::set_zoom(double scale, int offset) set_scale_offset(new_scale, new_offset); } +void View::calculate_tick_spacing() +{ + const double SpacingIncrement = 32.0f; + const double MinValueSpacing = 32.0f; + + double min_width = SpacingIncrement, typical_width; + + QFontMetrics m(QApplication::font()); + + do { + const double min_period = scale_ * min_width; + + const int order = (int)floorf(log10f(min_period)); + const double order_decimal = pow(10.0, order); + + unsigned int unit = 0; + + do { + tick_period_ = order_decimal * ScaleUnits[unit++]; + } while (tick_period_ < min_period && + unit < countof(ScaleUnits)); + + tick_prefix_ = (order - pv::util::FirstSIPrefixPower) / 3; + + typical_width = m.boundingRect(0, 0, INT_MAX, INT_MAX, + Qt::AlignLeft | Qt::AlignTop, + format_time(offset_, tick_prefix_)).width() + + MinValueSpacing; + + min_width += SpacingIncrement; + + } while(typical_width > tick_period_ / scale_); +} + void View::update_scroll() { assert(viewport_); diff --git a/pv/view/view.hpp b/pv/view/view.hpp index e763da7e..4561cec6 100644 --- a/pv/view/view.hpp +++ b/pv/view/view.hpp @@ -63,6 +63,8 @@ class View : public QAbstractScrollArea, public RowItemOwner { static const int MaxScrollValue; + static const int ScaleUnits[3]; + public: static const QColor CursorAreaColour; @@ -100,6 +102,16 @@ class View : public QAbstractScrollArea, public RowItemOwner { double offset() const; int owner_visual_v_offset() const; + /** + * Returns the SI prefix to apply to the graticule time markings. + */ + unsigned int tick_prefix() const; + + /** + * Returns period of the graticule time markings. + */ + double tick_period() const; + /** * Returns the number of nested parents that this row item owner has. */ @@ -175,6 +187,12 @@ class View : public QAbstractScrollArea, public RowItemOwner { */ void set_zoom(double scale, int offset); + /** + * Find a tick spacing and number formatting that does not cause + * the values to collide. + */ + void calculate_tick_spacing(); + void update_scroll(); void update_layout(); @@ -252,6 +270,9 @@ private Q_SLOTS: int v_offset_; bool updating_scroll_; + double tick_period_; + unsigned int tick_prefix_; + bool show_cursors_; CursorPair cursors_; diff --git a/pv/view/viewport.cpp b/pv/view/viewport.cpp index fbbb52bf..f5f0ab59 100644 --- a/pv/view/viewport.cpp +++ b/pv/view/viewport.cpp @@ -22,11 +22,12 @@ #include #include +#include "rowitempaintparams.hpp" #include "signal.hpp" #include "view.hpp" #include "viewport.hpp" -#include +#include #include @@ -69,18 +70,20 @@ void Viewport::paintEvent(QPaintEvent*) if (view_.cursors_shown()) view_.cursors().draw_viewport_background(p, rect()); + const RowItemPaintParams pp(0, width(), view_.scale(), view_.offset()); + // Plot the signal for (const shared_ptr r : row_items) { assert(r); - r->paint_back(p, 0, width()); + r->paint_back(p, pp); } for (const shared_ptr r : row_items) - r->paint_mid(p, 0, width()); + r->paint_mid(p, pp); for (const shared_ptr r : row_items) - r->paint_fore(p, 0, width()); + r->paint_fore(p, pp); if (view_.cursors_shown()) view_.cursors().draw_viewport_foreground(p, rect()); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7c454c02..f22f92ab 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -46,14 +46,14 @@ find_package(Qt4 REQUIRED) set(pulseview_TEST_SOURCES ${PROJECT_SOURCE_DIR}/pv/devicemanager.cpp - ${PROJECT_SOURCE_DIR}/pv/sigsession.cpp + ${PROJECT_SOURCE_DIR}/pv/session.cpp ${PROJECT_SOURCE_DIR}/pv/util.cpp ${PROJECT_SOURCE_DIR}/pv/view/cursorpair.cpp ${PROJECT_SOURCE_DIR}/pv/data/analog.cpp - ${PROJECT_SOURCE_DIR}/pv/data/analogsnapshot.cpp + ${PROJECT_SOURCE_DIR}/pv/data/analogsegment.cpp ${PROJECT_SOURCE_DIR}/pv/data/logic.cpp - ${PROJECT_SOURCE_DIR}/pv/data/logicsnapshot.cpp - ${PROJECT_SOURCE_DIR}/pv/data/snapshot.cpp + ${PROJECT_SOURCE_DIR}/pv/data/logicsegment.cpp + ${PROJECT_SOURCE_DIR}/pv/data/segment.cpp ${PROJECT_SOURCE_DIR}/pv/data/signaldata.cpp ${PROJECT_SOURCE_DIR}/pv/prop/double.cpp ${PROJECT_SOURCE_DIR}/pv/prop/enum.cpp @@ -80,14 +80,14 @@ set(pulseview_TEST_SOURCES ${PROJECT_SOURCE_DIR}/pv/widgets/colourpopup.cpp ${PROJECT_SOURCE_DIR}/pv/widgets/popup.cpp ${PROJECT_SOURCE_DIR}/pv/widgets/wellarray.cpp - data/analogsnapshot.cpp - data/logicsnapshot.cpp + data/analogsegment.cpp + data/logicsegment.cpp test.cpp ) # This list includes only QObject derived class headers. set(pulseview_TEST_HEADERS - ${PROJECT_SOURCE_DIR}/pv/sigsession.hpp + ${PROJECT_SOURCE_DIR}/pv/session.hpp ${PROJECT_SOURCE_DIR}/pv/prop/double.hpp ${PROJECT_SOURCE_DIR}/pv/prop/enum.hpp ${PROJECT_SOURCE_DIR}/pv/prop/int.hpp diff --git a/test/data/analogsnapshot.cpp b/test/data/analogsnapshot.cpp index 3dd04ed6..23f1b5c5 100644 --- a/test/data/analogsnapshot.cpp +++ b/test/data/analogsnapshot.cpp @@ -24,13 +24,13 @@ #include -#include +#include -using pv::data::AnalogSnapshot; +using pv::data::AnalogSegment; -BOOST_AUTO_TEST_SUITE(AnalogSnapshotTest) +BOOST_AUTO_TEST_SUITE(AnalogSegmentTest) -void push_analog(AnalogSnapshot &s, unsigned int num_samples, +void push_analog(AnalogSegment &s, unsigned int num_samples, float value) { float *const data = new float[num_samples]; @@ -43,15 +43,15 @@ void push_analog(AnalogSnapshot &s, unsigned int num_samples, BOOST_AUTO_TEST_CASE(Basic) { - // Create an empty AnalogSnapshot object - AnalogSnapshot s; + // Create an empty AnalogSegment object + AnalogSegment s; - //----- Test AnalogSnapshot::push_analog -----// + //----- Test AnalogSegment::push_analog -----// BOOST_CHECK(s.get_sample_count() == 0); - for (unsigned int i = 0; i < AnalogSnapshot::ScaleStepCount; i++) + for (unsigned int i = 0; i < AnalogSegment::ScaleStepCount; i++) { - const AnalogSnapshot::Envelope &m = s.envelope_levels_[i]; + const AnalogSegment::Envelope &m = s.envelope_levels_[i]; BOOST_CHECK_EQUAL(m.length, 0); BOOST_CHECK_EQUAL(m.data_length, 0); BOOST_CHECK(m.samples == NULL); @@ -63,9 +63,9 @@ BOOST_AUTO_TEST_CASE(Basic) BOOST_CHECK(s.get_sample_count() == 8); // There should not be enough samples to have a single mip map sample - for (unsigned int i = 0; i < AnalogSnapshot::ScaleStepCount; i++) + for (unsigned int i = 0; i < AnalogSegment::ScaleStepCount; i++) { - const AnalogSnapshot::Envelope &m = s.envelope_levels_[i]; + const AnalogSegment::Envelope &m = s.envelope_levels_[i]; BOOST_CHECK_EQUAL(m.length, 0); BOOST_CHECK_EQUAL(m.data_length, 0); BOOST_CHECK(m.samples == NULL); @@ -76,17 +76,17 @@ BOOST_AUTO_TEST_CASE(Basic) // There should now be enough data for exactly one sample // in mip map level 0, and that sample should be 0 - const AnalogSnapshot::Envelope &e0 = s.envelope_levels_[0]; + const AnalogSegment::Envelope &e0 = s.envelope_levels_[0]; BOOST_CHECK_EQUAL(e0.length, 1); - BOOST_CHECK_EQUAL(e0.data_length, AnalogSnapshot::EnvelopeDataUnit); + BOOST_CHECK_EQUAL(e0.data_length, AnalogSegment::EnvelopeDataUnit); BOOST_REQUIRE(e0.samples != NULL); BOOST_CHECK_EQUAL(e0.samples[0].min, 0.0f); BOOST_CHECK_EQUAL(e0.samples[0].max, 1.0f); // The higher levels should still be empty - for (unsigned int i = 1; i < AnalogSnapshot::ScaleStepCount; i++) + for (unsigned int i = 1; i < AnalogSegment::ScaleStepCount; i++) { - const AnalogSnapshot::Envelope &m = s.envelope_levels_[i]; + const AnalogSegment::Envelope &m = s.envelope_levels_[i]; BOOST_CHECK_EQUAL(m.length, 0); BOOST_CHECK_EQUAL(m.data_length, 0); BOOST_CHECK(m.samples == NULL); @@ -96,16 +96,16 @@ BOOST_AUTO_TEST_CASE(Basic) push_analog(s, 240, -1.0f); BOOST_CHECK_EQUAL(e0.length, 16); - BOOST_CHECK_EQUAL(e0.data_length, AnalogSnapshot::EnvelopeDataUnit); + BOOST_CHECK_EQUAL(e0.data_length, AnalogSegment::EnvelopeDataUnit); for (unsigned int i = 1; i < e0.length; i++) { BOOST_CHECK_EQUAL(e0.samples[i].min, -1.0f); BOOST_CHECK_EQUAL(e0.samples[i].max, -1.0f); } - const AnalogSnapshot::Envelope &e1 = s.envelope_levels_[1]; + const AnalogSegment::Envelope &e1 = s.envelope_levels_[1]; BOOST_CHECK_EQUAL(e1.length, 1); - BOOST_CHECK_EQUAL(e1.data_length, AnalogSnapshot::EnvelopeDataUnit); + BOOST_CHECK_EQUAL(e1.data_length, AnalogSegment::EnvelopeDataUnit); BOOST_REQUIRE(e1.samples != NULL); BOOST_CHECK_EQUAL(e1.samples[0].min, -1.0f); BOOST_CHECK_EQUAL(e1.samples[0].max, 1.0f); diff --git a/test/data/decoderstack.cpp b/test/data/decoderstack.cpp index baeec2d6..9a0ab355 100644 --- a/test/data/decoderstack.cpp +++ b/test/data/decoderstack.cpp @@ -25,7 +25,7 @@ #include "../../pv/data/decoderstack.h" #include "../../pv/devicemanager.h" -#include "../../pv/sigsession.h" +#include "../../pv/session.h" #include "../../pv/view/decodetrace.h" using pv::data::DecoderStack; diff --git a/test/data/logicsnapshot.cpp b/test/data/logicsnapshot.cpp index 4ad23aa4..3a6821d6 100644 --- a/test/data/logicsnapshot.cpp +++ b/test/data/logicsnapshot.cpp @@ -24,14 +24,14 @@ #include -#include +#include -using pv::data::LogicSnapshot; +using pv::data::LogicSegment; using std::vector; -BOOST_AUTO_TEST_SUITE(LogicSnapshotTest) +BOOST_AUTO_TEST_SUITE(LogicSegmentTest) -void push_logic(LogicSnapshot &s, unsigned int length, uint8_t value) +void push_logic(LogicSegment &s, unsigned int length, uint8_t value) { sr_datafeed_logic logic; logic.unitsize = 1; @@ -44,37 +44,37 @@ void push_logic(LogicSnapshot &s, unsigned int length, uint8_t value) BOOST_AUTO_TEST_CASE(Pow2) { - BOOST_CHECK_EQUAL(LogicSnapshot::pow2_ceil(0, 0), 0); - BOOST_CHECK_EQUAL(LogicSnapshot::pow2_ceil(1, 0), 1); - BOOST_CHECK_EQUAL(LogicSnapshot::pow2_ceil(2, 0), 2); + BOOST_CHECK_EQUAL(LogicSegment::pow2_ceil(0, 0), 0); + BOOST_CHECK_EQUAL(LogicSegment::pow2_ceil(1, 0), 1); + BOOST_CHECK_EQUAL(LogicSegment::pow2_ceil(2, 0), 2); BOOST_CHECK_EQUAL( - LogicSnapshot::pow2_ceil(INT64_MIN, 0), INT64_MIN); + LogicSegment::pow2_ceil(INT64_MIN, 0), INT64_MIN); BOOST_CHECK_EQUAL( - LogicSnapshot::pow2_ceil(INT64_MAX, 0), INT64_MAX); + LogicSegment::pow2_ceil(INT64_MAX, 0), INT64_MAX); - BOOST_CHECK_EQUAL(LogicSnapshot::pow2_ceil(0, 1), 0); - BOOST_CHECK_EQUAL(LogicSnapshot::pow2_ceil(1, 1), 2); - BOOST_CHECK_EQUAL(LogicSnapshot::pow2_ceil(2, 1), 2); - BOOST_CHECK_EQUAL(LogicSnapshot::pow2_ceil(3, 1), 4); + BOOST_CHECK_EQUAL(LogicSegment::pow2_ceil(0, 1), 0); + BOOST_CHECK_EQUAL(LogicSegment::pow2_ceil(1, 1), 2); + BOOST_CHECK_EQUAL(LogicSegment::pow2_ceil(2, 1), 2); + BOOST_CHECK_EQUAL(LogicSegment::pow2_ceil(3, 1), 4); } BOOST_AUTO_TEST_CASE(Basic) { - // Create an empty LogicSnapshot object + // Create an empty LogicSegment object sr_datafeed_logic logic; logic.length = 0; logic.unitsize = 1; logic.data = NULL; - LogicSnapshot s(logic); + LogicSegment s(logic); - //----- Test LogicSnapshot::push_logic -----// + //----- Test LogicSegment::push_logic -----// BOOST_CHECK(s.get_sample_count() == 0); - for (unsigned int i = 0; i < LogicSnapshot::ScaleStepCount; i++) + for (unsigned int i = 0; i < LogicSegment::ScaleStepCount; i++) { - const LogicSnapshot::MipMapLevel &m = s.mip_map_[i]; + const LogicSegment::MipMapLevel &m = s.mip_map_[i]; BOOST_CHECK_EQUAL(m.length, 0); BOOST_CHECK_EQUAL(m.data_length, 0); BOOST_CHECK(m.data == NULL); @@ -86,9 +86,9 @@ BOOST_AUTO_TEST_CASE(Basic) BOOST_CHECK(s.get_sample_count() == 8); // There should not be enough samples to have a single mip map sample - for (unsigned int i = 0; i < LogicSnapshot::ScaleStepCount; i++) + for (unsigned int i = 0; i < LogicSegment::ScaleStepCount; i++) { - const LogicSnapshot::MipMapLevel &m = s.mip_map_[i]; + const LogicSegment::MipMapLevel &m = s.mip_map_[i]; BOOST_CHECK_EQUAL(m.length, 0); BOOST_CHECK_EQUAL(m.data_length, 0); BOOST_CHECK(m.data == NULL); @@ -99,16 +99,16 @@ BOOST_AUTO_TEST_CASE(Basic) // There should now be enough data for exactly one sample // in mip map level 0, and that sample should be 0 - const LogicSnapshot::MipMapLevel &m0 = s.mip_map_[0]; + const LogicSegment::MipMapLevel &m0 = s.mip_map_[0]; BOOST_CHECK_EQUAL(m0.length, 1); - BOOST_CHECK_EQUAL(m0.data_length, LogicSnapshot::MipMapDataUnit); + BOOST_CHECK_EQUAL(m0.data_length, LogicSegment::MipMapDataUnit); BOOST_REQUIRE(m0.data != NULL); BOOST_CHECK_EQUAL(((uint8_t*)m0.data)[0], 0x11); // The higher levels should still be empty - for (unsigned int i = 1; i < LogicSnapshot::ScaleStepCount; i++) + for (unsigned int i = 1; i < LogicSegment::ScaleStepCount; i++) { - const LogicSnapshot::MipMapLevel &m = s.mip_map_[i]; + const LogicSegment::MipMapLevel &m = s.mip_map_[i]; BOOST_CHECK_EQUAL(m.length, 0); BOOST_CHECK_EQUAL(m.data_length, 0); BOOST_CHECK(m.data == NULL); @@ -118,22 +118,22 @@ BOOST_AUTO_TEST_CASE(Basic) push_logic(s, 240, 0); BOOST_CHECK_EQUAL(m0.length, 16); - BOOST_CHECK_EQUAL(m0.data_length, LogicSnapshot::MipMapDataUnit); + BOOST_CHECK_EQUAL(m0.data_length, LogicSegment::MipMapDataUnit); BOOST_CHECK_EQUAL(((uint8_t*)m0.data)[1], 0x11); for (unsigned int i = 2; i < m0.length; i++) BOOST_CHECK_EQUAL(((uint8_t*)m0.data)[i], 0); - const LogicSnapshot::MipMapLevel &m1 = s.mip_map_[1]; + const LogicSegment::MipMapLevel &m1 = s.mip_map_[1]; BOOST_CHECK_EQUAL(m1.length, 1); - BOOST_CHECK_EQUAL(m1.data_length, LogicSnapshot::MipMapDataUnit); + BOOST_CHECK_EQUAL(m1.data_length, LogicSegment::MipMapDataUnit); BOOST_REQUIRE(m1.data != NULL); BOOST_CHECK_EQUAL(((uint8_t*)m1.data)[0], 0x11); - //----- Test LogicSnapshot::get_subsampled_edges -----// + //----- Test LogicSegment::get_subsampled_edges -----// // Test a full view at full zoom. - vector edges; + vector edges; s.get_subsampled_edges(edges, 0, 255, 1, 0); BOOST_REQUIRE_EQUAL(edges.size(), 4); @@ -167,7 +167,7 @@ BOOST_AUTO_TEST_CASE(LargeData) for (unsigned int i = 0; i < Length; i++) *data++ = (uint8_t)(i >> 8); - LogicSnapshot s(logic); + LogicSegment s(logic); delete[] (uint8_t*)logic.data; BOOST_CHECK(s.get_sample_count() == Length); @@ -175,7 +175,7 @@ BOOST_AUTO_TEST_CASE(LargeData) // Check mip map level 0 BOOST_CHECK_EQUAL(s.mip_map_[0].length, 62500); BOOST_CHECK_EQUAL(s.mip_map_[0].data_length, - LogicSnapshot::MipMapDataUnit); + LogicSegment::MipMapDataUnit); BOOST_REQUIRE(s.mip_map_[0].data != NULL); prev_sample = 0; @@ -198,7 +198,7 @@ BOOST_AUTO_TEST_CASE(LargeData) // Check mip map level 1 BOOST_CHECK_EQUAL(s.mip_map_[1].length, 3906); BOOST_CHECK_EQUAL(s.mip_map_[1].data_length, - LogicSnapshot::MipMapDataUnit); + LogicSegment::MipMapDataUnit); BOOST_REQUIRE(s.mip_map_[1].data != NULL); prev_sample = 0; @@ -216,7 +216,7 @@ BOOST_AUTO_TEST_CASE(LargeData) // Check mip map level 2 BOOST_CHECK_EQUAL(s.mip_map_[2].length, 244); BOOST_CHECK_EQUAL(s.mip_map_[2].data_length, - LogicSnapshot::MipMapDataUnit); + LogicSegment::MipMapDataUnit); BOOST_REQUIRE(s.mip_map_[2].data != NULL); prev_sample = 0; @@ -234,7 +234,7 @@ BOOST_AUTO_TEST_CASE(LargeData) // Check mip map level 3 BOOST_CHECK_EQUAL(s.mip_map_[3].length, 15); BOOST_CHECK_EQUAL(s.mip_map_[3].data_length, - LogicSnapshot::MipMapDataUnit); + LogicSegment::MipMapDataUnit); BOOST_REQUIRE(s.mip_map_[3].data != NULL); for (unsigned int i = 0; i < s.mip_map_[3].length; i++) @@ -242,17 +242,17 @@ BOOST_AUTO_TEST_CASE(LargeData) 0xFF); // Check the higher levels - for (unsigned int i = 4; i < LogicSnapshot::ScaleStepCount; i++) + for (unsigned int i = 4; i < LogicSegment::ScaleStepCount; i++) { - const LogicSnapshot::MipMapLevel &m = s.mip_map_[i]; + const LogicSegment::MipMapLevel &m = s.mip_map_[i]; BOOST_CHECK_EQUAL(m.length, 0); BOOST_CHECK_EQUAL(m.data_length, 0); BOOST_CHECK(m.data == NULL); } - //----- Test LogicSnapshot::get_subsampled_edges -----// + //----- Test LogicSegment::get_subsampled_edges -----// // Check in normal case - vector edges; + vector edges; s.get_subsampled_edges(edges, 0, Length-1, 1, 7); BOOST_CHECK_EQUAL(edges.size(), 32); @@ -278,9 +278,9 @@ BOOST_AUTO_TEST_CASE(Pulses) const int Period = 64; const int Length = Cycles * Period; - vector edges; + vector edges; - //----- Create a LogicSnapshot -----// + //----- Create a LogicSegment -----// sr_datafeed_logic logic; logic.unitsize = 1; logic.length = Length; @@ -293,14 +293,14 @@ BOOST_AUTO_TEST_CASE(Pulses) *p++ = 0x00; } - LogicSnapshot s(logic); + LogicSegment s(logic); delete[] (uint8_t*)logic.data; //----- Check the mip-map -----// // Check mip map level 0 BOOST_CHECK_EQUAL(s.mip_map_[0].length, 12); BOOST_CHECK_EQUAL(s.mip_map_[0].data_length, - LogicSnapshot::MipMapDataUnit); + LogicSegment::MipMapDataUnit); BOOST_REQUIRE(s.mip_map_[0].data != NULL); for (unsigned int i = 0; i < s.mip_map_[0].length;) { @@ -309,7 +309,7 @@ BOOST_AUTO_TEST_CASE(Pulses) for (int j = 1; i < s.mip_map_[0].length && - j < Period/LogicSnapshot::MipMapScaleFactor; j++) { + j < Period/LogicSegment::MipMapScaleFactor; j++) { BOOST_TEST_MESSAGE( "Testing mip_map[0].data[" << i << "]"); BOOST_CHECK_EQUAL(s.get_subsample(0, i++) & 0xFF, 0x00); @@ -317,8 +317,8 @@ BOOST_AUTO_TEST_CASE(Pulses) } // Check the higher levels are all inactive - for (unsigned int i = 1; i < LogicSnapshot::ScaleStepCount; i++) { - const LogicSnapshot::MipMapLevel &m = s.mip_map_[i]; + for (unsigned int i = 1; i < LogicSegment::ScaleStepCount; i++) { + const LogicSegment::MipMapLevel &m = s.mip_map_[i]; BOOST_CHECK_EQUAL(m.length, 0); BOOST_CHECK_EQUAL(m.data_length, 0); BOOST_CHECK(m.data == NULL); @@ -341,9 +341,9 @@ BOOST_AUTO_TEST_CASE(LongPulses) const int Length = Cycles * Period; int j; - vector edges; + vector edges; - //----- Create a LogicSnapshot -----// + //----- Create a LogicSegment -----// sr_datafeed_logic logic; logic.unitsize = 8; logic.length = Length * 8; @@ -357,14 +357,14 @@ BOOST_AUTO_TEST_CASE(LongPulses) *p++ = 0; } - LogicSnapshot s(logic); + LogicSegment s(logic); delete[] (uint64_t*)logic.data; //----- Check the mip-map -----// // Check mip map level 0 BOOST_CHECK_EQUAL(s.mip_map_[0].length, 12); BOOST_CHECK_EQUAL(s.mip_map_[0].data_length, - LogicSnapshot::MipMapDataUnit); + LogicSegment::MipMapDataUnit); BOOST_REQUIRE(s.mip_map_[0].data != NULL); for (unsigned int i = 0; i < s.mip_map_[0].length;) { @@ -375,7 +375,7 @@ BOOST_AUTO_TEST_CASE(LongPulses) } for (; i < s.mip_map_[0].length && - j < Period/LogicSnapshot::MipMapScaleFactor; j++) { + j < Period/LogicSegment::MipMapScaleFactor; j++) { BOOST_TEST_MESSAGE( "Testing mip_map[0].data[" << i << "]"); BOOST_CHECK_EQUAL(s.get_subsample(0, i++), 0); @@ -383,8 +383,8 @@ BOOST_AUTO_TEST_CASE(LongPulses) } // Check the higher levels are all inactive - for (unsigned int i = 1; i < LogicSnapshot::ScaleStepCount; i++) { - const LogicSnapshot::MipMapLevel &m = s.mip_map_[i]; + for (unsigned int i = 1; i < LogicSegment::ScaleStepCount; i++) { + const LogicSegment::MipMapLevel &m = s.mip_map_[i]; BOOST_CHECK_EQUAL(m.length, 0); BOOST_CHECK_EQUAL(m.data_length, 0); BOOST_CHECK(m.data == NULL); @@ -438,7 +438,7 @@ BOOST_AUTO_TEST_CASE(LisaMUsbHid) bool state = false; int lastEdgePos = 0; - //----- Create a LogicSnapshot -----// + //----- Create a LogicSegment -----// sr_datafeed_logic logic; logic.unitsize = 1; logic.length = Length; @@ -454,10 +454,10 @@ BOOST_AUTO_TEST_CASE(LisaMUsbHid) state = !state; } - LogicSnapshot s(logic); + LogicSegment s(logic); delete[] (uint64_t*)logic.data; - vector edges; + vector edges; /* The trailing edge of the pulse train is falling in the source data. @@ -491,9 +491,9 @@ BOOST_AUTO_TEST_CASE(WideData) for (int i = 0; i < Length; i++) data[i] = 0x0FF0; - LogicSnapshot s(logic); + LogicSegment s(logic); - vector edges; + vector edges; edges.clear(); s.get_subsampled_edges(edges, 0, Length-1, 1, 0); @@ -523,9 +523,9 @@ BOOST_AUTO_TEST_CASE(Sixteen) for (int i = 0; i < Length; i++) data[i] = 0xFFFE; - LogicSnapshot s(logic); + LogicSegment s(logic); - vector edges; + vector edges; s.get_subsampled_edges(edges, 0, 2, 0.0004, 1); BOOST_CHECK_EQUAL(edges.size(), 2);