summaryrefslogtreecommitdiffstats
path: root/config
diff options
context:
space:
mode:
authorkmu <kmu@hdfgroup.org>2020-01-14 17:25:49 (GMT)
committerkmu <kmu@hdfgroup.org>2020-01-14 17:25:49 (GMT)
commit71b817038d8cd82163cf71119873b2ba65a2c81b (patch)
treeff2e04387a658c1d4188f402bc332825710577b8 /config
parent7366709e4000a96a9942934da0d13474213567f3 (diff)
parentc3c60dc7b5d5104475748f9967135903e3974cc3 (diff)
downloadhdf5-71b817038d8cd82163cf71119873b2ba65a2c81b.zip
hdf5-71b817038d8cd82163cf71119873b2ba65a2c81b.tar.gz
hdf5-71b817038d8cd82163cf71119873b2ba65a2c81b.tar.bz2
Merge branch 'develop' of https://git.hdfgroup.org/scm/hdffv/hdf5 into develop
Diffstat (limited to 'config')
-rw-r--r--config/cmake/HDFCompilerFlags.cmake2
-rw-r--r--config/cmake/jrunTest.cmake239
-rw-r--r--config/cmake/scripts/CTestScript.cmake14
-rw-r--r--config/cmake/vfdTest.cmake2
-rw-r--r--config/cmake/volTest.cmake2
-rw-r--r--config/cmake_ext_mod/CTestCustom.cmake5
-rw-r--r--config/cmake_ext_mod/grepTest.cmake123
-rw-r--r--config/cmake_ext_mod/runTest.cmake234
-rw-r--r--config/gnu-flags2
-rw-r--r--config/sanitizer/LICENSE174
-rw-r--r--config/sanitizer/README.md307
-rw-r--r--config/sanitizer/code-coverage.cmake536
-rw-r--r--config/sanitizer/sanitizers.cmake96
-rw-r--r--config/sanitizer/tools.cmake111
14 files changed, 1570 insertions, 277 deletions
diff --git a/config/cmake/HDFCompilerFlags.cmake b/config/cmake/HDFCompilerFlags.cmake
index f49b674..c803384 100644
--- a/config/cmake/HDFCompilerFlags.cmake
+++ b/config/cmake/HDFCompilerFlags.cmake
@@ -200,7 +200,7 @@ if (NOT MSVC AND CMAKE_COMPILER_IS_GNUCC)
# Append more extra warning flags that only gcc 7.x+ know about
if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 7.0)
- set (H5_CFLAGS4 "${H5_CFLAGS4} -Walloc-zero -Walloca -Wduplicated-branches -Wformat-overflow=2 -Wformat-truncation=2 -Wimplicit-fallthrough=5 -Wrestrict")
+ set (H5_CFLAGS4 "${H5_CFLAGS4} -Walloc-zero -Walloca -Wduplicated-branches -Wformat-overflow=2 -Wformat-truncation=1 -Wimplicit-fallthrough=5 -Wrestrict")
endif ()
# Append more extra warning flags that only gcc 8.x+ know about
diff --git a/config/cmake/jrunTest.cmake b/config/cmake/jrunTest.cmake
index e736b7a..0315536 100644
--- a/config/cmake/jrunTest.cmake
+++ b/config/cmake/jrunTest.cmake
@@ -75,16 +75,19 @@ message (STATUS "COMMAND Result: ${TEST_RESULT}")
# if the .err file exists and ERRROR_APPEND is enabled
if (EXISTS "${TEST_FOLDER}/${TEST_OUTPUT}.err")
file (READ ${TEST_FOLDER}/${TEST_OUTPUT}.err TEST_STREAM)
- if (TEST_MASK_FILE)
- STRING(REGEX REPLACE "CurrentDir is [^\n]+\n" "CurrentDir is (dir name)\n" TEST_STREAM "${TEST_STREAM}")
- endif ()
+ list(LENGTH TEST_STREAM test_len)
+ if (test_len GREATER 0)
+ if (TEST_MASK_FILE)
+ STRING(REGEX REPLACE "CurrentDir is [^\n]+\n" "CurrentDir is (dir name)\n" TEST_STREAM "${TEST_STREAM}")
+ endif ()
- if (NOT ERROR_APPEND)
- # write back to original .err file
- file (WRITE ${TEST_FOLDER}/${TEST_OUTPUT}.err "${TEST_STREAM}")
- else ()
- # append error output to the stdout output file
- file (APPEND ${TEST_FOLDER}/${TEST_OUTPUT} "${TEST_STREAM}")
+ if (NOT ERROR_APPEND)
+ # write back to original .err file
+ file (WRITE ${TEST_FOLDER}/${TEST_OUTPUT}.err "${TEST_STREAM}")
+ else ()
+ # append error output to the stdout output file
+ file (APPEND ${TEST_FOLDER}/${TEST_OUTPUT} "${TEST_STREAM}")
+ endif ()
endif ()
endif ()
@@ -122,146 +125,172 @@ endif ()
message (STATUS "COMMAND Error: ${TEST_ERROR}")
# compare output files to references unless this must be skipped
+set (TEST_COMPARE_RESULT 0)
if (NOT TEST_SKIP_COMPARE)
if (EXISTS "${TEST_FOLDER}/${TEST_REFERENCE}")
- if (WIN32 OR MINGW)
- configure_file(${TEST_FOLDER}/${TEST_REFERENCE} ${TEST_FOLDER}/${TEST_REFERENCE}.tmp NEWLINE_STYLE CRLF)
- file(RENAME ${TEST_FOLDER}/${TEST_REFERENCE}.tmp ${TEST_FOLDER}/${TEST_REFERENCE})
- #file (READ ${TEST_FOLDER}/${TEST_REFERENCE} TEST_STREAM)
- #file (WRITE ${TEST_FOLDER}/${TEST_REFERENCE} "${TEST_STREAM}")
- endif ()
+ file (READ ${TEST_FOLDER}/${TEST_REFERENCE} TEST_STREAM)
+ list(LENGTH TEST_STREAM test_len)
+ if (test_len GREATER 0)
+ if (WIN32 OR MINGW)
+ configure_file(${TEST_FOLDER}/${TEST_REFERENCE} ${TEST_FOLDER}/${TEST_REFERENCE}.tmp NEWLINE_STYLE CRLF)
+ if (EXISTS "${TEST_FOLDER}/${TEST_REFERENCE}.tmp")
+ file(RENAME ${TEST_FOLDER}/${TEST_REFERENCE}.tmp ${TEST_FOLDER}/${TEST_REFERENCE})
+ endif ()
+ #file (READ ${TEST_FOLDER}/${TEST_REFERENCE} TEST_STREAM)
+ #file (WRITE ${TEST_FOLDER}/${TEST_REFERENCE} "${TEST_STREAM}")
+ endif ()
- if (NOT TEST_SORT_COMPARE)
- # now compare the output with the reference
- execute_process (
- COMMAND ${CMAKE_COMMAND} -E compare_files ${TEST_FOLDER}/${TEST_OUTPUT} ${TEST_FOLDER}/${TEST_REFERENCE}
- RESULT_VARIABLE TEST_RESULT
- )
- else ()
- file (STRINGS ${TEST_FOLDER}/${TEST_OUTPUT} v1)
- file (STRINGS ${TEST_FOLDER}/${TEST_REFERENCE} v2)
- list (SORT v1)
- list (SORT v2)
- if (NOT v1 STREQUAL v2)
- set(TEST_RESULT 1)
+ if (NOT TEST_SORT_COMPARE)
+ # now compare the output with the reference
+ execute_process (
+ COMMAND ${CMAKE_COMMAND} -E compare_files ${TEST_FOLDER}/${TEST_OUTPUT} ${TEST_FOLDER}/${TEST_REFERENCE}
+ RESULT_VARIABLE TEST_COMPARE_RESULT
+ )
+ else ()
+ file (STRINGS ${TEST_FOLDER}/${TEST_OUTPUT} v1)
+ file (STRINGS ${TEST_FOLDER}/${TEST_REFERENCE} v2)
+ list (SORT v1)
+ list (SORT v2)
+ if (NOT v1 STREQUAL v2)
+ set(TEST_COMPARE_RESULT 1)
+ endif ()
endif ()
- endif ()
- if (TEST_RESULT)
- set (TEST_RESULT 0)
- file (STRINGS ${TEST_FOLDER}/${TEST_OUTPUT} test_act)
- list (LENGTH test_act len_act)
- file (STRINGS ${TEST_FOLDER}/${TEST_REFERENCE} test_ref)
- list (LENGTH test_ref len_ref)
- if (len_act GREATER 0 AND len_ref GREATER 0)
- math (EXPR _FP_LEN "${len_ref} - 1")
- foreach (line RANGE 0 ${_FP_LEN})
- list (GET test_act ${line} str_act)
- list (GET test_ref ${line} str_ref)
- if (NOT str_act STREQUAL str_ref)
- if (str_act)
- set (TEST_RESULT 1)
- message (STATUS "line = ${line}\n***ACTUAL: ${str_act}\n****REFER: ${str_ref}\n")
+ if (TEST_COMPARE_RESULT)
+ set (TEST_COMPARE_RESULT 0)
+ file (STRINGS ${TEST_FOLDER}/${TEST_OUTPUT} test_act)
+ list (LENGTH test_act len_act)
+ file (STRINGS ${TEST_FOLDER}/${TEST_REFERENCE} test_ref)
+ list (LENGTH test_ref len_ref)
+ if (len_act GREATER 0 AND len_ref GREATER 0)
+ math (EXPR _FP_LEN "${len_ref} - 1")
+ foreach (line RANGE 0 ${_FP_LEN})
+ list (GET test_act ${line} str_act)
+ list (GET test_ref ${line} str_ref)
+ if (NOT str_act STREQUAL str_ref)
+ if (str_act)
+ set (TEST_COMPARE_RESULT 1)
+ message (STATUS "line = ${line}\n***ACTUAL: ${str_act}\n****REFER: ${str_ref}\n")
+ endif ()
endif ()
+ endforeach ()
+ else ()
+ if (len_act EQUAL 0)
+ message (STATUS "COMPARE Failed: ${TEST_FOLDER}/${TEST_OUTPUT} is empty")
+ endif ()
+ if (len_ref EQUAL 0)
+ message (STATUS "COMPARE Failed: ${TEST_FOLDER}/${TEST_REFERENCE} is empty")
endif ()
- endforeach ()
- else ()
- if (len_act EQUAL 0)
- message (STATUS "COMPARE Failed: ${TEST_FOLDER}/${TEST_OUTPUT} is empty")
endif ()
- if (len_ref EQUAL 0)
- message (STATUS "COMPARE Failed: ${TEST_FOLDER}/${TEST_REFERENCE} is empty")
+ if (NOT len_act EQUAL len_ref)
+ set (TEST_COMPARE_RESULT 1)
endif ()
endif ()
- if (NOT len_act EQUAL len_ref)
- set (TEST_RESULT 1)
- endif ()
endif ()
- message (STATUS "COMPARE Result: ${TEST_RESULT}")
+ message (STATUS "COMPARE Result: ${TEST_COMPARE_RESULT}")
# again, if return value is !=0 scream and shout
- if (TEST_RESULT)
+ if (TEST_COMPARE_RESULT)
message (FATAL_ERROR "Failed: The output of ${TEST_OUTPUT} did not match ${TEST_REFERENCE}")
endif ()
endif ()
# now compare the .err file with the error reference, if supplied
+ set (TEST_ERRREF_RESULT 0)
if (TEST_ERRREF)
- if (WIN32 OR MINGW)
- configure_file(${TEST_FOLDER}/${TEST_ERRREF} ${TEST_FOLDER}/${TEST_ERRREF}.tmp NEWLINE_STYLE CRLF)
- file(RENAME ${TEST_FOLDER}/${TEST_ERRREF}.tmp ${TEST_FOLDER}/${TEST_ERRREF})
- #file (READ ${TEST_FOLDER}/${TEST_ERRREF} TEST_STREAM)
- #file (WRITE ${TEST_FOLDER}/${TEST_ERRREF} "${TEST_STREAM}")
- endif ()
+ file (READ ${TEST_FOLDER}/${TEST_ERRREF} TEST_STREAM)
+ list(LENGTH TEST_STREAM test_len)
+ if (test_len GREATER 0)
+ if (WIN32 OR MINGW)
+ configure_file(${TEST_FOLDER}/${TEST_ERRREF} ${TEST_FOLDER}/${TEST_ERRREF}.tmp NEWLINE_STYLE CRLF)
+ if (EXISTS "${TEST_FOLDER}/${TEST_ERRREF}.tmp")
+ file(RENAME ${TEST_FOLDER}/${TEST_ERRREF}.tmp ${TEST_FOLDER}/${TEST_ERRREF})
+ endif ()
+ #file (READ ${TEST_FOLDER}/${TEST_ERRREF} TEST_STREAM)
+ #file (WRITE ${TEST_FOLDER}/${TEST_ERRREF} "${TEST_STREAM}")
+ endif ()
- # now compare the error output with the error reference
- execute_process (
- COMMAND ${CMAKE_COMMAND} -E compare_files ${TEST_FOLDER}/${TEST_OUTPUT}.err ${TEST_FOLDER}/${TEST_ERRREF}
- RESULT_VARIABLE TEST_RESULT
- )
- if (TEST_RESULT)
- set (TEST_RESULT 0)
- file (STRINGS ${TEST_FOLDER}/${TEST_OUTPUT}.err test_act)
- list (LENGTH test_act len_act)
- file (STRINGS ${TEST_FOLDER}/${TEST_ERRREF} test_ref)
- list (LENGTH test_ref len_ref)
- math (EXPR _FP_LEN "${len_ref} - 1")
- if (len_act GREATER 0 AND len_ref GREATER 0)
+ # now compare the error output with the error reference
+ execute_process (
+ COMMAND ${CMAKE_COMMAND} -E compare_files ${TEST_FOLDER}/${TEST_OUTPUT}.err ${TEST_FOLDER}/${TEST_ERRREF}
+ RESULT_VARIABLE TEST_ERRREF_RESULT
+ )
+ if (TEST_ERRREF_RESULT)
+ set (TEST_ERRREF_RESULT 0)
+ file (STRINGS ${TEST_FOLDER}/${TEST_OUTPUT}.err test_act)
+ list (LENGTH test_act len_act)
+ file (STRINGS ${TEST_FOLDER}/${TEST_ERRREF} test_ref)
+ list (LENGTH test_ref len_ref)
math (EXPR _FP_LEN "${len_ref} - 1")
- foreach (line RANGE 0 ${_FP_LEN})
- list (GET test_act ${line} str_act)
- list (GET test_ref ${line} str_ref)
- if (NOT str_act STREQUAL str_ref)
- if (str_act)
- set (TEST_RESULT 1)
- message (STATUS "line = ${line}\n***ACTUAL: ${str_act}\n****REFER: ${str_ref}\n")
+ if (len_act GREATER 0 AND len_ref GREATER 0)
+ math (EXPR _FP_LEN "${len_ref} - 1")
+ foreach (line RANGE 0 ${_FP_LEN})
+ list (GET test_act ${line} str_act)
+ list (GET test_ref ${line} str_ref)
+ if (NOT str_act STREQUAL str_ref)
+ if (str_act)
+ set (TEST_ERRREF_RESULT 1)
+ message (STATUS "line = ${line}\n***ACTUAL: ${str_act}\n****REFER: ${str_ref}\n")
+ endif ()
endif ()
+ endforeach ()
+ else ()
+ if (len_act EQUAL 0)
+ message (STATUS "COMPARE Failed: ${TEST_FOLDER}/${TEST_OUTPUT}.err is empty")
+ endif ()
+ if (len_ref EQUAL 0)
+ message (STATUS "COMPARE Failed: ${TEST_FOLDER}/${TEST_ERRREF} is empty")
endif ()
- endforeach ()
- else ()
- if (len_act EQUAL 0)
- message (STATUS "COMPARE Failed: ${TEST_FOLDER}/${TEST_OUTPUT}.err is empty")
endif ()
- if (len_ref EQUAL 0)
- message (STATUS "COMPARE Failed: ${TEST_FOLDER}/${TEST_ERRREF} is empty")
+ if (NOT len_act EQUAL len_ref)
+ set (TEST_ERRREF_RESULT 1)
endif ()
endif ()
- if (NOT len_act EQUAL len_ref)
- set (TEST_RESULT 1)
- endif ()
endif ()
- message (STATUS "COMPARE Result: ${TEST_RESULT}")
+ message (STATUS "COMPARE Result: ${TEST_ERRREF_RESULT}")
# again, if return value is !=0 scream and shout
- if (TEST_RESULT)
+ if (TEST_ERRREF_RESULT)
message (FATAL_ERROR "Failed: The error output of ${TEST_OUTPUT}.err did not match ${TEST_ERRREF}")
endif ()
endif ()
endif ()
+set (TEST_GREP_RESULT 0)
if (TEST_GREP_COMPARE)
# now grep the output with the reference
file (READ ${TEST_FOLDER}/${TEST_OUTPUT} TEST_STREAM)
+ list(LENGTH TEST_STREAM test_len)
+ if (test_len GREATER 0)
+ # TEST_REFERENCE should always be matched
+ string (REGEX MATCH "${TEST_REFERENCE}" TEST_MATCH ${TEST_STREAM})
+ string (COMPARE EQUAL "${TEST_REFERENCE}" "${TEST_MATCH}" TEST_GREP_RESULT)
+ if (NOT TEST_GREP_RESULT)
+ message (FATAL_ERROR "Failed: The output of ${TEST_PROGRAM} did not contain ${TEST_REFERENCE}")
+ endif ()
- # TEST_REFERENCE should always be matched
- string (REGEX MATCH "${TEST_REFERENCE}" TEST_MATCH ${TEST_STREAM})
- string (COMPARE EQUAL "${TEST_REFERENCE}" "${TEST_MATCH}" TEST_RESULT)
- if (NOT TEST_RESULT)
- message (FATAL_ERROR "Failed: The output of ${TEST_PROGRAM} did not contain ${TEST_REFERENCE}")
- endif ()
-
- string (REGEX MATCH "${TEST_FILTER}" TEST_MATCH ${TEST_STREAM})
- if (TEST_EXPECT)
- # TEST_EXPECT (1) interprets TEST_FILTER as; NOT to match
- string (LENGTH "${TEST_MATCH}" TEST_RESULT)
- if (TEST_RESULT)
- message (FATAL_ERROR "Failed: The output of ${TEST_PROGRAM} did contain ${TEST_FILTER}")
+ string (REGEX MATCH "${TEST_FILTER}" TEST_MATCH ${TEST_STREAM})
+ if (TEST_EXPECT)
+ # TEST_EXPECT (1) interprets TEST_FILTER as; NOT to match
+ string (LENGTH "${TEST_MATCH}" TEST_GREP_RESULT)
+ if (TEST_GREP_RESULT)
+ message (FATAL_ERROR "Failed: The output of ${TEST_PROGRAM} did contain ${TEST_FILTER}")
+ endif ()
endif ()
endif ()
endif ()
+# dump the output unless nodisplay option is set
+if (TEST_SKIP_COMPARE AND NOT TEST_NO_DISPLAY)
+ file (READ ${TEST_FOLDER}/${TEST_OUTPUT} TEST_STREAM)
+ execute_process (
+ COMMAND ${CMAKE_COMMAND} -E echo ${TEST_STREAM}
+ RESULT_VARIABLE TEST_RESULT
+ )
+endif ()
+
# everything went fine...
message (STATUS "${TEST_PROGRAM} Passed")
diff --git a/config/cmake/scripts/CTestScript.cmake b/config/cmake/scripts/CTestScript.cmake
index 8425312..3c85d48 100644
--- a/config/cmake/scripts/CTestScript.cmake
+++ b/config/cmake/scripts/CTestScript.cmake
@@ -50,6 +50,17 @@ if (SITE_BUILDNAME_SUFFIX)
endif ()
set (BUILD_OPTIONS "${ADD_BUILD_OPTIONS} -DSITE:STRING=${CTEST_SITE} -DBUILDNAME:STRING=${CTEST_BUILD_NAME}")
+# Launchers work only with Makefile and Ninja generators.
+if(NOT "${CTEST_CMAKE_GENERATOR}" MATCHES "Make|Ninja")
+ set(CTEST_USE_LAUNCHERS 0)
+ set(ENV{CTEST_USE_LAUNCHERS_DEFAULT} 0)
+ set(BUILD_OPTIONS "${BUILD_OPTIONS} -DCTEST_USE_LAUNCHERS:BOOL=OFF")
+else()
+ set(CTEST_USE_LAUNCHERS 1)
+ set(ENV{CTEST_USE_LAUNCHERS_DEFAULT} 1)
+ set(BUILD_OPTIONS "${BUILD_OPTIONS} -DCTEST_USE_LAUNCHERS:BOOL=ON")
+endif()
+
#-----------------------------------------------------------------------------
# MAC machines need special option
#-----------------------------------------------------------------------------
@@ -219,9 +230,6 @@ else ()
)
endif ()
-set(CTEST_USE_LAUNCHERS 1)
-set(ENV{CTEST_USE_LAUNCHERS_DEFAULT} 1)
-
#-----------------------------------------------------------------------------
## -- set output to english
set ($ENV{LC_MESSAGES} "en_EN")
diff --git a/config/cmake/vfdTest.cmake b/config/cmake/vfdTest.cmake
index 12ee40b..c07d005 100644
--- a/config/cmake/vfdTest.cmake
+++ b/config/cmake/vfdTest.cmake
@@ -64,7 +64,7 @@ if (NOT TEST_RESULT EQUAL TEST_EXPECT)
if (NOT TEST_NOERRDISPLAY)
if (EXISTS "${TEST_FOLDER}/${TEST_OUTPUT}_${TEST_VFD}.out")
file (READ ${TEST_FOLDER}/${TEST_OUTPUT}_${TEST_VFD}.out TEST_STREAM)
- message (STATUS "Output USING ${TEST_VFD}:\n${TEST_STREAM}")
+ message (STATUS "Output USING ${TEST_VFD}:\n${TEST_STREAM}")
endif ()
endif ()
message (FATAL_ERROR "Failed: Test program ${TEST_PROGRAM} exited != ${TEST_EXPECT}.\n${TEST_ERROR}")
diff --git a/config/cmake/volTest.cmake b/config/cmake/volTest.cmake
index 1dcd2b1..e735109 100644
--- a/config/cmake/volTest.cmake
+++ b/config/cmake/volTest.cmake
@@ -64,7 +64,7 @@ if (NOT TEST_RESULT EQUAL TEST_EXPECT)
if (NOT TEST_NOERRDISPLAY)
if (EXISTS "${TEST_FOLDER}/${TEST_OUTPUT}.out")
file (READ ${TEST_FOLDER}/${TEST_OUTPUT}.out TEST_STREAM)
- message (STATUS "Output USING ${TEST_VOL}:\n${TEST_STREAM}")
+ message (STATUS "Output USING ${TEST_VOL}:\n${TEST_STREAM}")
endif ()
endif ()
message (FATAL_ERROR "Failed: Test program ${TEST_PROGRAM} exited != ${TEST_EXPECT}.\n${TEST_ERROR}")
diff --git a/config/cmake_ext_mod/CTestCustom.cmake b/config/cmake_ext_mod/CTestCustom.cmake
index 025bce4..f8d4cd6 100644
--- a/config/cmake_ext_mod/CTestCustom.cmake
+++ b/config/cmake_ext_mod/CTestCustom.cmake
@@ -1,16 +1,17 @@
set (CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS 3000)
-
+
set (CTEST_CUSTOM_WARNING_EXCEPTION
${CTEST_CUSTOM_WARNING_EXCEPTION}
"note.*expected.*void.*but argument is of type.*volatile"
"SZIP.src.*:[ \t]*warning"
+ "ZLIB.src.*:[ \t]*warning"
"jpeg.src.*:[ \t]*warning"
"POSIX name for this item is deprecated"
"disabling jobserver mode"
"warning.*implicit declaration of function"
"note: expanded from macro"
)
-
+
set (CTEST_CUSTOM_MEMCHECK_IGNORE
${CTEST_CUSTOM_MEMCHECK_IGNORE}
)
diff --git a/config/cmake_ext_mod/grepTest.cmake b/config/cmake_ext_mod/grepTest.cmake
index 78ee0da..c65c951 100644
--- a/config/cmake_ext_mod/grepTest.cmake
+++ b/config/cmake_ext_mod/grepTest.cmake
@@ -82,91 +82,102 @@ if (TEST_FIND_RESULT GREATER 0)
endif ()
# if the TEST_ERRREF exists grep the error output with the error reference
+set (TEST_ERRREF_RESULT 0)
if (TEST_ERRREF)
# if the .err file exists grep the error output with the error reference before comparing stdout
if (EXISTS "${TEST_FOLDER}/${TEST_OUTPUT}.err")
file (READ ${TEST_FOLDER}/${TEST_OUTPUT}.err TEST_ERR_STREAM)
-
- # TEST_ERRREF should always be matched
- string (REGEX MATCH "${TEST_ERRREF}" TEST_MATCH ${TEST_ERR_STREAM})
- string (COMPARE EQUAL "${TEST_ERRREF}" "${TEST_MATCH}" TEST_RESULT)
- if (NOT TEST_RESULT)
- message (FATAL_ERROR "Failed: The error output of ${TEST_PROGRAM} did not contain ${TEST_ERRREF}")
+ list(LENGTH TEST_ERR_STREAM test_len)
+ if (test_len GREATER 0)
+ # TEST_ERRREF should always be matched
+ string (REGEX MATCH "${TEST_ERRREF}" TEST_MATCH ${TEST_ERR_STREAM})
+ string (COMPARE EQUAL "${TEST_ERRREF}" "${TEST_MATCH}" TEST_ERRREF_RESULT)
+ if (NOT TEST_ERRREF_RESULT)
+ message (FATAL_ERROR "Failed: The error output of ${TEST_PROGRAM} did not contain ${TEST_ERRREF}")
+ endif ()
endif ()
endif ()
#always compare output file to reference unless this must be skipped
+ set (TEST_COMPARE_RESULT 0)
if (NOT TEST_SKIP_COMPARE)
if (EXISTS "${TEST_FOLDER}/${TEST_REFERENCE}")
- if (WIN32 OR MINGW)
- configure_file(${TEST_FOLDER}/${TEST_REFERENCE} ${TEST_FOLDER}/${TEST_REFERENCE}.tmp NEWLINE_STYLE CRLF)
- file(RENAME ${TEST_FOLDER}/${TEST_REFERENCE}.tmp ${TEST_FOLDER}/${TEST_REFERENCE})
- #file (READ ${TEST_FOLDER}/${TEST_REFERENCE} TEST_STREAM)
- #file (WRITE ${TEST_FOLDER}/${TEST_REFERENCE} "${TEST_STREAM}")
- endif ()
- if (NOT TEST_SORT_COMPARE)
- # now compare the output with the reference
- execute_process (
- COMMAND ${CMAKE_COMMAND} -E compare_files ${TEST_FOLDER}/${TEST_OUTPUT} ${TEST_FOLDER}/${TEST_REFERENCE}
- RESULT_VARIABLE TEST_RESULT
- )
- else ()
- file (STRINGS ${TEST_FOLDER}/${TEST_OUTPUT} v1)
- file (STRINGS ${TEST_FOLDER}/${TEST_REFERENCE} v2)
- list (SORT v1)
- list (SORT v2)
- if (NOT v1 STREQUAL v2)
- set(TEST_RESULT 1)
+ file (READ ${TEST_FOLDER}/${TEST_REFERENCE} TEST_STREAM)
+ list(LENGTH TEST_STREAM test_len)
+ if (test_len GREATER 0)
+ if (WIN32 OR MINGW)
+ configure_file(${TEST_FOLDER}/${TEST_REFERENCE} ${TEST_FOLDER}/${TEST_REFERENCE}.tmp NEWLINE_STYLE CRLF)
+ if (EXISTS "${TEST_FOLDER}/${TEST_REFERENCE}.tmp")
+ file(RENAME ${TEST_FOLDER}/${TEST_REFERENCE}.tmp ${TEST_FOLDER}/${TEST_REFERENCE})
+ endif ()
+ #file (READ ${TEST_FOLDER}/${TEST_REFERENCE} TEST_STREAM)
+ #file (WRITE ${TEST_FOLDER}/${TEST_REFERENCE} "${TEST_STREAM}")
+ endif ()
+ if (NOT TEST_SORT_COMPARE)
+ # now compare the output with the reference
+ execute_process (
+ COMMAND ${CMAKE_COMMAND} -E compare_files ${TEST_FOLDER}/${TEST_OUTPUT} ${TEST_FOLDER}/${TEST_REFERENCE}
+ RESULT_VARIABLE TEST_COMPARE_RESULT
+ )
+ else ()
+ file (STRINGS ${TEST_FOLDER}/${TEST_OUTPUT} v1)
+ file (STRINGS ${TEST_FOLDER}/${TEST_REFERENCE} v2)
+ list (SORT v1)
+ list (SORT v2)
+ if (NOT v1 STREQUAL v2)
+ set(TEST_COMPARE_RESULT 1)
+ endif ()
endif ()
- endif ()
- if (TEST_RESULT)
- set (TEST_RESULT 0)
- file (STRINGS ${TEST_FOLDER}/${TEST_OUTPUT} test_act)
- list (LENGTH test_act len_act)
- file (STRINGS ${TEST_FOLDER}/${TEST_REFERENCE} test_ref)
- list (LENGTH test_ref len_ref)
- if (len_act GREATER 0 AND len_ref GREATER 0)
- math (EXPR _FP_LEN "${len_ref} - 1")
- foreach (line RANGE 0 ${_FP_LEN})
- list (GET test_act ${line} str_act)
- list (GET test_ref ${line} str_ref)
- if (NOT str_act STREQUAL str_ref)
- if (str_act)
- set (TEST_RESULT 1)
- message (STATUS "line = ${line}\n***ACTUAL: ${str_act}\n****REFER: ${str_ref}\n")
+ if (TEST_COMPARE_RESULT)
+ set (TEST_COMPARE_RESULT 0)
+ file (STRINGS ${TEST_FOLDER}/${TEST_OUTPUT} test_act)
+ list (LENGTH test_act len_act)
+ file (STRINGS ${TEST_FOLDER}/${TEST_REFERENCE} test_ref)
+ list (LENGTH test_ref len_ref)
+ if (len_act GREATER 0 AND len_ref GREATER 0)
+ math (EXPR _FP_LEN "${len_ref} - 1")
+ foreach (line RANGE 0 ${_FP_LEN})
+ list (GET test_act ${line} str_act)
+ list (GET test_ref ${line} str_ref)
+ if (NOT str_act STREQUAL str_ref)
+ if (str_act)
+ set (TEST_COMPARE_RESULT 1)
+ message (STATUS "line = ${line}\n***ACTUAL: ${str_act}\n****REFER: ${str_ref}\n")
+ endif ()
endif ()
+ endforeach ()
+ else ()
+ if (len_act EQUAL 0)
+ message (STATUS "COMPARE Failed: ${TEST_FOLDER}/${TEST_OUTPUT} is empty")
+ endif ()
+ if (len_ref EQUAL 0)
+ message (STATUS "COMPARE Failed: ${TEST_FOLDER}/${TEST_REFERENCE} is empty")
endif ()
- endforeach ()
- else ()
- if (len_act EQUAL 0)
- message (STATUS "COMPARE Failed: ${TEST_FOLDER}/${TEST_OUTPUT} is empty")
endif ()
- if (len_ref EQUAL 0)
- message (STATUS "COMPARE Failed: ${TEST_FOLDER}/${TEST_REFERENCE} is empty")
+ if (NOT len_act EQUAL len_ref)
+ set (TEST_COMPARE_RESULT 1)
endif ()
endif ()
- if (NOT len_act EQUAL len_ref)
- set (TEST_RESULT 1)
- endif ()
endif ()
- message (STATUS "COMPARE Result: ${TEST_RESULT}")
+ message (STATUS "COMPARE Result: ${TEST_COMPARE_RESULT}")
# again, if return value is !=0 scream and shout
- if (TEST_RESULT)
+ if (TEST_COMPARE_RESULT)
message (FATAL_ERROR "Failed: The output of ${TEST_OUTPUT} did not match ${TEST_REFERENCE}")
endif ()
endif ()
endif ()
else ()
# else grep the output with the reference
+ set (TEST_GREP_RESULT 0)
file (READ ${TEST_FOLDER}/${TEST_OUTPUT} TEST_STREAM)
# TEST_REFERENCE should always be matched
string (REGEX MATCH "${TEST_REFERENCE}" TEST_MATCH ${TEST_STREAM})
- string (COMPARE EQUAL "${TEST_REFERENCE}" "${TEST_MATCH}" TEST_RESULT)
- if (NOT TEST_RESULT)
+ string (COMPARE EQUAL "${TEST_REFERENCE}" "${TEST_MATCH}" TEST_GREP_RESULT)
+ if (NOT TEST_GREP_RESULT)
message (FATAL_ERROR "Failed: The output of ${TEST_PROGRAM} did not contain ${TEST_REFERENCE}")
endif ()
endif ()
@@ -176,8 +187,8 @@ if (TEST_FILTER)
string (REGEX MATCH "${TEST_FILTER}" TEST_MATCH ${TEST_STREAM})
if (TEST_EXPECT)
# TEST_EXPECT (1) interprets TEST_FILTER as; NOT to match
- string (LENGTH "${TEST_MATCH}" TEST_RESULT)
- if (TEST_RESULT)
+ string (LENGTH "${TEST_MATCH}" TEST_GREP_RESULT)
+ if (TEST_GREP_RESULT)
message (FATAL_ERROR "Failed: The output of ${TEST_PROGRAM} did contain ${TEST_FILTER}")
endif ()
endif ()
diff --git a/config/cmake_ext_mod/runTest.cmake b/config/cmake_ext_mod/runTest.cmake
index 6f633f3..885e4f7 100644
--- a/config/cmake_ext_mod/runTest.cmake
+++ b/config/cmake_ext_mod/runTest.cmake
@@ -90,18 +90,21 @@ message (STATUS "COMMAND Result: ${TEST_RESULT}")
# if the .err file exists and ERRROR_APPEND is enabled
if (EXISTS "${TEST_FOLDER}/${TEST_OUTPUT}.err")
file (READ ${TEST_FOLDER}/${TEST_OUTPUT}.err TEST_STREAM)
- if (TEST_MASK_FILE)
- STRING(REGEX REPLACE "CurrentDir is [^\n]+\n" "CurrentDir is (dir name)\n" TEST_STREAM "${TEST_STREAM}")
- endif ()
- # remove special output
- string (REGEX REPLACE "^.*_pmi_alps[^\n]+\n" "" TEST_STREAM "${TEST_STREAM}")
+ list(LENGTH TEST_STREAM test_len)
+ if (test_len GREATER 0)
+ if (TEST_MASK_FILE)
+ STRING(REGEX REPLACE "CurrentDir is [^\n]+\n" "CurrentDir is (dir name)\n" TEST_STREAM "${TEST_STREAM}")
+ endif ()
+ # remove special output
+ string (REGEX REPLACE "^.*_pmi_alps[^\n]+\n" "" TEST_STREAM "${TEST_STREAM}")
- if (NOT ERROR_APPEND)
- # write back to original .err file
- file (WRITE ${TEST_FOLDER}/${TEST_OUTPUT}.err "${TEST_STREAM}")
- else ()
- # append error output to the stdout output file
- file (APPEND ${TEST_FOLDER}/${TEST_OUTPUT} "${TEST_STREAM}")
+ if (NOT ERROR_APPEND)
+ # write back to original .err file
+ file (WRITE ${TEST_FOLDER}/${TEST_OUTPUT}.err "${TEST_STREAM}")
+ else ()
+ # append error output to the stdout output file
+ file (APPEND ${TEST_FOLDER}/${TEST_OUTPUT} "${TEST_STREAM}")
+ endif ()
endif ()
endif ()
@@ -203,142 +206,159 @@ if (TEST_REF_FILTER)
endif ()
# compare output files to references unless this must be skipped
+set (TEST_COMPARE_RESULT 0)
if (NOT TEST_SKIP_COMPARE)
if (EXISTS "${TEST_FOLDER}/${TEST_REFERENCE}")
- if (WIN32 OR MINGW)
- configure_file(${TEST_FOLDER}/${TEST_REFERENCE} ${TEST_FOLDER}/${TEST_REFERENCE}.tmp NEWLINE_STYLE CRLF)
- file(RENAME ${TEST_FOLDER}/${TEST_REFERENCE}.tmp ${TEST_FOLDER}/${TEST_REFERENCE})
- #file (READ ${TEST_FOLDER}/${TEST_REFERENCE} TEST_STREAM)
- #file (WRITE ${TEST_FOLDER}/${TEST_REFERENCE} "${TEST_STREAM}")
- endif ()
+ file (READ ${TEST_FOLDER}/${TEST_REFERENCE} TEST_STREAM)
+ list(LENGTH TEST_STREAM test_len)
+ if (test_len GREATER 0)
+ if (WIN32 OR MINGW)
+ configure_file(${TEST_FOLDER}/${TEST_REFERENCE} ${TEST_FOLDER}/${TEST_REFERENCE}.tmp NEWLINE_STYLE CRLF)
+ if (EXISTS "${TEST_FOLDER}/${TEST_REFERENCE}.tmp")
+ file(RENAME ${TEST_FOLDER}/${TEST_REFERENCE}.tmp ${TEST_FOLDER}/${TEST_REFERENCE})
+ endif ()
+ #file (READ ${TEST_FOLDER}/${TEST_REFERENCE} TEST_STREAM)
+ #file (WRITE ${TEST_FOLDER}/${TEST_REFERENCE} "${TEST_STREAM}")
+ endif ()
- if (NOT TEST_SORT_COMPARE)
- # now compare the output with the reference
- execute_process (
- COMMAND ${CMAKE_COMMAND} -E compare_files ${TEST_FOLDER}/${TEST_OUTPUT} ${TEST_FOLDER}/${TEST_REFERENCE}
- RESULT_VARIABLE TEST_RESULT
- )
- else ()
- file (STRINGS ${TEST_FOLDER}/${TEST_OUTPUT} v1)
- file (STRINGS ${TEST_FOLDER}/${TEST_REFERENCE} v2)
- list (SORT v1)
- list (SORT v2)
- if (NOT v1 STREQUAL v2)
- set(TEST_RESULT 1)
+ if (NOT TEST_SORT_COMPARE)
+ # now compare the output with the reference
+ execute_process (
+ COMMAND ${CMAKE_COMMAND} -E compare_files ${TEST_FOLDER}/${TEST_OUTPUT} ${TEST_FOLDER}/${TEST_REFERENCE}
+ RESULT_VARIABLE TEST_COMPARE_RESULT
+ )
+ else ()
+ file (STRINGS ${TEST_FOLDER}/${TEST_OUTPUT} v1)
+ file (STRINGS ${TEST_FOLDER}/${TEST_REFERENCE} v2)
+ list (SORT v1)
+ list (SORT v2)
+ if (NOT v1 STREQUAL v2)
+ set(TEST_COMPARE_RESULT 1)
+ endif ()
endif ()
- endif ()
- if (TEST_RESULT)
- set (TEST_RESULT 0)
- file (STRINGS ${TEST_FOLDER}/${TEST_OUTPUT} test_act)
- list (LENGTH test_act len_act)
- file (STRINGS ${TEST_FOLDER}/${TEST_REFERENCE} test_ref)
- list (LENGTH test_ref len_ref)
- if (len_act GREATER 0 AND len_ref GREATER 0)
- math (EXPR _FP_LEN "${len_ref} - 1")
- foreach (line RANGE 0 ${_FP_LEN})
- list (GET test_act ${line} str_act)
- list (GET test_ref ${line} str_ref)
- if (NOT str_act STREQUAL str_ref)
- if (str_act)
- set (TEST_RESULT 1)
- message (STATUS "line = ${line}\n***ACTUAL: ${str_act}\n****REFER: ${str_ref}\n")
+ if (TEST_COMPARE_RESULT)
+ set (TEST_COMPARE_RESULT 0)
+ file (STRINGS ${TEST_FOLDER}/${TEST_OUTPUT} test_act)
+ list (LENGTH test_act len_act)
+ file (STRINGS ${TEST_FOLDER}/${TEST_REFERENCE} test_ref)
+ list (LENGTH test_ref len_ref)
+ if (len_act GREATER 0 AND len_ref GREATER 0)
+ math (EXPR _FP_LEN "${len_ref} - 1")
+ foreach (line RANGE 0 ${_FP_LEN})
+ list (GET test_act ${line} str_act)
+ list (GET test_ref ${line} str_ref)
+ if (NOT str_act STREQUAL str_ref)
+ if (str_act)
+ set (TEST_COMPARE_RESULT 1)
+ message (STATUS "line = ${line}\n***ACTUAL: ${str_act}\n****REFER: ${str_ref}\n")
+ endif ()
endif ()
+ endforeach ()
+ else ()
+ if (len_act EQUAL 0)
+ message (STATUS "COMPARE Failed: ${TEST_FOLDER}/${TEST_OUTPUT} is empty")
+ endif ()
+ if (len_ref EQUAL 0)
+ message (STATUS "COMPARE Failed: ${TEST_FOLDER}/${TEST_REFERENCE} is empty")
endif ()
- endforeach ()
- else ()
- if (len_act EQUAL 0)
- message (STATUS "COMPARE Failed: ${TEST_FOLDER}/${TEST_OUTPUT} is empty")
endif ()
- if (len_ref EQUAL 0)
- message (STATUS "COMPARE Failed: ${TEST_FOLDER}/${TEST_REFERENCE} is empty")
+ if (NOT len_act EQUAL len_ref)
+ set (TEST_COMPARE_RESULT 1)
endif ()
endif ()
- if (NOT len_act EQUAL len_ref)
- set (TEST_RESULT 1)
- endif ()
endif ()
- message (STATUS "COMPARE Result: ${TEST_RESULT}")
+ message (STATUS "COMPARE Result: ${TEST_COMPARE_RESULT}")
# again, if return value is !=0 scream and shout
- if (TEST_RESULT)
+ if (TEST_COMPARE_RESULT)
message (FATAL_ERROR "Failed: The output of ${TEST_OUTPUT} did not match ${TEST_REFERENCE}")
endif ()
endif ()
# now compare the .err file with the error reference, if supplied
+ set (TEST_ERRREF_RESULT 0)
if (TEST_ERRREF)
- if (WIN32 OR MINGW)
- configure_file(${TEST_FOLDER}/${TEST_ERRREF} ${TEST_FOLDER}/${TEST_ERRREF}.tmp NEWLINE_STYLE CRLF)
- file(RENAME ${TEST_FOLDER}/${TEST_ERRREF}.tmp ${TEST_FOLDER}/${TEST_ERRREF})
- #file (READ ${TEST_FOLDER}/${TEST_ERRREF} TEST_STREAM)
- #file (WRITE ${TEST_FOLDER}/${TEST_ERRREF} "${TEST_STREAM}")
- endif ()
+ file (READ ${TEST_FOLDER}/${TEST_ERRREF} TEST_STREAM)
+ list(LENGTH TEST_STREAM test_len)
+ if (test_len GREATER 0)
+ if (WIN32 OR MINGW)
+ configure_file(${TEST_FOLDER}/${TEST_ERRREF} ${TEST_FOLDER}/${TEST_ERRREF}.tmp NEWLINE_STYLE CRLF)
+ if (EXISTS "${TEST_FOLDER}/${TEST_ERRREF}.tmp")
+ file(RENAME ${TEST_FOLDER}/${TEST_ERRREF}.tmp ${TEST_FOLDER}/${TEST_ERRREF})
+ endif ()
+ #file (READ ${TEST_FOLDER}/${TEST_ERRREF} TEST_STREAM)
+ #file (WRITE ${TEST_FOLDER}/${TEST_ERRREF} "${TEST_STREAM}")
+ endif ()
- # now compare the error output with the error reference
- execute_process (
- COMMAND ${CMAKE_COMMAND} -E compare_files ${TEST_FOLDER}/${TEST_OUTPUT}.err ${TEST_FOLDER}/${TEST_ERRREF}
- RESULT_VARIABLE TEST_RESULT
- )
- if (TEST_RESULT)
- set (TEST_RESULT 0)
- file (STRINGS ${TEST_FOLDER}/${TEST_OUTPUT}.err test_act)
- list (LENGTH test_act len_act)
- file (STRINGS ${TEST_FOLDER}/${TEST_ERRREF} test_ref)
- list (LENGTH test_ref len_ref)
- math (EXPR _FP_LEN "${len_ref} - 1")
- if (len_act GREATER 0 AND len_ref GREATER 0)
+ # now compare the error output with the error reference
+ execute_process (
+ COMMAND ${CMAKE_COMMAND} -E compare_files ${TEST_FOLDER}/${TEST_OUTPUT}.err ${TEST_FOLDER}/${TEST_ERRREF}
+ RESULT_VARIABLE TEST_ERRREF_RESULT
+ )
+ if (TEST_ERRREF_RESULT)
+ set (TEST_ERRREF_RESULT 0)
+ file (STRINGS ${TEST_FOLDER}/${TEST_OUTPUT}.err test_act)
+ list (LENGTH test_act len_act)
+ file (STRINGS ${TEST_FOLDER}/${TEST_ERRREF} test_ref)
+ list (LENGTH test_ref len_ref)
math (EXPR _FP_LEN "${len_ref} - 1")
- foreach (line RANGE 0 ${_FP_LEN})
- list (GET test_act ${line} str_act)
- list (GET test_ref ${line} str_ref)
- if (NOT str_act STREQUAL str_ref)
- if (str_act)
- set (TEST_RESULT 1)
- message (STATUS "line = ${line}\n***ACTUAL: ${str_act}\n****REFER: ${str_ref}\n")
+ if (len_act GREATER 0 AND len_ref GREATER 0)
+ math (EXPR _FP_LEN "${len_ref} - 1")
+ foreach (line RANGE 0 ${_FP_LEN})
+ list (GET test_act ${line} str_act)
+ list (GET test_ref ${line} str_ref)
+ if (NOT str_act STREQUAL str_ref)
+ if (str_act)
+ set (TEST_ERRREF_RESULT 1)
+ message (STATUS "line = ${line}\n***ACTUAL: ${str_act}\n****REFER: ${str_ref}\n")
+ endif ()
endif ()
+ endforeach ()
+ else ()
+ if (len_act EQUAL 0)
+ message (STATUS "COMPARE Failed: ${TEST_FOLDER}/${TEST_OUTPUT}.err is empty")
+ endif ()
+ if (len_ref EQUAL 0)
+ message (STATUS "COMPARE Failed: ${TEST_FOLDER}/${TEST_ERRREF} is empty")
endif ()
- endforeach ()
- else ()
- if (len_act EQUAL 0)
- message (STATUS "COMPARE Failed: ${TEST_FOLDER}/${TEST_OUTPUT}.err is empty")
endif ()
- if (len_ref EQUAL 0)
- message (STATUS "COMPARE Failed: ${TEST_FOLDER}/${TEST_ERRREF} is empty")
+ if (NOT len_act EQUAL len_ref)
+ set (TEST_ERRREF_RESULT 1)
endif ()
endif ()
- if (NOT len_act EQUAL len_ref)
- set (TEST_RESULT 1)
- endif ()
endif ()
- message (STATUS "COMPARE Result: ${TEST_RESULT}")
+ message (STATUS "COMPARE Result: ${TEST_ERRREF_RESULT}")
# again, if return value is !=0 scream and shout
- if (TEST_RESULT)
+ if (TEST_ERRREF_RESULT)
message (FATAL_ERROR "Failed: The error output of ${TEST_OUTPUT}.err did not match ${TEST_ERRREF}")
endif ()
endif ()
endif ()
+set (TEST_GREP_RESULT 0)
if (TEST_GREP_COMPARE)
# now grep the output with the reference
file (READ ${TEST_FOLDER}/${TEST_OUTPUT} TEST_STREAM)
+ list(LENGTH TEST_STREAM test_len)
+ if (test_len GREATER 0)
+ # TEST_REFERENCE should always be matched
+ string (REGEX MATCH "${TEST_REFERENCE}" TEST_MATCH ${TEST_STREAM})
+ string (COMPARE EQUAL "${TEST_REFERENCE}" "${TEST_MATCH}" TEST_GREP_RESULT)
+ if (NOT TEST_GREP_RESULT)
+ message (FATAL_ERROR "Failed: The output of ${TEST_PROGRAM} did not contain ${TEST_REFERENCE}")
+ endif ()
- # TEST_REFERENCE should always be matched
- string (REGEX MATCH "${TEST_REFERENCE}" TEST_MATCH ${TEST_STREAM})
- string (COMPARE EQUAL "${TEST_REFERENCE}" "${TEST_MATCH}" TEST_RESULT)
- if (NOT TEST_RESULT)
- message (FATAL_ERROR "Failed: The output of ${TEST_PROGRAM} did not contain ${TEST_REFERENCE}")
- endif ()
-
- string (REGEX MATCH "${TEST_FILTER}" TEST_MATCH ${TEST_STREAM})
- if (TEST_EXPECT)
- # TEST_EXPECT (1) interprets TEST_FILTER as; NOT to match
- string (LENGTH "${TEST_MATCH}" TEST_RESULT)
- if (TEST_RESULT)
- message (FATAL_ERROR "Failed: The output of ${TEST_PROGRAM} did contain ${TEST_FILTER}")
+ string (REGEX MATCH "${TEST_FILTER}" TEST_MATCH ${TEST_STREAM})
+ if (TEST_EXPECT)
+ # TEST_EXPECT (1) interprets TEST_FILTER as; NOT to match
+ string (LENGTH "${TEST_MATCH}" TEST_GREP_RESULT)
+ if (TEST_GREP_RESULT)
+ message (FATAL_ERROR "Failed: The output of ${TEST_PROGRAM} did contain ${TEST_FILTER}")
+ endif ()
endif ()
endif ()
endif ()
diff --git a/config/gnu-flags b/config/gnu-flags
index 16795d0..a5f3258 100644
--- a/config/gnu-flags
+++ b/config/gnu-flags
@@ -276,7 +276,7 @@ if test "X-gcc" = "X-$cc_vendor"; then
# gcc 7
if test $cc_vers_major -ge 7; then
DEVELOPER_WARNING_CFLAGS="$DEVELOPER_WARNING_CFLAGS -Wstringop-overflow=2"
- H5_CFLAGS="$H5_CFLAGS -Walloc-zero -Walloca -Wduplicated-branches -Wformat-overflow=2 -Wformat-truncation=2 -Wimplicit-fallthrough=5 -Wrestrict"
+ H5_CFLAGS="$H5_CFLAGS -Walloc-zero -Walloca -Wduplicated-branches -Wformat-overflow=2 -Wformat-truncation=1 -Wimplicit-fallthrough=5 -Wrestrict"
fi
# gcc 8
diff --git a/config/sanitizer/LICENSE b/config/sanitizer/LICENSE
new file mode 100644
index 0000000..895657b
--- /dev/null
+++ b/config/sanitizer/LICENSE
@@ -0,0 +1,174 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability. \ No newline at end of file
diff --git a/config/sanitizer/README.md b/config/sanitizer/README.md
new file mode 100644
index 0000000..0d5fb6c
--- /dev/null
+++ b/config/sanitizer/README.md
@@ -0,0 +1,307 @@
+# CMake Scripts <!-- omit in toc -->
+
+[![pipeline status](https://git.stabletec.com/other/cmake-scripts/badges/master/pipeline.svg)](https://git.stabletec.com/other/cmake-scripts/commits/master)
+[![license](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://git.stabletec.com/other/cmake-scripts/blob/master/LICENSE)
+
+This is a collection of quite useful scripts that expand the possibilities for building software with CMake, by making some things easier and otherwise adding new build types
+
+- [C++ Standards `c++-standards.cmake`](#c-standards-c-standardscmake)
+- [Sanitizer Builds `sanitizers.cmake`](#sanitizer-builds-sanitizerscmake)
+- [Code Coverage `code-coverage.cmake`](#code-coverage-code-coveragecmake)
+ - [Added Targets](#added-targets)
+ - [Usage](#usage)
+ - [Example 1 - All targets instrumented](#example-1---all-targets-instrumented)
+ - [1a - Via global command](#1a---via-global-command)
+ - [1b - Via target commands](#1b---via-target-commands)
+ - [Example 2: Target instrumented, but with regex pattern of files to be excluded from report](#example-2-target-instrumented-but-with-regex-pattern-of-files-to-be-excluded-from-report)
+ - [Example 3: Target added to the 'ccov' and 'ccov-all' targets](#example-3-target-added-to-the-ccov-and-ccov-all-targets)
+- [Compiler Options `compiler-options.cmake`](#compiler-options-compiler-optionscmake)
+- [Dependency Graph `dependency-graph.cmake`](#dependency-graph-dependency-graphcmake)
+ - [Required Arguments](#required-arguments)
+ - [OUTPUT_TYPE *STR*](#output_type-str)
+ - [Optional Arguments](#optional-arguments)
+ - [ADD_TO_DEP_GRAPH](#add_to_dep_graph)
+ - [TARGET_NAME *STR*](#target_name-str)
+ - [OUTPUT_DIR *STR*](#output_dir-str)
+- [Doxygen `doxygen.cmake`](#doxygen-doxygencmake)
+ - [Optional Arguments](#optional-arguments-1)
+ - [ADD_TO_DOC](#add_to_doc)
+ - [INSTALLABLE](#installable)
+ - [PROCESS_DOXYFILE](#process_doxyfile)
+ - [TARGET_NAME *STR*](#target_name-str-1)
+ - [OUTPUT_DIR *STR*](#output_dir-str-1)
+ - [INSTALL_PATH *STR*](#install_path-str)
+ - [DOXYFILE_PATH *STR*](#doxyfile_path-str)
+- [Prepare the Catch Test Framework `prepare_catch.cmake`](#prepare-the-catch-test-framework-prepare_catchcmake)
+ - [Optional Arguments](#optional-arguments-2)
+ - [COMPILED_CATCH](#compiled_catch)
+ - [CATCH1](#catch1)
+ - [CLONE](#clone)
+- [Tools `tools.cmake`](#tools-toolscmake)
+ - [clang-tidy](#clang-tidy)
+ - [include-what-you-use](#include-what-you-use)
+ - [cppcheck](#cppcheck)
+- [Formatting `formatting.cmake`](#formatting-formattingcmake)
+ - [clang-format](#clang-format)
+ - [cmake-format](#cmake-format)
+
+## C++ Standards [`c++-standards.cmake`](c++-standards.cmake)
+
+Using the functions `cxx_11()`, `cxx_14()`, `cxx_17()` or `cxx_20()` this adds the appropriate flags for both unix and MSVC compilers, even for those before 3.11 with improper support.
+
+These obviously force the standard to be required, and also disables compiler-specific extensions, ie `--std=gnu++11`. This helps to prevent fragmenting the code base with items not available elsewhere, adhering to the agreed C++ standards only.
+
+## Sanitizer Builds [`sanitizers.cmake`](sanitizers.cmake)
+
+Sanitizers are tools that perform checks during a program’s runtime and returns issues, and as such, along with unit testing, code coverage and static analysis, is another tool to add to the programmers toolbox. And of course, like the previous tools, are tragically simple to add into any project using CMake, allowing any project and developer to quickly and easily use.
+
+A quick rundown of the tools available, and what they do:
+- [LeakSanitizer](https://clang.llvm.org/docs/LeakSanitizer.html) detects memory leaks, or issues where memory is allocated and never deallocated, causing programs to slowly consume more and more memory, eventually leading to a crash.
+- [AddressSanitizer](https://clang.llvm.org/docs/AddressSanitizer.html) is a fast memory error detector. It is useful for detecting most issues dealing with memory, such as:
+ - Out of bounds accesses to heap, stack, global
+ - Use after free
+ - Use after return
+ - Use after scope
+ - Double-free, invalid free
+ - Memory leaks (using LeakSanitizer)
+- [ThreadSanitizer](https://clang.llvm.org/docs/ThreadSanitizer.html) detects data races for multi-threaded code.
+- [UndefinedBehaviourSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) detects the use of various features of C/C++ that are explicitly listed as resulting in undefined behaviour. Most notably:
+ - Using misaligned or null pointer.
+ - Signed integer overflow
+ - Conversion to, from, or between floating-point types which would overflow the destination
+ - Division by zero
+ - Unreachable code
+- [MemorySanitizer](https://clang.llvm.org/docs/MemorySanitizer.html) detects uninitialized reads.
+
+These are used by declaring the `USE_SANITIZER` CMake variable as one of:
+- Address
+- Memory
+- MemoryWithOrigins
+- Undefined
+- Thread
+- Address;Undefined
+- Undefined;Address
+- Leak
+
+## Code Coverage [`code-coverage.cmake`](code-coverage.cmake)
+
+![Code Coverage Examples](img/code-cov.png)
+
+> In computer science, test coverage is a measure used to describe the degree to which the source code of a program is executed when a particular test suite runs. A program with high test coverage, measured as a percentage, has had more of its source code executed during testing, which suggests it has a lower chance of containing undetected software bugs compared to a program with low test coverage. Many different metrics can be used to calculate test coverage; some of the most basic are the percentage of program subroutines and the percentage of program statements called during execution of the test suite.
+>
+> [Wikipedia, Code Coverage](https://en.wikipedia.org/wiki/Code_coverage)
+
+Code coverage is the detailing of, during the execution of a binary, which regions, functions, or lines of code are *actually* executed. This can be used in a number of ways, from figuring out areas that automated testing is lacking or not touching, to giving a user an instrumented binary to determine which areas of code are used most/least to determine which areas to focus on. Although this does come with the caveat that coverage is no guarantee of good testing, just of what code has been.
+
+Coverage here is supported on both GCC and Clang. GCC requires the `lcov` program, and Clang requires `llvm-cov` and `llvm-profdata`, often provided with the llvm toolchain.
+
+To enable, turn on the `CODE_COVERAGE` variable.
+
+### Added Targets
+
+- GCOV/LCOV:
+ - ccov : Generates HTML code coverage report for every target added with 'AUTO' parameter.
+ - ccov-${TARNGET_NAME} : Generates HTML code coverage report for the associated named target.
+ - ccov-all : Generates HTML code coverage report, merging every target added with 'ALL' parameter into a single detailed report.
+ - ccov-all-capture : Generates an all-merged.info file, for use with coverage dashboards (e.g. codecov.io, coveralls).
+- LLVM-COV:
+ - ccov : Generates HTML code coverage report for every target added with 'AUTO' parameter.
+ - ccov-report : Generates HTML code coverage report for every target added with 'AUTO' parameter.
+ - ccov-${TARGET_NAME} : Generates HTML code coverage report.
+ - ccov-rpt-${TARGET_NAME} : Prints to command line summary per-file coverage information.
+ - ccov-show-${TARGET_NAME} : Prints to command line detailed per-line coverage information.
+ - ccov-all : Generates HTML code coverage report, merging every target added with 'ALL' parameter into a single detailed report.
+ - ccov-all-report : Prints summary per-file coverage information for every target added with ALL' parameter to the command line.
+
+### Usage
+
+To enable any code coverage instrumentation/targets, the single CMake option of `CODE_COVERAGE` needs to be set to 'ON', either by GUI, ccmake, or on the command line ie `-DCODE_COVERAGE=ON`.
+
+From this point, there are two primary methods for adding instrumentation to targets:
+1. A blanket instrumentation by calling `add_code_coverage()`, where all targets in that directory and all subdirectories are automatically instrumented.
+2. Per-target instrumentation by calling `target_code_coverage(<TARGET_NAME>)`, where the target is given and thus only that target is instrumented. This applies to both libraries and executables.
+
+To add coverage targets, such as calling `make ccov` to generate the actual coverage information for perusal or consumption, call `target_code_coverage(<TARGET_NAME>)` on an *executable* target.
+
+**NOTE:** For more options, please check the actual [`code-coverage.cmake`](code-coverage.cmake) file.
+
+#### Example 1 - All targets instrumented
+
+In this case, the coverage information reported will will be that of the `theLib` library target and `theExe` executable.
+
+##### 1a - Via global command
+
+```
+add_code_coverage() # Adds instrumentation to all targets
+
+add_library(theLib lib.cpp)
+
+add_executable(theExe main.cpp)
+target_link_libraries(theExe PRIVATE theLib)
+target_code_coverage(theExe) # As an executable target, adds the 'ccov-theExe' target (instrumentation already added via global anyways) for generating code coverage reports.
+```
+
+##### 1b - Via target commands
+
+```
+add_library(theLib lib.cpp)
+target_code_coverage(theLib) # As a library target, adds coverage instrumentation but no targets.
+
+add_executable(theExe main.cpp)
+target_link_libraries(theExe PRIVATE theLib)
+target_code_coverage(theExe) # As an executable target, adds the 'ccov-theExe' target and instrumentation for generating code coverage reports.
+```
+
+#### Example 2: Target instrumented, but with regex pattern of files to be excluded from report
+
+```
+add_executable(theExe main.cpp non_covered.cpp)
+target_code_coverage(theExe EXCLUDE non_covered.cpp) # As an executable target, the reports will exclude the non-covered.cpp file.
+```
+
+#### Example 3: Target added to the 'ccov' and 'ccov-all' targets
+
+```
+add_code_coverage_all_targets(EXCLUDE test/*) # Adds the 'ccov-all' target set and sets it to exclude all files in test/ folders.
+
+add_executable(theExe main.cpp non_covered.cpp)
+target_code_coverage(theExe AUTO ALL EXCLUDE non_covered.cpp test/*) # As an executable target, adds to the 'ccov' and ccov-all' targets, and the reports will exclude the non-covered.cpp file, and any files in a test/ folder.
+```
+
+## Compiler Options [`compiler-options.cmake`](compiler-options.cmake)
+
+Allows for easy use of some pre-made compiler options for the major compilers.
+
+Using `-DENABLE_ALL_WARNINGS=ON` will enable almost all of the warnings available for a compiler:
+
+| Compiler | Options |
+| :------- | :------------ |
+| MSVC | /W4 |
+| GCC | -Wall -Wextra |
+| Clang | -Wall -Wextra |
+
+Using `-DENABLE_EFFECTIVE_CXX=ON` adds the `-Weffc++` for both GCC and clang.
+
+Using `-DGENERATE_DEPENDENCY_DATA=ON` generates `.d` files along with regular object files on a per-source file basis on GCC/Clang compilers. These files contains the list of all header files used during compilation of that compilation unit.
+
+## Dependency Graph [`dependency-graph.cmake`](dependency-graph.cmake)
+
+CMake, with the dot application available, will build a visual representation of the library/executable dependencies, like so:
+![Dependency Graph](img/dp-graph.png)
+
+### Required Arguments
+
+#### OUTPUT_TYPE *STR*
+The type of output of `dot` to produce. Can be whatever `dot` itself supports (eg. png, ps, pdf).
+
+### Optional Arguments
+
+#### ADD_TO_DEP_GRAPH
+If specified, add this generated target to be a dependency of the more general `dep-graph` target.
+
+#### TARGET_NAME *STR*
+The name to give the doc target. (Default: doc-${PROJECT_NAME})
+
+#### OUTPUT_DIR *STR*
+The directory to place the generated output
+
+## Doxygen [`doxygen.cmake`](doxygen.cmake)
+
+Builds doxygen documentation with a default 'Doxyfile.in' or with a specified one, and can make the results installable (under the `doc` install target)
+
+This can only be used once per project, as each target generated is as `doc-${PROJECT_NAME}` unless TARGET_NAME is specified.
+
+### Optional Arguments
+
+#### ADD_TO_DOC
+If specified, adds this generated target to be a dependency of the more general `doc` target.
+
+#### INSTALLABLE
+Adds the generated documentation to the generic `install` target, under the `documentation` installation group.
+
+#### PROCESS_DOXYFILE
+If set, then will process the found Doxyfile through the CMAKE `configure_file` function for macro replacements before using it. (@ONLY)
+
+#### TARGET_NAME *STR*
+The name to give the doc target. (Default: doc-${PROJECT_NAME})
+
+#### OUTPUT_DIR *STR*
+The directory to place the generated output. (Default: ${CMAKE_CURRENT_BINARY_DIR}/doc)
+
+#### INSTALL_PATH *STR*
+The path to install the documenttation under. (if not specified, defaults to 'share/${PROJECT_NAME})
+
+#### DOXYFILE_PATH *STR*
+The given doxygen file to use/process. (Defaults to'${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile')
+
+## Prepare the Catch Test Framework [`prepare_catch.cmake`](prepare_catch.cmake)
+
+The included `prepare_catch` function contained within attempts to add the infrastructure necessary for automatically adding C/C++ tests using the Catch2 library, including either an interface or pre-compiled 'catch' target library.
+
+It first attempts to find the header on the local machine, and failing that, clones the single header variant for use. It does make the determination between pre-C++11 and will use Catch1.X rather than Catch2 (when cloned), automatically or forced.. Adds a subdirectory of tests/ if it exists from the macro's calling location.
+
+### Optional Arguments
+
+#### COMPILED_CATCH
+If this option is specified, then generates the 'catch' target as a library with catch already pre-compiled as part of the library. Otherwise acts just an interface library for the header location.
+
+#### CATCH1
+Force the use of Catch1.X, rather than auto-detecting the C++ version in use.
+
+#### CLONE
+Force cloning of Catch, rather than attempting to use a locally-found variant.
+
+## Tools [`tools.cmake`](tools.cmake)
+
+### clang-tidy
+
+> clang-tidy is a clang-based C++ “linter” tool. Its purpose is to provide an extensible framework for diagnosing and fixing typical programming errors, like style violations, interface misuse, or bugs that can be deduced via static analysis. clang-tidy is modular and provides a convenient interface for writing new checks.
+>
+> [clang-tidy page](https://clang.llvm.org/extra/clang-tidy/)
+
+When detected, [clang-tidy](https://clang.llvm.org/extra/clang-tidy/) can be enabled by using the option of `-DCLANG_TIDY=ON`, as it is disabled by default.
+
+To use, add the `clang_tidy()` function, with the arguments being the options to pass to the clang tidy program, such as '-checks=*'.
+
+### include-what-you-use
+
+This tool helps to organize headers for all files encompass all items being used in that file, without accidentally relying upon headers deep down a chain of other headers. This is disabled by default, and can be enabled via have the program installed and adding `-DIWYU=ON`.
+
+To use, add the `include_what_you_use()` function, with the arguments being the options to pass to the program.
+
+### cppcheck
+
+This tool is another static analyzer in the vein of clang-tidy, which focuses on having no false positives. This is by default disabled, and can be enabled via have the program installed and adding `-DCPPCHECK=ON`.
+
+To use, add the `cppcheck()` function, with the arguments being the options to pass to the program.
+
+## Formatting [`formatting.cmake`](formatting.cmake)
+
+### clang-format
+
+Allows to automatically perform code formatting using the clang-format program, by calling an easy-to-use target ala `make format`. It requires a target name, and the list of files to format. As well, if the target name is the name of another target, then all files associated with that target will be added, and the target name changed to be `format_<TARGET>`. As well, any targets otherwise listed with the files will also have their files imported for formatting.
+
+```
+file(GLOB_RECURSE ALL_CODE_FILES
+ ${PROJECT_SOURCE_DIR}/src/*.[ch]pp
+ ${PROJECT_SOURCE_DIR}/src/*.[ch]
+ ${PROJECT_SOURCE_DIR}/include/*.[h]pp
+ ${PROJECT_SOURCE_DIR}/include/*.[h]
+ ${PROJECT_SOURCE_DIR}/example/*.[ch]pp
+ ${PROJECT_SOURCE_DIR}/example/*.[ch]
+)
+
+clang_format(TARGET_NAME ${ALL_CODE_FILES})
+```
+
+### cmake-format
+
+Similar to the clang-format above, creates a target `cmake-format` when the `cmake_format(<FILES>)` function is defined in CMake scripts, and any <FILES> passed in will be formatted by the cmake-format program, if it is found.
+
+```
+file(GLOB_RECURSE CMAKE_FILES
+ CMakeLists.txt
+)
+
+cmake_format(TARGET_NAME ${CMAKE_FILES})
+``` \ No newline at end of file
diff --git a/config/sanitizer/code-coverage.cmake b/config/sanitizer/code-coverage.cmake
new file mode 100644
index 0000000..8d765f7
--- /dev/null
+++ b/config/sanitizer/code-coverage.cmake
@@ -0,0 +1,536 @@
+#
+# Copyright (C) 2018 by George Cave - gcave@stablecoder.ca
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+# USAGE: To enable any code coverage instrumentation/targets, the single CMake
+# option of `CODE_COVERAGE` needs to be set to 'ON', either by GUI, ccmake, or
+# on the command line.
+#
+# From this point, there are two primary methods for adding instrumentation to
+# targets: 1 - A blanket instrumentation by calling `add_code_coverage()`, where
+# all targets in that directory and all subdirectories are automatically
+# instrumented. 2 - Per-target instrumentation by calling
+# `target_code_coverage(<TARGET_NAME>)`, where the target is given and thus only
+# that target is instrumented. This applies to both libraries and executables.
+#
+# To add coverage targets, such as calling `make ccov` to generate the actual
+# coverage information for perusal or consumption, call
+# `target_code_coverage(<TARGET_NAME>)` on an *executable* target.
+#
+# Example 1: All targets instrumented
+#
+# In this case, the coverage information reported will will be that of the
+# `theLib` library target and `theExe` executable.
+#
+# 1a: Via global command
+#
+# ~~~
+# add_code_coverage() # Adds instrumentation to all targets
+#
+# add_library(theLib lib.cpp)
+#
+# add_executable(theExe main.cpp)
+# target_link_libraries(theExe PRIVATE theLib)
+# target_code_coverage(theExe) # As an executable target, adds the 'ccov-theExe' target (instrumentation already added via global anyways) for generating code coverage reports.
+# ~~~
+#
+# 1b: Via target commands
+#
+# ~~~
+# add_library(theLib lib.cpp)
+# target_code_coverage(theLib) # As a library target, adds coverage instrumentation but no targets.
+#
+# add_executable(theExe main.cpp)
+# target_link_libraries(theExe PRIVATE theLib)
+# target_code_coverage(theExe) # As an executable target, adds the 'ccov-theExe' target and instrumentation for generating code coverage reports.
+# ~~~
+#
+# Example 2: Target instrumented, but with regex pattern of files to be excluded
+# from report
+#
+# ~~~
+# add_executable(theExe main.cpp non_covered.cpp)
+# target_code_coverage(theExe EXCLUDE non_covered.cpp test/*) # As an executable target, the reports will exclude the non-covered.cpp file, and any files in a test/ folder.
+# ~~~
+#
+# Example 3: Target added to the 'ccov' and 'ccov-all' targets
+#
+# ~~~
+# add_code_coverage_all_targets(EXCLUDE test/*) # Adds the 'ccov-all' target set and sets it to exclude all files in test/ folders.
+#
+# add_executable(theExe main.cpp non_covered.cpp)
+# target_code_coverage(theExe AUTO ALL EXCLUDE non_covered.cpp test/*) # As an executable target, adds to the 'ccov' and ccov-all' targets, and the reports will exclude the non-covered.cpp file, and any files in a test/ folder.
+# ~~~
+
+# Options
+option(
+ CODE_COVERAGE
+ "Builds targets with code coverage instrumentation. (Requires GCC or Clang)"
+ OFF)
+
+# Programs
+find_program(LLVM_COV_PATH llvm-cov)
+find_program(LLVM_PROFDATA_PATH llvm-profdata)
+find_program(LCOV_PATH lcov)
+find_program(GENHTML_PATH genhtml)
+
+# Variables
+set(CMAKE_COVERAGE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/ccov)
+
+# Common initialization/checks
+if(CODE_COVERAGE AND NOT CODE_COVERAGE_ADDED)
+ set(CODE_COVERAGE_ADDED ON)
+
+ # Common Targets
+ add_custom_target(
+ ccov-preprocessing
+ COMMAND ${CMAKE_COMMAND} -E make_directory
+ ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}
+ DEPENDS ccov-clean)
+
+ if(CMAKE_C_COMPILER_ID MATCHES "[Cc]lang"
+ OR CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang")
+ # Messages
+ message(STATUS "Building with llvm Code Coverage Tools")
+
+ if(NOT LLVM_COV_PATH)
+ message(FATAL_ERROR "llvm-cov not found! Aborting.")
+ else()
+ # Version number checking for 'EXCLUDE' compatibility
+ execute_process(COMMAND ${LLVM_COV_PATH} --version
+ OUTPUT_VARIABLE LLVM_COV_VERSION_CALL_OUTPUT)
+ string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" LLVM_COV_VERSION
+ ${LLVM_COV_VERSION_CALL_OUTPUT})
+
+ if(LLVM_COV_VERSION VERSION_LESS "7.0.0")
+ message(
+ WARNING
+ "target_code_coverage()/add_code_coverage_all_targets() 'EXCLUDE' option only available on llvm-cov >= 7.0.0"
+ )
+ endif()
+ endif()
+
+ # Targets
+ add_custom_target(
+ ccov-clean
+ COMMAND rm -f ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list
+ COMMAND rm -f ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/profraw.list)
+
+ # Used to get the shared object file list before doing the main all-
+ # processing
+ add_custom_target(
+ ccov-libs
+ COMMAND ;
+ COMMENT "libs ready for coverage report.")
+
+ elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")
+ # Messages
+ message(STATUS "Building with lcov Code Coverage Tools")
+
+ if(CMAKE_BUILD_TYPE)
+ string(TOUPPER ${CMAKE_BUILD_TYPE} upper_build_type)
+ if(NOT ${upper_build_type} STREQUAL "DEBUG")
+ message(
+ WARNING
+ "Code coverage results with an optimized (non-Debug) build may be misleading"
+ )
+ endif()
+ else()
+ message(
+ WARNING
+ "Code coverage results with an optimized (non-Debug) build may be misleading"
+ )
+ endif()
+ if(NOT LCOV_PATH)
+ message(FATAL_ERROR "lcov not found! Aborting...")
+ endif()
+ if(NOT GENHTML_PATH)
+ message(FATAL_ERROR "genhtml not found! Aborting...")
+ endif()
+
+ # Targets
+ add_custom_target(ccov-clean COMMAND ${LCOV_PATH} --directory
+ ${CMAKE_BINARY_DIR} --zerocounters)
+
+ else()
+ set(CODE_COVERAGE_ADDED OFF)
+ message(STATUS "Code coverage requires Clang or GCC.(${CMAKE_C_COMPILER_ID})")
+ endif()
+endif()
+
+# Adds code coverage instrumentation to a library, or instrumentation/targets
+# for an executable target.
+# ~~~
+# EXECUTABLE ADDED TARGETS:
+# GCOV/LCOV:
+# ccov : Generates HTML code coverage report for every target added with 'AUTO' parameter.
+# ccov-${TARGET_NAME} : Generates HTML code coverage report for the associated named target.
+# ccov-all : Generates HTML code coverage report, merging every target added with 'ALL' parameter into a single detailed report.
+#
+# LLVM-COV:
+# ccov : Generates HTML code coverage report for every target added with 'AUTO' parameter.
+# ccov-report : Generates HTML code coverage report for every target added with 'AUTO' parameter.
+# ccov-${TARGET_NAME} : Generates HTML code coverage report.
+# ccov-report-${TARGET_NAME} : Prints to command line summary per-file coverage information.
+# ccov-show-${TARGET_NAME} : Prints to command line detailed per-line coverage information.
+# ccov-all : Generates HTML code coverage report, merging every target added with 'ALL' parameter into a single detailed report.
+# ccov-all-report : Prints summary per-file coverage information for every target added with ALL' parameter to the command line.
+#
+# Required:
+# TARGET_NAME - Name of the target to generate code coverage for.
+# Optional:
+# AUTO - Adds the target to the 'ccov' target so that it can be run in a batch with others easily. Effective on executable targets.
+# ALL - Adds the target to the 'ccov-all' and 'ccov-all-report' targets, which merge several executable targets coverage data to a single report. Effective on executable targets.
+# EXTERNAL - For GCC's lcov, allows the profiling of 'external' files from the processing directory
+# EXCLUDE <REGEX_PATTERNS> - Excludes files of the patterns provided from coverage. **These do not copy to the 'all' targets.**
+# OBJECTS <TARGETS> - For executables ONLY, if the provided targets are shared libraries, adds coverage information to the output
+# ~~~
+function(target_code_coverage TARGET_NAME)
+ # Argument parsing
+ set(options AUTO ALL EXTERNAL)
+ set(multi_value_keywords EXCLUDE OBJECTS)
+ cmake_parse_arguments(target_code_coverage "${options}" ""
+ "${multi_value_keywords}" ${ARGN})
+
+ if(CODE_COVERAGE)
+
+ # Add code coverage instrumentation to the target's linker command
+ if(CMAKE_C_COMPILER_ID MATCHES "[Cc]lang"
+ OR CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang")
+ target_compile_options(${TARGET_NAME} PRIVATE -fprofile-instr-generate
+ -fcoverage-mapping)
+ set_property(
+ TARGET ${TARGET_NAME}
+ APPEND_STRING
+ PROPERTY LINK_FLAGS "-fprofile-instr-generate ")
+ set_property(
+ TARGET ${TARGET_NAME}
+ APPEND_STRING
+ PROPERTY LINK_FLAGS "-fcoverage-mapping ")
+ elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")
+ target_compile_options(${TARGET_NAME} PRIVATE -fprofile-arcs
+ -ftest-coverage)
+ target_link_libraries(${TARGET_NAME} PRIVATE gcov)
+ endif()
+
+ # Targets
+ get_target_property(target_type ${TARGET_NAME} TYPE)
+
+ # Add shared library to processing for 'all' targets
+ if(target_type STREQUAL "SHARED_LIBRARY" AND target_code_coverage_ALL)
+ if(CMAKE_C_COMPILER_ID MATCHES "[Cc]lang"
+ OR CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang")
+ add_custom_target(
+ ccov-run-${TARGET_NAME}
+ COMMAND echo "-object=$<TARGET_FILE:${TARGET_NAME}>" >>
+ ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list
+ DEPENDS ccov-preprocessing ${TARGET_NAME})
+
+ if(NOT TARGET ccov-libs)
+ message(
+ FATAL_ERROR
+ "Calling target_code_coverage with 'ALL' must be after a call to 'add_code_coverage_all_targets'."
+ )
+ endif()
+
+ add_dependencies(ccov-libs ccov-run-${TARGET_NAME})
+ endif()
+ endif()
+
+ # For executables add targets to run and produce output
+ if(target_type STREQUAL "EXECUTABLE")
+ if(CMAKE_C_COMPILER_ID MATCHES "[Cc]lang"
+ OR CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?Cc]lang")
+
+ # If there are shared objects to also work with, generate the string to
+ # add them here
+ foreach(SO_TARGET ${target_code_coverage_OBJECTS})
+ # Check to see if the target is a shared object
+ if(TARGET ${SO_TARGET})
+ get_target_property(SO_TARGET_TYPE ${SO_TARGET} TYPE)
+ if(${SO_TARGET_TYPE} STREQUAL "SHARED_LIBRARY")
+ set(SO_OBJECTS ${SO_OBJECTS} -object=$<TARGET_FILE:${SO_TARGET}>)
+ endif()
+ endif()
+ endforeach()
+
+ # Run the executable, generating raw profile data
+ add_custom_target(
+ ccov-run-${TARGET_NAME}
+ COMMAND LLVM_PROFILE_FILE=${TARGET_NAME}.profraw
+ $<TARGET_FILE:${TARGET_NAME}>
+ COMMAND echo "-object=$<TARGET_FILE:${TARGET_NAME}>" >>
+ ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list
+ COMMAND echo "${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}.profraw " >>
+ ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/profraw.list
+ DEPENDS ccov-preprocessing ccov-libs ${TARGET_NAME})
+
+ # Merge the generated profile data so llvm-cov can process it
+ add_custom_target(
+ ccov-processing-${TARGET_NAME}
+ COMMAND ${LLVM_PROFDATA_PATH} merge -sparse ${TARGET_NAME}.profraw -o
+ ${TARGET_NAME}.profdata
+ DEPENDS ccov-run-${TARGET_NAME})
+
+ # Ignore regex only works on LLVM >= 7
+ if(LLVM_COV_VERSION VERSION_GREATER_EQUAL "7.0.0")
+ foreach(EXCLUDE_ITEM ${target_code_coverage_EXCLUDE})
+ set(EXCLUDE_REGEX ${EXCLUDE_REGEX}
+ -ignore-filename-regex='${EXCLUDE_ITEM}')
+ endforeach()
+ endif()
+
+ # Print out details of the coverage information to the command line
+ add_custom_target(
+ ccov-show-${TARGET_NAME}
+ COMMAND
+ ${LLVM_COV_PATH} show $<TARGET_FILE:${TARGET_NAME}> ${SO_OBJECTS}
+ -instr-profile=${TARGET_NAME}.profdata -show-line-counts-or-regions
+ ${EXCLUDE_REGEX}
+ DEPENDS ccov-processing-${TARGET_NAME})
+
+ # Print out a summary of the coverage information to the command line
+ add_custom_target(
+ ccov-report-${TARGET_NAME}
+ COMMAND ${LLVM_COV_PATH} report $<TARGET_FILE:${TARGET_NAME}>
+ ${SO_OBJECTS} -instr-profile=${TARGET_NAME}.profdata
+ ${EXCLUDE_REGEX}
+ DEPENDS ccov-processing-${TARGET_NAME})
+
+ # Generates HTML output of the coverage information for perusal
+ add_custom_target(
+ ccov-${TARGET_NAME}
+ COMMAND
+ ${LLVM_COV_PATH} show $<TARGET_FILE:${TARGET_NAME}> ${SO_OBJECTS}
+ -instr-profile=${TARGET_NAME}.profdata -show-line-counts-or-regions
+ -output-dir=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/${TARGET_NAME}
+ -format="html" ${EXCLUDE_REGEX}
+ DEPENDS ccov-processing-${TARGET_NAME})
+
+ elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")
+ set(COVERAGE_INFO
+ "${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/${TARGET_NAME}.info")
+
+ # Run the executable, generating coverage information
+ add_custom_target(
+ ccov-run-${TARGET_NAME}
+ COMMAND $<TARGET_FILE:${TARGET_NAME}>
+ DEPENDS ccov-preprocessing ${TARGET_NAME})
+
+ # Generate exclusion string for use
+ foreach(EXCLUDE_ITEM ${target_code_coverage_EXCLUDE})
+ set(EXCLUDE_REGEX ${EXCLUDE_REGEX} --remove ${COVERAGE_INFO}
+ '${EXCLUDE_ITEM}')
+ endforeach()
+
+ if(EXCLUDE_REGEX)
+ set(EXCLUDE_COMMAND ${LCOV_PATH} ${EXCLUDE_REGEX} --output-file
+ ${COVERAGE_INFO})
+ else()
+ set(EXCLUDE_COMMAND ;)
+ endif()
+
+ if(NOT ${target_code_coverage_EXTERNAL})
+ set(EXTERNAL_OPTION --no-external)
+ endif()
+
+ # Capture coverage data
+ add_custom_target(
+ ccov-capture-${TARGET_NAME}
+ COMMAND ${CMAKE_COMMAND} -E remove ${COVERAGE_INFO}
+ COMMAND ${LCOV_PATH} --directory ${CMAKE_BINARY_DIR} --zerocounters
+ COMMAND $<TARGET_FILE:${TARGET_NAME}>
+ COMMAND
+ ${LCOV_PATH} --directory ${CMAKE_BINARY_DIR} --base-directory
+ ${CMAKE_SOURCE_DIR} --capture ${EXTERNAL_OPTION} --output-file
+ ${COVERAGE_INFO}
+ COMMAND ${EXCLUDE_COMMAND}
+ DEPENDS ccov-preprocessing ${TARGET_NAME})
+
+ # Generates HTML output of the coverage information for perusal
+ add_custom_target(
+ ccov-${TARGET_NAME}
+ COMMAND ${GENHTML_PATH} -o
+ ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/${TARGET_NAME}
+ ${COVERAGE_INFO}
+ DEPENDS ccov-capture-${TARGET_NAME})
+ endif()
+
+ add_custom_command(
+ TARGET ccov-${TARGET_NAME}
+ POST_BUILD
+ COMMAND ;
+ COMMENT
+ "Open ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/${TARGET_NAME}/index.html in your browser to view the coverage report."
+ )
+
+ # AUTO
+ if(target_code_coverage_AUTO)
+ if(NOT TARGET ccov)
+ add_custom_target(ccov)
+ endif()
+ add_dependencies(ccov ccov-${TARGET_NAME})
+
+ if(NOT CMAKE_COMPILER_IS_GNUCXX)
+ if(NOT TARGET ccov-report)
+ add_custom_target(ccov-report)
+ endif()
+ add_dependencies(ccov-report ccov-report-${TARGET_NAME})
+ endif()
+ endif()
+
+ # ALL
+ if(target_code_coverage_ALL)
+ if(NOT TARGET ccov-all-processing)
+ message(
+ FATAL_ERROR
+ "Calling target_code_coverage with 'ALL' must be after a call to 'add_code_coverage_all_targets'."
+ )
+ endif()
+
+ add_dependencies(ccov-all-processing ccov-run-${TARGET_NAME})
+ endif()
+ endif()
+ endif()
+endfunction()
+
+# Adds code coverage instrumentation to all targets in the current directory and
+# any subdirectories. To add coverage instrumentation to only specific targets,
+# use `target_code_coverage`.
+function(add_code_coverage)
+ if(CMAKE_C_COMPILER_ID MATCHES "[Cc]lang"
+ OR CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang")
+ add_compile_options(-fprofile-instr-generate -fcoverage-mapping)
+ add_link_options(-fprofile-instr-generate -fcoverage-mapping)
+ elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")
+ add_compile_options(-fprofile-arcs -ftest-coverage)
+ link_libraries(gcov)
+ endif()
+endfunction()
+
+# Adds the 'ccov-all' type targets that calls all targets added via
+# `target_code_coverage` with the `ALL` parameter, but merges all the coverage
+# data from them into a single large report instead of the numerous smaller
+# reports. Also adds the ccov-all-capture Generates an all-merged.info file, for
+# use with coverage dashboards (e.g. codecov.io, coveralls).
+# ~~~
+# Optional:
+# EXCLUDE <REGEX_PATTERNS> - Excludes files of the regex patterns provided from coverage.
+# ~~~
+function(add_code_coverage_all_targets)
+ # Argument parsing
+ set(multi_value_keywords EXCLUDE)
+ cmake_parse_arguments(add_code_coverage_all_targets "" ""
+ "${multi_value_keywords}" ${ARGN})
+
+ if(CODE_COVERAGE)
+ if(CMAKE_C_COMPILER_ID MATCHES "[Cc]lang"
+ OR CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang")
+
+ # Merge the profile data for all of the run executables
+ add_custom_target(
+ ccov-all-processing
+ COMMAND
+ ${LLVM_PROFDATA_PATH} merge -o
+ ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.profdata -sparse `cat
+ ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/profraw.list`)
+
+ # Regex exclude only available for LLVM >= 7
+ if(LLVM_COV_VERSION VERSION_GREATER_EQUAL "7.0.0")
+ foreach(EXCLUDE_ITEM ${add_code_coverage_all_targets_EXCLUDE})
+ set(EXCLUDE_REGEX ${EXCLUDE_REGEX}
+ -ignore-filename-regex='${EXCLUDE_ITEM}')
+ endforeach()
+ endif()
+
+ # Print summary of the code coverage information to the command line
+ add_custom_target(
+ ccov-all-report
+ COMMAND
+ ${LLVM_COV_PATH} report `cat
+ ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list`
+ -instr-profile=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.profdata
+ ${EXCLUDE_REGEX}
+ DEPENDS ccov-all-processing)
+
+ # Export coverage information so continuous integration tools (e.g.
+ # Jenkins) can consume it
+ add_custom_target(
+ ccov-all-export
+ COMMAND
+ ${LLVM_COV_PATH} export `cat
+ ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list`
+ -instr-profile=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.profdata
+ -format="text" ${EXCLUDE_REGEX} >
+ ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/coverage.json
+ DEPENDS ccov-all-processing)
+
+ # Generate HTML output of all added targets for perusal
+ add_custom_target(
+ ccov-all
+ COMMAND
+ ${LLVM_COV_PATH} show `cat
+ ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list`
+ -instr-profile=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.profdata
+ -show-line-counts-or-regions
+ -output-dir=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged
+ -format="html" ${EXCLUDE_REGEX}
+ DEPENDS ccov-all-processing)
+
+ elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")
+ set(COVERAGE_INFO "${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.info")
+
+ # Nothing required for gcov
+ add_custom_target(ccov-all-processing COMMAND ;)
+
+ # Exclusion regex string creation
+ foreach(EXCLUDE_ITEM ${add_code_coverage_all_targets_EXCLUDE})
+ set(EXCLUDE_REGEX ${EXCLUDE_REGEX} --remove ${COVERAGE_INFO}
+ '${EXCLUDE_ITEM}')
+ endforeach()
+
+ if(EXCLUDE_REGEX)
+ set(EXCLUDE_COMMAND ${LCOV_PATH} ${EXCLUDE_REGEX} --output-file
+ ${COVERAGE_INFO})
+ else()
+ set(EXCLUDE_COMMAND ;)
+ endif()
+
+ # Capture coverage data
+ add_custom_target(
+ ccov-all-capture
+ COMMAND ${CMAKE_COMMAND} -E remove ${COVERAGE_INFO}
+ COMMAND ${LCOV_PATH} --directory ${CMAKE_BINARY_DIR} --capture
+ --output-file ${COVERAGE_INFO}
+ COMMAND ${EXCLUDE_COMMAND}
+ DEPENDS ccov-all-processing)
+
+ # Generates HTML output of all targets for perusal
+ add_custom_target(
+ ccov-all
+ COMMAND ${GENHTML_PATH} -o ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged
+ ${COVERAGE_INFO}
+ DEPENDS ccov-all-capture)
+
+ endif()
+
+ add_custom_command(
+ TARGET ccov-all
+ POST_BUILD
+ COMMAND ;
+ COMMENT
+ "Open ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged/index.html in your browser to view the coverage report."
+ )
+ endif()
+endfunction()
diff --git a/config/sanitizer/sanitizers.cmake b/config/sanitizer/sanitizers.cmake
new file mode 100644
index 0000000..7a6c195
--- /dev/null
+++ b/config/sanitizer/sanitizers.cmake
@@ -0,0 +1,96 @@
+#
+# Copyright (C) 2018 by George Cave - gcave@stablecoder.ca
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+set(USE_SANITIZER
+ ""
+ CACHE
+ STRING
+ "Compile with a sanitizer. Options are: Address, Memory, MemoryWithOrigins, Undefined, Thread, Leak, 'Address;Undefined'"
+)
+
+function(append value)
+ foreach(variable ${ARGN})
+ set(${variable}
+ "${${variable}} ${value}"
+ PARENT_SCOPE)
+ endforeach(variable)
+endfunction()
+
+if(USE_SANITIZER)
+ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+
+ append("-fno-omit-frame-pointer" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
+
+ if(UNIX)
+
+ if(uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG")
+ append("-O1" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
+ endif()
+
+ if(USE_SANITIZER MATCHES "([Aa]ddress);([Uu]ndefined)"
+ OR USE_SANITIZER MATCHES "([Uu]ndefined);([Aa]ddress)")
+ message(STATUS "Building with Address, Undefined sanitizers")
+ append("-fsanitize=address,undefined" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
+ set(MEMCHECK_TYPE AddressSanitizer)
+ elseif(USE_SANITIZER MATCHES "([Aa]ddress)")
+ # Optional: -fno-optimize-sibling-calls -fsanitize-address-use-after-scope
+ message(STATUS "Building with Address sanitizer")
+ append("-fsanitize=address" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
+ set(MEMCHECK_TYPE AddressSanitizer)
+ elseif(USE_SANITIZER MATCHES "([Mm]emory([Ww]ith[Oo]rigins)?)")
+ # Optional: -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2
+ append("-fsanitize=memory" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
+ if(USE_SANITIZER MATCHES "([Mm]emory[Ww]ith[Oo]rigins)")
+ message(STATUS "Building with MemoryWithOrigins sanitizer")
+ append("-fsanitize-memory-track-origins" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
+ else()
+ message(STATUS "Building with Memory sanitizer")
+ endif()
+ set(MEMCHECK_TYPE MemorySanitizer)
+ elseif(USE_SANITIZER MATCHES "([Uu]ndefined)")
+ message(STATUS "Building with Undefined sanitizer")
+ append("-fsanitize=undefined" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
+ if(EXISTS "${BLACKLIST_FILE}")
+ append("-fsanitize-blacklist=${BLACKLIST_FILE}" CMAKE_C_FLAGS
+ CMAKE_CXX_FLAGS)
+ endif()
+ set(MEMCHECK_TYPE UndefinedBehaviorSanitizer)
+ elseif(USE_SANITIZER MATCHES "([Tt]hread)")
+ message(STATUS "Building with Thread sanitizer")
+ append("-fsanitize=thread" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
+ set(MEMCHECK_TYPE ThreadSanitizer)
+ elseif(USE_SANITIZER MATCHES "([Ll]eak)")
+ message(STATUS "Building with Leak sanitizer")
+ append("-fsanitize=leak" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
+ set(MEMCHECK_TYPE LeakSanitizer)
+ else()
+ message(
+ FATAL_ERROR "Unsupported value of USE_SANITIZER: ${USE_SANITIZER}")
+ endif()
+ elseif(MSVC)
+ if(USE_SANITIZER MATCHES "([Aa]ddress)")
+ message(STATUS "Building with Address sanitizer")
+ append("-fsanitize=address" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
+ else()
+ message(
+ FATAL_ERROR
+ "This sanitizer not yet supported in the MSVC environment: ${USE_SANITIZER}"
+ )
+ endif()
+ else()
+ message(FATAL_ERROR "USE_SANITIZER is not supported on this platform.")
+ endif()
+
+endif()
diff --git a/config/sanitizer/tools.cmake b/config/sanitizer/tools.cmake
new file mode 100644
index 0000000..a44022f
--- /dev/null
+++ b/config/sanitizer/tools.cmake
@@ -0,0 +1,111 @@
+#
+# Copyright (C) 2018 by George Cave - gcave@stablecoder.ca
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+option(CLANG_TIDY "Turns on clang-tidy processing if it is found." OFF)
+option(IWYU "Turns on include-what-you-use processing if it is found." OFF)
+option(CPPCHECK "Turns on cppcheck processing if it is found." OFF)
+
+# Adds clang-tidy checks to the compilation, with the given arguments being used
+# as the options set.
+macro(clang_tidy)
+ if(CLANG_TIDY AND CLANG_TIDY_EXE)
+ set(CMAKE_CXX_CLANG_TIDY ${CLANG_TIDY_EXE} ${ARGN})
+ endif()
+endmacro()
+
+# Adds include_what_you_use to the compilation, with the given arguments being
+# used as the options set.
+macro(include_what_you_use)
+ if(IWYU AND IWYU_EXE)
+ set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "${IWYU_EXE};${IWYU_STRING}")
+ endif()
+endmacro()
+
+# Adds cppcheck to the compilation, with the given arguments being used as the
+# options set.
+macro(cppcheck)
+ if(CPPCHECK AND CPPCHECK_EXE)
+ set(CMAKE_CXX_CPPCHECK "${CPPCHECK_EXE};${CPPCHECK_STRING}")
+ endif()
+endmacro()
+
+find_program(CLANG_TIDY_EXE NAMES "clang-tidy")
+if(CLANG_TIDY_EXE)
+ message(STATUS "clang-tidy found: ${CLANG_TIDY_EXE}")
+ if(NOT CLANG_TIDY)
+ message(STATUS "clang-tidy NOT ENABLED via 'CLANG_TIDY' variable!")
+ set(CMAKE_CXX_CLANG_TIDY
+ ""
+ CACHE STRING "" FORCE) # delete it
+ endif()
+elseif(CLANG_TIDY)
+ message(SEND_ERROR "Cannot enable clang-tidy, as executable not found!")
+ set(CMAKE_CXX_CLANG_TIDY
+ ""
+ CACHE STRING "" FORCE) # delete it
+else()
+ message(STATUS "clang-tidy not found!")
+ set(CMAKE_CXX_CLANG_TIDY
+ ""
+ CACHE STRING "" FORCE) # delete it
+endif()
+
+find_program(IWYU_EXE NAMES "include-what-you-use")
+if(IWYU_EXE)
+ message(STATUS "include-what-you-use found: ${IWYU_EXE}")
+ if(NOT IWYU)
+ message(STATUS "include-what-you-use NOT ENABLED via 'IWYU' variable!")
+ set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE
+ ""
+ CACHE STRING "" FORCE) # delete it
+ endif()
+elseif(IWYU)
+ message(
+ SEND_ERROR "Cannot enable include-what-you-use, as executable not found!")
+ set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE
+ ""
+ CACHE STRING "" FORCE) # delete it
+else()
+ message(STATUS "include-what-you-use not found!")
+ set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE
+ ""
+ CACHE STRING "" FORCE) # delete it
+endif()
+
+find_program(CPPCHECK_EXE NAMES "cppcheck")
+if(CPPCHECK_EXE)
+ message(STATUS "cppcheck found: ${CPPCHECK_EXE}")
+ if(CPPECHECK)
+ set(CMAKE_CXX_CPPCHECK
+ "${CPPCHECK_EXE};--enable=warning,performance,portability,missingInclude;--template=\"[{severity}][{id}] {message} {callstack} \(On {file}:{line}\)\";--suppress=missingIncludeSystem;--quiet;--verbose;--force"
+ )
+ endif()
+ if(NOT CPPCHECK)
+ message(STATUS "cppcheck NOT ENABLED via 'CPPCHECK' variable!")
+ set(CMAKE_CXX_CPPCHECK
+ ""
+ CACHE STRING "" FORCE) # delete it
+ endif()
+elseif(CPPCHECK)
+ message(SEND_ERROR "Cannot enable cppcheck, as executable not found!")
+ set(CMAKE_CXX_CPPCHECK
+ ""
+ CACHE STRING "" FORCE) # delete it
+else()
+ message(STATUS "cppcheck not found!")
+ set(CMAKE_CXX_CPPCHECK
+ ""
+ CACHE STRING "" FORCE) # delete it
+endif()