mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-10-31 12:17:11 +01:00 
			
		
		
		
	Add codecov.io coverage tracking
* Every Linux build tracks coverage when running Debug mode * OS X not supported yet (Future WIP) * Our own unit tests, non-default reporters and Clara are ignored
This commit is contained in:
		
							
								
								
									
										157
									
								
								CMake/FindGcov.cmake
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								CMake/FindGcov.cmake
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,157 @@ | ||||
| # This file is part of CMake-codecov. | ||||
| # | ||||
| # Copyright (c) | ||||
| #   2015-2017 RWTH Aachen University, Federal Republic of Germany | ||||
| # | ||||
| # See the LICENSE file in the package base directory for details | ||||
| # | ||||
| # Written by Alexander Haase, alexander.haase@rwth-aachen.de | ||||
| # | ||||
|  | ||||
|  | ||||
| # include required Modules | ||||
| include(FindPackageHandleStandardArgs) | ||||
|  | ||||
|  | ||||
| # Search for gcov binary. | ||||
| set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET}) | ||||
| set(CMAKE_REQUIRED_QUIET ${codecov_FIND_QUIETLY}) | ||||
|  | ||||
| get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) | ||||
| foreach (LANG ${ENABLED_LANGUAGES}) | ||||
| 	# Gcov evaluation is dependend on the used compiler. Check gcov support for | ||||
| 	# each compiler that is used. If gcov binary was already found for this | ||||
| 	# compiler, do not try to find it again. | ||||
| 	if (NOT GCOV_${CMAKE_${LANG}_COMPILER_ID}_BIN) | ||||
| 		get_filename_component(COMPILER_PATH "${CMAKE_${LANG}_COMPILER}" PATH) | ||||
|  | ||||
| 		if ("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "GNU") | ||||
| 			# Some distributions like OSX (homebrew) ship gcov with the compiler | ||||
| 			# version appended as gcov-x. To find this binary we'll build the | ||||
| 			# suggested binary name with the compiler version. | ||||
| 			string(REGEX MATCH "^[0-9]+" GCC_VERSION | ||||
| 				"${CMAKE_${LANG}_COMPILER_VERSION}") | ||||
|  | ||||
| 			find_program(GCOV_BIN NAMES gcov-${GCC_VERSION} gcov | ||||
| 				HINTS ${COMPILER_PATH}) | ||||
|  | ||||
| 		elseif ("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "Clang") | ||||
| 			# Some distributions like Debian ship llvm-cov with the compiler | ||||
| 			# version appended as llvm-cov-x.y. To find this binary we'll build | ||||
| 			# the suggested binary name with the compiler version. | ||||
| 			string(REGEX MATCH "^[0-9]+.[0-9]+" LLVM_VERSION | ||||
| 				"${CMAKE_${LANG}_COMPILER_VERSION}") | ||||
|  | ||||
| 			# llvm-cov prior version 3.5 seems to be not working with coverage | ||||
| 			# evaluation tools, but these versions are compatible with the gcc | ||||
| 			# gcov tool. | ||||
| 			if(LLVM_VERSION VERSION_GREATER 3.4) | ||||
| 				find_program(LLVM_COV_BIN NAMES "llvm-cov-${LLVM_VERSION}" | ||||
| 					"llvm-cov" HINTS ${COMPILER_PATH}) | ||||
| 				mark_as_advanced(LLVM_COV_BIN) | ||||
|  | ||||
| 				if (LLVM_COV_BIN) | ||||
| 					find_program(LLVM_COV_WRAPPER "llvm-cov-wrapper" PATHS | ||||
| 						${CMAKE_MODULE_PATH}) | ||||
| 					if (LLVM_COV_WRAPPER) | ||||
| 						set(GCOV_BIN "${LLVM_COV_WRAPPER}" CACHE FILEPATH "") | ||||
|  | ||||
| 						# set additional parameters | ||||
| 						set(GCOV_${CMAKE_${LANG}_COMPILER_ID}_ENV | ||||
| 							"LLVM_COV_BIN=${LLVM_COV_BIN}" CACHE STRING | ||||
| 							"Environment variables for llvm-cov-wrapper.") | ||||
| 						mark_as_advanced(GCOV_${CMAKE_${LANG}_COMPILER_ID}_ENV) | ||||
| 					endif () | ||||
| 				endif () | ||||
| 			endif () | ||||
|  | ||||
| 			if (NOT GCOV_BIN) | ||||
| 				# Fall back to gcov binary if llvm-cov was not found or is | ||||
| 				# incompatible. This is the default on OSX, but may crash on | ||||
| 				# recent Linux versions. | ||||
| 				find_program(GCOV_BIN gcov HINTS ${COMPILER_PATH}) | ||||
| 			endif () | ||||
| 		endif () | ||||
|  | ||||
|  | ||||
| 		if (GCOV_BIN) | ||||
| 			set(GCOV_${CMAKE_${LANG}_COMPILER_ID}_BIN "${GCOV_BIN}" CACHE STRING | ||||
| 				"${LANG} gcov binary.") | ||||
|  | ||||
| 			if (NOT CMAKE_REQUIRED_QUIET) | ||||
| 				message("-- Found gcov evaluation for " | ||||
| 				"${CMAKE_${LANG}_COMPILER_ID}: ${GCOV_BIN}") | ||||
| 			endif() | ||||
|  | ||||
| 			unset(GCOV_BIN CACHE) | ||||
| 		endif () | ||||
| 	endif () | ||||
| endforeach () | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| # Add a new global target for all gcov targets. This target could be used to | ||||
| # generate the gcov files for the whole project instead of calling <TARGET>-gcov | ||||
| # for each target. | ||||
| if (NOT TARGET gcov) | ||||
| 	add_custom_target(gcov) | ||||
| endif (NOT TARGET gcov) | ||||
|  | ||||
|  | ||||
|  | ||||
| # This function will add gcov evaluation for target <TNAME>. Only sources of | ||||
| # this target will be evaluated and no dependencies will be added. It will call | ||||
| # Gcov on any source file of <TNAME> once and store the gcov file in the same | ||||
| # directory. | ||||
| function (add_gcov_target TNAME) | ||||
| 	set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir) | ||||
|  | ||||
| 	# We don't have to check, if the target has support for coverage, thus this | ||||
| 	# will be checked by add_coverage_target in Findcoverage.cmake. Instead we | ||||
| 	# have to determine which gcov binary to use. | ||||
| 	get_target_property(TSOURCES ${TNAME} SOURCES) | ||||
| 	set(SOURCES "") | ||||
| 	set(TCOMPILER "") | ||||
| 	foreach (FILE ${TSOURCES}) | ||||
| 		codecov_path_of_source(${FILE} FILE) | ||||
| 		if (NOT "${FILE}" STREQUAL "") | ||||
| 			codecov_lang_of_source(${FILE} LANG) | ||||
| 			if (NOT "${LANG}" STREQUAL "") | ||||
| 				list(APPEND SOURCES "${FILE}") | ||||
| 				set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID}) | ||||
| 			endif () | ||||
| 		endif () | ||||
| 	endforeach () | ||||
|  | ||||
| 	# If no gcov binary was found, coverage data can't be evaluated. | ||||
| 	if (NOT GCOV_${TCOMPILER}_BIN) | ||||
| 		message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.") | ||||
| 		return() | ||||
| 	endif () | ||||
|  | ||||
| 	set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}") | ||||
| 	set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}") | ||||
|  | ||||
|  | ||||
| 	set(BUFFER "") | ||||
| 	foreach(FILE ${SOURCES}) | ||||
| 		get_filename_component(FILE_PATH "${TDIR}/${FILE}" PATH) | ||||
|  | ||||
| 		# call gcov | ||||
| 		add_custom_command(OUTPUT ${TDIR}/${FILE}.gcov | ||||
| 			COMMAND ${GCOV_ENV} ${GCOV_BIN} ${TDIR}/${FILE}.gcno > /dev/null | ||||
| 			DEPENDS ${TNAME} ${TDIR}/${FILE}.gcno | ||||
| 			WORKING_DIRECTORY ${FILE_PATH} | ||||
| 		) | ||||
|  | ||||
| 		list(APPEND BUFFER ${TDIR}/${FILE}.gcov) | ||||
| 	endforeach() | ||||
|  | ||||
|  | ||||
| 	# add target for gcov evaluation of <TNAME> | ||||
| 	add_custom_target(${TNAME}-gcov DEPENDS ${BUFFER}) | ||||
|  | ||||
| 	# add evaluation target to the global gcov target. | ||||
| 	add_dependencies(gcov ${TNAME}-gcov) | ||||
| endfunction (add_gcov_target) | ||||
							
								
								
									
										354
									
								
								CMake/FindLcov.cmake
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										354
									
								
								CMake/FindLcov.cmake
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,354 @@ | ||||
| # This file is part of CMake-codecov. | ||||
| # | ||||
| # Copyright (c) | ||||
| #   2015-2017 RWTH Aachen University, Federal Republic of Germany | ||||
| # | ||||
| # See the LICENSE file in the package base directory for details | ||||
| # | ||||
| # Written by Alexander Haase, alexander.haase@rwth-aachen.de | ||||
| # | ||||
|  | ||||
|  | ||||
| # configuration | ||||
| set(LCOV_DATA_PATH "${CMAKE_BINARY_DIR}/lcov/data") | ||||
| set(LCOV_DATA_PATH_INIT "${LCOV_DATA_PATH}/init") | ||||
| set(LCOV_DATA_PATH_CAPTURE "${LCOV_DATA_PATH}/capture") | ||||
| set(LCOV_HTML_PATH "${CMAKE_BINARY_DIR}/lcov/html") | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| # Search for Gcov which is used by Lcov. | ||||
| find_package(Gcov) | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| # This function will add lcov evaluation for target <TNAME>. Only sources of | ||||
| # this target will be evaluated and no dependencies will be added. It will call | ||||
| # geninfo on any source file of <TNAME> once and store the info file in the same | ||||
| # directory. | ||||
| # | ||||
| # Note: This function is only a wrapper to define this function always, even if | ||||
| #   coverage is not supported by the compiler or disabled. This function must | ||||
| #   be defined here, because the module will be exited, if there is no coverage | ||||
| #   support by the compiler or it is disabled by the user. | ||||
| function (add_lcov_target TNAME) | ||||
| 	if (LCOV_FOUND) | ||||
| 		# capture initial coverage data | ||||
| 		lcov_capture_initial_tgt(${TNAME}) | ||||
|  | ||||
| 		# capture coverage data after execution | ||||
| 		lcov_capture_tgt(${TNAME}) | ||||
| 	endif () | ||||
| endfunction (add_lcov_target) | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| # include required Modules | ||||
| include(FindPackageHandleStandardArgs) | ||||
|  | ||||
| # Search for required lcov binaries. | ||||
| find_program(LCOV_BIN lcov) | ||||
| find_program(GENINFO_BIN geninfo) | ||||
| find_program(GENHTML_BIN genhtml) | ||||
| find_package_handle_standard_args(lcov | ||||
| 	REQUIRED_VARS LCOV_BIN GENINFO_BIN GENHTML_BIN | ||||
| ) | ||||
|  | ||||
| # enable genhtml C++ demangeling, if c++filt is found. | ||||
| set(GENHTML_CPPFILT_FLAG "") | ||||
| find_program(CPPFILT_BIN c++filt) | ||||
| if (NOT CPPFILT_BIN STREQUAL "") | ||||
| 	set(GENHTML_CPPFILT_FLAG "--demangle-cpp") | ||||
| endif (NOT CPPFILT_BIN STREQUAL "") | ||||
|  | ||||
| # enable no-external flag for lcov, if available. | ||||
| if (GENINFO_BIN AND NOT DEFINED GENINFO_EXTERN_FLAG) | ||||
| 	set(FLAG "") | ||||
| 	execute_process(COMMAND ${GENINFO_BIN} --help OUTPUT_VARIABLE GENINFO_HELP) | ||||
| 	string(REGEX MATCH "external" GENINFO_RES "${GENINFO_HELP}") | ||||
| 	if (GENINFO_RES) | ||||
| 		set(FLAG "--no-external") | ||||
| 	endif () | ||||
|  | ||||
| 	set(GENINFO_EXTERN_FLAG "${FLAG}" | ||||
| 		CACHE STRING "Geninfo flag to exclude system sources.") | ||||
| endif () | ||||
|  | ||||
| # If Lcov was not found, exit module now. | ||||
| if (NOT LCOV_FOUND) | ||||
| 	return() | ||||
| endif (NOT LCOV_FOUND) | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| # Create directories to be used. | ||||
| file(MAKE_DIRECTORY ${LCOV_DATA_PATH_INIT}) | ||||
| file(MAKE_DIRECTORY ${LCOV_DATA_PATH_CAPTURE}) | ||||
|  | ||||
| set(LCOV_REMOVE_PATTERNS "") | ||||
|  | ||||
| # This function will merge lcov files to a single target file. Additional lcov | ||||
| # flags may be set with setting LCOV_EXTRA_FLAGS before calling this function. | ||||
| function (lcov_merge_files OUTFILE ...) | ||||
| 	# Remove ${OUTFILE} from ${ARGV} and generate lcov parameters with files. | ||||
| 	list(REMOVE_AT ARGV 0) | ||||
|  | ||||
| 	# Generate merged file. | ||||
| 	string(REPLACE "${CMAKE_BINARY_DIR}/" "" FILE_REL "${OUTFILE}") | ||||
| 	add_custom_command(OUTPUT "${OUTFILE}.raw" | ||||
| 		COMMAND cat ${ARGV} > ${OUTFILE}.raw | ||||
| 		DEPENDS ${ARGV} | ||||
| 		COMMENT "Generating ${FILE_REL}" | ||||
| 	) | ||||
|  | ||||
| 	add_custom_command(OUTPUT "${OUTFILE}" | ||||
| 		COMMAND ${LCOV_BIN} --quiet -a ${OUTFILE}.raw --output-file ${OUTFILE} | ||||
| 			--base-directory ${PROJECT_SOURCE_DIR} ${LCOV_EXTRA_FLAGS} | ||||
| 		COMMAND ${LCOV_BIN} --quiet -r ${OUTFILE} ${LCOV_REMOVE_PATTERNS} | ||||
| 			--output-file ${OUTFILE} ${LCOV_EXTRA_FLAGS} | ||||
| 		DEPENDS ${OUTFILE}.raw | ||||
| 		COMMENT "Post-processing ${FILE_REL}" | ||||
| 	) | ||||
| endfunction () | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| # Add a new global target to generate initial coverage reports for all targets. | ||||
| # This target will be used to generate the global initial info file, which is | ||||
| # used to gather even empty report data. | ||||
| if (NOT TARGET lcov-capture-init) | ||||
| 	add_custom_target(lcov-capture-init) | ||||
| 	set(LCOV_CAPTURE_INIT_FILES "" CACHE INTERNAL "") | ||||
| endif (NOT TARGET lcov-capture-init) | ||||
|  | ||||
|  | ||||
| # This function will add initial capture of coverage data for target <TNAME>, | ||||
| # which is needed to get also data for objects, which were not loaded at | ||||
| # execution time. It will call geninfo for every source file of <TNAME> once and | ||||
| # store the info file in the same directory. | ||||
| function (lcov_capture_initial_tgt TNAME) | ||||
| 	# We don't have to check, if the target has support for coverage, thus this | ||||
| 	# will be checked by add_coverage_target in Findcoverage.cmake. Instead we | ||||
| 	# have to determine which gcov binary to use. | ||||
| 	get_target_property(TSOURCES ${TNAME} SOURCES) | ||||
| 	set(SOURCES "") | ||||
| 	set(TCOMPILER "") | ||||
| 	foreach (FILE ${TSOURCES}) | ||||
| 		codecov_path_of_source(${FILE} FILE) | ||||
| 		if (NOT "${FILE}" STREQUAL "") | ||||
| 			codecov_lang_of_source(${FILE} LANG) | ||||
| 			if (NOT "${LANG}" STREQUAL "") | ||||
| 				list(APPEND SOURCES "${FILE}") | ||||
| 				set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID}) | ||||
| 			endif () | ||||
| 		endif () | ||||
| 	endforeach () | ||||
|  | ||||
| 	# If no gcov binary was found, coverage data can't be evaluated. | ||||
| 	if (NOT GCOV_${TCOMPILER}_BIN) | ||||
| 		message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.") | ||||
| 		return() | ||||
| 	endif () | ||||
|  | ||||
| 	set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}") | ||||
| 	set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}") | ||||
|  | ||||
|  | ||||
| 	set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir) | ||||
| 	set(GENINFO_FILES "") | ||||
| 	foreach(FILE ${SOURCES}) | ||||
| 		# generate empty coverage files | ||||
| 		set(OUTFILE "${TDIR}/${FILE}.info.init") | ||||
| 		list(APPEND GENINFO_FILES ${OUTFILE}) | ||||
|  | ||||
| 		add_custom_command(OUTPUT ${OUTFILE} COMMAND ${GCOV_ENV} ${GENINFO_BIN} | ||||
| 				--quiet --base-directory ${PROJECT_SOURCE_DIR} --initial | ||||
| 				--gcov-tool ${GCOV_BIN} --output-filename ${OUTFILE} | ||||
| 				${GENINFO_EXTERN_FLAG} ${TDIR}/${FILE}.gcno | ||||
| 			DEPENDS ${TNAME} | ||||
| 			COMMENT "Capturing initial coverage data for ${FILE}" | ||||
| 		) | ||||
| 	endforeach() | ||||
|  | ||||
| 	# Concatenate all files generated by geninfo to a single file per target. | ||||
| 	set(OUTFILE "${LCOV_DATA_PATH_INIT}/${TNAME}.info") | ||||
| 	set(LCOV_EXTRA_FLAGS "--initial") | ||||
| 	lcov_merge_files("${OUTFILE}" ${GENINFO_FILES}) | ||||
| 	add_custom_target(${TNAME}-capture-init ALL DEPENDS ${OUTFILE}) | ||||
|  | ||||
| 	# add geninfo file generation to global lcov-geninfo target | ||||
| 	add_dependencies(lcov-capture-init ${TNAME}-capture-init) | ||||
| 	set(LCOV_CAPTURE_INIT_FILES "${LCOV_CAPTURE_INIT_FILES}" | ||||
| 		"${OUTFILE}" CACHE INTERNAL "" | ||||
| 	) | ||||
| endfunction (lcov_capture_initial_tgt) | ||||
|  | ||||
|  | ||||
| # This function will generate the global info file for all targets. It has to be | ||||
| # called after all other CMake functions in the root CMakeLists.txt file, to get | ||||
| # a full list of all targets that generate coverage data. | ||||
| function (lcov_capture_initial) | ||||
| 	# Skip this function (and do not create the following targets), if there are | ||||
| 	# no input files. | ||||
| 	if ("${LCOV_CAPTURE_INIT_FILES}" STREQUAL "") | ||||
| 		return() | ||||
| 	endif () | ||||
|  | ||||
| 	# Add a new target to merge the files of all targets. | ||||
| 	set(OUTFILE "${LCOV_DATA_PATH_INIT}/all_targets.info") | ||||
| 	lcov_merge_files("${OUTFILE}" ${LCOV_CAPTURE_INIT_FILES}) | ||||
| 	add_custom_target(lcov-geninfo-init ALL	DEPENDS ${OUTFILE} | ||||
| 		lcov-capture-init | ||||
| 	) | ||||
| endfunction (lcov_capture_initial) | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| # Add a new global target to generate coverage reports for all targets. This | ||||
| # target will be used to generate the global info file. | ||||
| if (NOT TARGET lcov-capture) | ||||
| 	add_custom_target(lcov-capture) | ||||
| 	set(LCOV_CAPTURE_FILES "" CACHE INTERNAL "") | ||||
| endif (NOT TARGET lcov-capture) | ||||
|  | ||||
|  | ||||
| # This function will add capture of coverage data for target <TNAME>, which is | ||||
| # needed to get also data for objects, which were not loaded at execution time. | ||||
| # It will call geninfo for every source file of <TNAME> once and store the info | ||||
| # file in the same directory. | ||||
| function (lcov_capture_tgt TNAME) | ||||
| 	# We don't have to check, if the target has support for coverage, thus this | ||||
| 	# will be checked by add_coverage_target in Findcoverage.cmake. Instead we | ||||
| 	# have to determine which gcov binary to use. | ||||
| 	get_target_property(TSOURCES ${TNAME} SOURCES) | ||||
| 	set(SOURCES "") | ||||
| 	set(TCOMPILER "") | ||||
| 	foreach (FILE ${TSOURCES}) | ||||
| 		codecov_path_of_source(${FILE} FILE) | ||||
| 		if (NOT "${FILE}" STREQUAL "") | ||||
| 			codecov_lang_of_source(${FILE} LANG) | ||||
| 			if (NOT "${LANG}" STREQUAL "") | ||||
| 				list(APPEND SOURCES "${FILE}") | ||||
| 				set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID}) | ||||
| 			endif () | ||||
| 		endif () | ||||
| 	endforeach () | ||||
|  | ||||
| 	# If no gcov binary was found, coverage data can't be evaluated. | ||||
| 	if (NOT GCOV_${TCOMPILER}_BIN) | ||||
| 		message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.") | ||||
| 		return() | ||||
| 	endif () | ||||
|  | ||||
| 	set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}") | ||||
| 	set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}") | ||||
|  | ||||
|  | ||||
| 	set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir) | ||||
| 	set(GENINFO_FILES "") | ||||
| 	foreach(FILE ${SOURCES}) | ||||
| 		# Generate coverage files. If no .gcda file was generated during | ||||
| 		# execution, the empty coverage file will be used instead. | ||||
| 		set(OUTFILE "${TDIR}/${FILE}.info") | ||||
| 		list(APPEND GENINFO_FILES ${OUTFILE}) | ||||
|  | ||||
| 		add_custom_command(OUTPUT ${OUTFILE} | ||||
| 			COMMAND test -f "${TDIR}/${FILE}.gcda" | ||||
| 				&& ${GCOV_ENV} ${GENINFO_BIN} --quiet --base-directory | ||||
| 					${PROJECT_SOURCE_DIR} --gcov-tool ${GCOV_BIN} | ||||
| 					--output-filename ${OUTFILE} ${GENINFO_EXTERN_FLAG} | ||||
| 					${TDIR}/${FILE}.gcda | ||||
| 				|| cp ${OUTFILE}.init ${OUTFILE} | ||||
| 			DEPENDS ${TNAME} ${TNAME}-capture-init | ||||
| 			COMMENT "Capturing coverage data for ${FILE}" | ||||
| 		) | ||||
| 	endforeach() | ||||
|  | ||||
| 	# Concatenate all files generated by geninfo to a single file per target. | ||||
| 	set(OUTFILE "${LCOV_DATA_PATH_CAPTURE}/${TNAME}.info") | ||||
| 	lcov_merge_files("${OUTFILE}" ${GENINFO_FILES}) | ||||
| 	add_custom_target(${TNAME}-geninfo DEPENDS ${OUTFILE}) | ||||
|  | ||||
| 	# add geninfo file generation to global lcov-capture target | ||||
| 	add_dependencies(lcov-capture ${TNAME}-geninfo) | ||||
| 	set(LCOV_CAPTURE_FILES "${LCOV_CAPTURE_FILES}" "${OUTFILE}" CACHE INTERNAL | ||||
| 		"" | ||||
| 	) | ||||
|  | ||||
| 	# Add target for generating html output for this target only. | ||||
| 	file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/${TNAME}) | ||||
| 	add_custom_target(${TNAME}-genhtml | ||||
| 		COMMAND ${GENHTML_BIN} --quiet --sort --prefix ${PROJECT_SOURCE_DIR} | ||||
| 			--baseline-file ${LCOV_DATA_PATH_INIT}/${TNAME}.info | ||||
| 			--output-directory ${LCOV_HTML_PATH}/${TNAME} | ||||
| 			--title "${CMAKE_PROJECT_NAME} - target ${TNAME}" | ||||
| 			${GENHTML_CPPFILT_FLAG} ${OUTFILE} | ||||
| 		DEPENDS ${TNAME}-geninfo ${TNAME}-capture-init | ||||
| 	) | ||||
| endfunction (lcov_capture_tgt) | ||||
|  | ||||
|  | ||||
| # This function will generate the global info file for all targets. It has to be | ||||
| # called after all other CMake functions in the root CMakeLists.txt file, to get | ||||
| # a full list of all targets that generate coverage data. | ||||
| function (lcov_capture) | ||||
| 	# Skip this function (and do not create the following targets), if there are | ||||
| 	# no input files. | ||||
| 	if ("${LCOV_CAPTURE_FILES}" STREQUAL "") | ||||
| 		return() | ||||
| 	endif () | ||||
|  | ||||
| 	# Add a new target to merge the files of all targets. | ||||
| 	set(OUTFILE "${LCOV_DATA_PATH_CAPTURE}/all_targets.info") | ||||
| 	lcov_merge_files("${OUTFILE}" ${LCOV_CAPTURE_FILES}) | ||||
| 	add_custom_target(lcov-geninfo DEPENDS ${OUTFILE} lcov-capture) | ||||
|  | ||||
| 	# Add a new global target for all lcov targets. This target could be used to | ||||
| 	# generate the lcov html output for the whole project instead of calling | ||||
| 	# <TARGET>-geninfo and <TARGET>-genhtml for each target. It will also be | ||||
| 	# used to generate a html site for all project data together instead of one | ||||
| 	# for each target. | ||||
| 	if (NOT TARGET lcov) | ||||
| 		file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/all_targets) | ||||
| 		add_custom_target(lcov | ||||
| 			COMMAND ${GENHTML_BIN} --quiet --sort | ||||
| 				--baseline-file ${LCOV_DATA_PATH_INIT}/all_targets.info | ||||
| 				--output-directory ${LCOV_HTML_PATH}/all_targets | ||||
| 				--title "${CMAKE_PROJECT_NAME}" --prefix "${PROJECT_SOURCE_DIR}" | ||||
| 				${GENHTML_CPPFILT_FLAG} ${OUTFILE} | ||||
| 			DEPENDS lcov-geninfo-init lcov-geninfo | ||||
| 		) | ||||
| 	endif () | ||||
| endfunction (lcov_capture) | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| # Add a new global target to generate the lcov html report for the whole project | ||||
| # instead of calling <TARGET>-genhtml for each target (to create an own report | ||||
| # for each target). Instead of the lcov target it does not require geninfo for | ||||
| # all targets, so you have to call <TARGET>-geninfo to generate the info files | ||||
| # the targets you'd like to have in your report or lcov-geninfo for generating | ||||
| # info files for all targets before calling lcov-genhtml. | ||||
| file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/selected_targets) | ||||
| if (NOT TARGET lcov-genhtml) | ||||
| 	add_custom_target(lcov-genhtml | ||||
| 		COMMAND ${GENHTML_BIN} | ||||
| 			--quiet | ||||
| 			--output-directory ${LCOV_HTML_PATH}/selected_targets | ||||
| 			--title \"${CMAKE_PROJECT_NAME} - targets  `find | ||||
| 				${LCOV_DATA_PATH_CAPTURE} -name \"*.info\" ! -name | ||||
| 				\"all_targets.info\" -exec basename {} .info \\\;`\" | ||||
| 			--prefix ${PROJECT_SOURCE_DIR} | ||||
| 			--sort | ||||
| 			${GENHTML_CPPFILT_FLAG} | ||||
| 			`find ${LCOV_DATA_PATH_CAPTURE} -name \"*.info\" ! -name | ||||
| 				\"all_targets.info\"` | ||||
| 	) | ||||
| endif (NOT TARGET lcov-genhtml) | ||||
							
								
								
									
										258
									
								
								CMake/Findcodecov.cmake
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										258
									
								
								CMake/Findcodecov.cmake
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,258 @@ | ||||
| # This file is part of CMake-codecov. | ||||
| # | ||||
| # Copyright (c) | ||||
| #   2015-2017 RWTH Aachen University, Federal Republic of Germany | ||||
| # | ||||
| # See the LICENSE file in the package base directory for details | ||||
| # | ||||
| # Written by Alexander Haase, alexander.haase@rwth-aachen.de | ||||
| # | ||||
|  | ||||
|  | ||||
| # Add an option to choose, if coverage should be enabled or not. If enabled | ||||
| # marked targets will be build with coverage support and appropriate targets | ||||
| # will be added. If disabled coverage will be ignored for *ALL* targets. | ||||
| option(ENABLE_COVERAGE "Enable coverage build." OFF) | ||||
|  | ||||
| set(COVERAGE_FLAG_CANDIDATES | ||||
| 	# gcc and clang | ||||
| 	"-O0 -g -fprofile-arcs -ftest-coverage" | ||||
|  | ||||
| 	# gcc and clang fallback | ||||
| 	"-O0 -g --coverage" | ||||
| ) | ||||
|  | ||||
|  | ||||
| # Add coverage support for target ${TNAME} and register target for coverage | ||||
| # evaluation. If coverage is disabled or not supported, this function will | ||||
| # simply do nothing. | ||||
| # | ||||
| # Note: This function is only a wrapper to define this function always, even if | ||||
| #   coverage is not supported by the compiler or disabled. This function must | ||||
| #   be defined here, because the module will be exited, if there is no coverage | ||||
| #   support by the compiler or it is disabled by the user. | ||||
| function (add_coverage TNAME) | ||||
| 	# only add coverage for target, if coverage is support and enabled. | ||||
| 	if (ENABLE_COVERAGE) | ||||
| 		foreach (TNAME ${ARGV}) | ||||
| 			add_coverage_target(${TNAME}) | ||||
| 		endforeach () | ||||
| 	endif () | ||||
| endfunction (add_coverage) | ||||
|  | ||||
|  | ||||
| # Add global target to gather coverage information after all targets have been | ||||
| # added. Other evaluation functions could be added here, after checks for the | ||||
| # specific module have been passed. | ||||
| # | ||||
| # Note: This function is only a wrapper to define this function always, even if | ||||
| #   coverage is not supported by the compiler or disabled. This function must | ||||
| #   be defined here, because the module will be exited, if there is no coverage | ||||
| #   support by the compiler or it is disabled by the user. | ||||
| function (coverage_evaluate) | ||||
| 	# add lcov evaluation | ||||
| 	if (LCOV_FOUND) | ||||
| 		lcov_capture_initial() | ||||
| 		lcov_capture() | ||||
| 	endif (LCOV_FOUND) | ||||
| endfunction () | ||||
|  | ||||
|  | ||||
| # Exit this module, if coverage is disabled. add_coverage is defined before this | ||||
| # return, so this module can be exited now safely without breaking any build- | ||||
| # scripts. | ||||
| if (NOT ENABLE_COVERAGE) | ||||
| 	return() | ||||
| endif () | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| # Find the reuired flags foreach language. | ||||
| set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET}) | ||||
| set(CMAKE_REQUIRED_QUIET ${codecov_FIND_QUIETLY}) | ||||
|  | ||||
| get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) | ||||
| foreach (LANG ${ENABLED_LANGUAGES}) | ||||
| 	# Coverage flags are not dependend on language, but the used compiler. So | ||||
| 	# instead of searching flags foreach language, search flags foreach compiler | ||||
| 	# used. | ||||
| 	set(COMPILER ${CMAKE_${LANG}_COMPILER_ID}) | ||||
| 	if (NOT COVERAGE_${COMPILER}_FLAGS) | ||||
| 		foreach (FLAG ${COVERAGE_FLAG_CANDIDATES}) | ||||
| 			if(NOT CMAKE_REQUIRED_QUIET) | ||||
| 				message(STATUS "Try ${COMPILER} code coverage flag = [${FLAG}]") | ||||
| 			endif() | ||||
|  | ||||
| 			set(CMAKE_REQUIRED_FLAGS "${FLAG}") | ||||
| 			unset(COVERAGE_FLAG_DETECTED CACHE) | ||||
|  | ||||
| 			if (${LANG} STREQUAL "C") | ||||
| 				include(CheckCCompilerFlag) | ||||
| 				check_c_compiler_flag("${FLAG}" COVERAGE_FLAG_DETECTED) | ||||
|  | ||||
| 			elseif (${LANG} STREQUAL "CXX") | ||||
| 				include(CheckCXXCompilerFlag) | ||||
| 				check_cxx_compiler_flag("${FLAG}" COVERAGE_FLAG_DETECTED) | ||||
|  | ||||
| 			elseif (${LANG} STREQUAL "Fortran") | ||||
| 				# CheckFortranCompilerFlag was introduced in CMake 3.x. To be | ||||
| 				# compatible with older Cmake versions, we will check if this | ||||
| 				# module is present before we use it. Otherwise we will define | ||||
| 				# Fortran coverage support as not available. | ||||
| 				include(CheckFortranCompilerFlag OPTIONAL | ||||
| 					RESULT_VARIABLE INCLUDED) | ||||
| 				if (INCLUDED) | ||||
| 					check_fortran_compiler_flag("${FLAG}" | ||||
| 						COVERAGE_FLAG_DETECTED) | ||||
| 				elseif (NOT CMAKE_REQUIRED_QUIET) | ||||
| 					message("-- Performing Test COVERAGE_FLAG_DETECTED") | ||||
| 					message("-- Performing Test COVERAGE_FLAG_DETECTED - Failed" | ||||
| 						" (Check not supported)") | ||||
| 				endif () | ||||
| 			endif() | ||||
|  | ||||
| 			if (COVERAGE_FLAG_DETECTED) | ||||
| 				set(COVERAGE_${COMPILER}_FLAGS "${FLAG}" | ||||
| 					CACHE STRING "${COMPILER} flags for code coverage.") | ||||
| 				mark_as_advanced(COVERAGE_${COMPILER}_FLAGS) | ||||
| 				break() | ||||
| 			else () | ||||
| 				message(WARNING "Code coverage is not available for ${COMPILER}" | ||||
| 				        " compiler. Targets using this compiler will be " | ||||
| 				        "compiled without it.") | ||||
| 			endif () | ||||
| 		endforeach () | ||||
| 	endif () | ||||
| endforeach () | ||||
|  | ||||
| set(CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_SAVE}) | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| # Helper function to get the language of a source file. | ||||
| function (codecov_lang_of_source FILE RETURN_VAR) | ||||
| 	get_filename_component(FILE_EXT "${FILE}" EXT) | ||||
| 	string(TOLOWER "${FILE_EXT}" FILE_EXT) | ||||
| 	string(SUBSTRING "${FILE_EXT}" 1 -1 FILE_EXT) | ||||
|  | ||||
| 	get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) | ||||
| 	foreach (LANG ${ENABLED_LANGUAGES}) | ||||
| 		list(FIND CMAKE_${LANG}_SOURCE_FILE_EXTENSIONS "${FILE_EXT}" TEMP) | ||||
| 		if (NOT ${TEMP} EQUAL -1) | ||||
| 			set(${RETURN_VAR} "${LANG}" PARENT_SCOPE) | ||||
| 			return() | ||||
| 		endif () | ||||
| 	endforeach() | ||||
|  | ||||
| 	set(${RETURN_VAR} "" PARENT_SCOPE) | ||||
| endfunction () | ||||
|  | ||||
|  | ||||
| # Helper function to get the relative path of the source file destination path. | ||||
| # This path is needed by FindGcov and FindLcov cmake files to locate the | ||||
| # captured data. | ||||
| function (codecov_path_of_source FILE RETURN_VAR) | ||||
| 	string(REGEX MATCH "TARGET_OBJECTS:([^ >]+)" _source ${FILE}) | ||||
|  | ||||
| 	# If expression was found, SOURCEFILE is a generator-expression for an | ||||
| 	# object library. Currently we found no way to call this function automatic | ||||
| 	# for the referenced target, so it must be called in the directoryso of the | ||||
| 	# object library definition. | ||||
| 	if (NOT "${_source}" STREQUAL "") | ||||
| 		set(${RETURN_VAR} "" PARENT_SCOPE) | ||||
| 		return() | ||||
| 	endif () | ||||
|  | ||||
|  | ||||
| 	string(REPLACE "${CMAKE_CURRENT_BINARY_DIR}/" "" FILE "${FILE}") | ||||
| 	if(IS_ABSOLUTE ${FILE}) | ||||
| 		file(RELATIVE_PATH FILE ${CMAKE_CURRENT_SOURCE_DIR} ${FILE}) | ||||
| 	endif() | ||||
|  | ||||
| 	# get the right path for file | ||||
| 	string(REPLACE ".." "__" PATH "${FILE}") | ||||
|  | ||||
| 	set(${RETURN_VAR} "${PATH}" PARENT_SCOPE) | ||||
| endfunction() | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| # Add coverage support for target ${TNAME} and register target for coverage | ||||
| # evaluation. | ||||
| function(add_coverage_target TNAME) | ||||
| 	# Check if all sources for target use the same compiler. If a target uses | ||||
| 	# e.g. C and Fortran mixed and uses different compilers (e.g. clang and | ||||
| 	# gfortran) this can trigger huge problems, because different compilers may | ||||
| 	# use different implementations for code coverage. | ||||
| 	get_target_property(TSOURCES ${TNAME} SOURCES) | ||||
| 	set(TARGET_COMPILER "") | ||||
| 	set(ADDITIONAL_FILES "") | ||||
| 	foreach (FILE ${TSOURCES}) | ||||
| 		# If expression was found, FILE is a generator-expression for an object | ||||
| 		# library. Object libraries will be ignored. | ||||
| 		string(REGEX MATCH "TARGET_OBJECTS:([^ >]+)" _file ${FILE}) | ||||
| 		if ("${_file}" STREQUAL "") | ||||
| 			codecov_lang_of_source(${FILE} LANG) | ||||
| 			if (LANG) | ||||
| 				list(APPEND TARGET_COMPILER ${CMAKE_${LANG}_COMPILER_ID}) | ||||
|  | ||||
| 				list(APPEND ADDITIONAL_FILES "${FILE}.gcno") | ||||
| 				list(APPEND ADDITIONAL_FILES "${FILE}.gcda") | ||||
| 			endif () | ||||
| 		endif () | ||||
| 	endforeach () | ||||
|  | ||||
| 	list(REMOVE_DUPLICATES TARGET_COMPILER) | ||||
| 	list(LENGTH TARGET_COMPILER NUM_COMPILERS) | ||||
|  | ||||
| 	if (NUM_COMPILERS GREATER 1) | ||||
| 		message(WARNING "Can't use code coverage for target ${TNAME}, because " | ||||
| 		        "it will be compiled by incompatible compilers. Target will be " | ||||
| 		        "compiled without code coverage.") | ||||
| 		return() | ||||
|  | ||||
| 	elseif (NUM_COMPILERS EQUAL 0) | ||||
| 		message(WARNING "Can't use code coverage for target ${TNAME}, because " | ||||
| 		        "it uses an unknown compiler. Target will be compiled without " | ||||
| 		        "code coverage.") | ||||
| 		return() | ||||
|  | ||||
| 	elseif (NOT DEFINED "COVERAGE_${TARGET_COMPILER}_FLAGS") | ||||
| 		# A warning has been printed before, so just return if flags for this | ||||
| 		# compiler aren't available. | ||||
| 		return() | ||||
| 	endif() | ||||
|  | ||||
|  | ||||
| 	# enable coverage for target | ||||
| 	set_property(TARGET ${TNAME} APPEND_STRING | ||||
| 		PROPERTY COMPILE_FLAGS " ${COVERAGE_${TARGET_COMPILER}_FLAGS}") | ||||
| 	set_property(TARGET ${TNAME} APPEND_STRING | ||||
| 		PROPERTY LINK_FLAGS " ${COVERAGE_${TARGET_COMPILER}_FLAGS}") | ||||
|  | ||||
|  | ||||
| 	# Add gcov files generated by compiler to clean target. | ||||
| 	set(CLEAN_FILES "") | ||||
| 	foreach (FILE ${ADDITIONAL_FILES}) | ||||
| 		codecov_path_of_source(${FILE} FILE) | ||||
| 		list(APPEND CLEAN_FILES "CMakeFiles/${TNAME}.dir/${FILE}") | ||||
| 	endforeach() | ||||
|  | ||||
| 	set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES | ||||
| 		"${CLEAN_FILES}") | ||||
|  | ||||
|  | ||||
| 	add_gcov_target(${TNAME}) | ||||
| 	add_lcov_target(${TNAME}) | ||||
| endfunction(add_coverage_target) | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| # Include modules for parsing the collected data and output it in a readable | ||||
| # format (like gcov and lcov). | ||||
| find_package(Gcov) | ||||
| find_package(Lcov) | ||||
							
								
								
									
										56
									
								
								CMake/llvm-cov-wrapper
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										56
									
								
								CMake/llvm-cov-wrapper
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| #!/bin/sh | ||||
|  | ||||
| # This file is part of CMake-codecov. | ||||
| # | ||||
| # Copyright (c) | ||||
| #   2015-2017 RWTH Aachen University, Federal Republic of Germany | ||||
| # | ||||
| # See the LICENSE file in the package base directory for details | ||||
| # | ||||
| # Written by Alexander Haase, alexander.haase@rwth-aachen.de | ||||
| # | ||||
|  | ||||
| if [ -z "$LLVM_COV_BIN" ] | ||||
| then | ||||
| 	echo "LLVM_COV_BIN not set!" >& 2 | ||||
| 	exit 1 | ||||
| fi | ||||
|  | ||||
|  | ||||
| # Get LLVM version to find out. | ||||
| LLVM_VERSION=$($LLVM_COV_BIN -version | grep -i "LLVM version" \ | ||||
| 	| sed "s/^\([A-Za-z ]*\)\([0-9]\).\([0-9]\).*$/\2.\3/g") | ||||
|  | ||||
| if [ "$1" = "-v" ] | ||||
| then | ||||
| 	echo "llvm-cov-wrapper $LLVM_VERSION" | ||||
| 	exit 0 | ||||
| fi | ||||
|  | ||||
|  | ||||
| if [ -n "$LLVM_VERSION" ] | ||||
| then | ||||
| 	MAJOR=$(echo $LLVM_VERSION | cut -d'.' -f1) | ||||
| 	MINOR=$(echo $LLVM_VERSION | cut -d'.' -f2) | ||||
|  | ||||
| 	if [ $MAJOR -eq 3 ] && [ $MINOR -le 4 ] | ||||
| 	then | ||||
| 		if [ -f "$1" ] | ||||
| 		then | ||||
| 			filename=$(basename "$1") | ||||
| 			extension="${filename##*.}" | ||||
|  | ||||
| 			case "$extension" in | ||||
| 				"gcno") exec $LLVM_COV_BIN --gcno="$1" ;; | ||||
| 				"gcda") exec $LLVM_COV_BIN --gcda="$1" ;; | ||||
| 			esac | ||||
| 		fi | ||||
| 	fi | ||||
|  | ||||
| 	if [ $MAJOR -eq 3 ] && [ $MINOR -le 5 ] | ||||
| 	then | ||||
| 		exec $LLVM_COV_BIN $@ | ||||
| 	fi | ||||
| fi | ||||
|  | ||||
| exec $LLVM_COV_BIN gcov $@ | ||||
		Reference in New Issue
	
	Block a user
	 Martin Hořeňovský
					Martin Hořeňovský