Browse Source

Merge commit '2ef7a8a47805c7165ae5a47b75e634ed35de59dd' as 'cmake'

master
Dominik Meyer 4 months ago
parent
commit
69c22b1a3a
19 changed files with 1462 additions and 0 deletions
  1. +25
    -0
      cmake/Jenkinsfile
  2. +1
    -0
      cmake/Modules/CheckParent.cmake
  3. +76
    -0
      cmake/Modules/FindGMP.cmake
  4. +25
    -0
      cmake/Modules/FindValgrind.cmake
  5. +47
    -0
      cmake/Modules/GenerateCccc.cmake
  6. +74
    -0
      cmake/Modules/GenerateCppCheck.cmake
  7. +23
    -0
      cmake/Modules/ProcessDOXYGEN.cmake
  8. +17
    -0
      cmake/Modules/ProcessGIT.cmake
  9. +22
    -0
      cmake/Modules/add_my_test.cmake
  10. +66
    -0
      cmake/Modules/c++-standards.cmake
  11. +588
    -0
      cmake/Modules/code-coverage.cmake
  12. +99
    -0
      cmake/Modules/codecheck.cmake
  13. +46
    -0
      cmake/Modules/compiler-options.cmake
  14. +13
    -0
      cmake/Modules/defaultIncludes.cmake
  15. +11
    -0
      cmake/Modules/defaultOptions.cmake
  16. +132
    -0
      cmake/Modules/doxygen.cmake
  17. +87
    -0
      cmake/Modules/sanitizers.cmake
  18. +94
    -0
      cmake/Modules/tools.cmake
  19. +16
    -0
      cmake/Toolchains/Toolchain-mingw64.cmake

+ 25
- 0
cmake/Jenkinsfile View File

@@ -0,0 +1,25 @@
pipeline {
agent none

options {
// Only keep the 1 most recent builds
buildDiscarder(logRotator(numToKeepStr: "1"))
}


stages {

stage("Build")
{
agent {
label 'c++'
}

steps {
echo "build"
}

}

}
}

+ 1
- 0
cmake/Modules/CheckParent.cmake View File

@@ -0,0 +1 @@
get_directory_property(hasParent PARENT_DIRECTORY)

+ 76
- 0
cmake/Modules/FindGMP.cmake View File

@@ -0,0 +1,76 @@
# Try to find the GMP library
# https://gmplib.org/
#
# This module supports requiring a minimum version, e.g. you can do
# find_package(GMP 6.0.0)
# to require version 6.0.0 to newer of GMP.
#
# Once done this will define
#
# GMP_FOUND - system has GMP lib with correct version
# GMP_INCLUDES - the GMP include directory
# GMP_LIBRARIES - the GMP library
# GMP_VERSION - GMP version
#
# Copyright (c) 2016 Jack Poulson, <jack.poulson@gmail.com>
# Redistribution and use is allowed according to the terms of the BSD license.

find_path(GMP_INCLUDES NAMES gmp.h PATHS $ENV{GMPDIR} ${INCLUDE_INSTALL_DIR})

# Set GMP_FIND_VERSION to 5.1.0 if no minimum version is specified
if(NOT GMP_FIND_VERSION)
if(NOT GMP_FIND_VERSION_MAJOR)
set(GMP_FIND_VERSION_MAJOR 5)
endif()
if(NOT GMP_FIND_VERSION_MINOR)
set(GMP_FIND_VERSION_MINOR 1)
endif()
if(NOT GMP_FIND_VERSION_PATCH)
set(GMP_FIND_VERSION_PATCH 0)
endif()
set(GMP_FIND_VERSION
"${GMP_FIND_VERSION_MAJOR}.${GMP_FIND_VERSION_MINOR}.${GMP_FIND_VERSION_PATCH}")
endif()

message("GMP_INCLUDES=${GMP_INCLUDES}")
if(GMP_INCLUDES)
# Since the GMP version macros may be in a file included by gmp.h of the form
# gmp-.*[_]?.*.h (e.g., gmp-x86_64.h), we search each of them.
file(GLOB GMP_HEADERS "${GMP_INCLUDES}/gmp.h" "${GMP_INCLUDES}/gmp-*.h")
foreach(gmp_header_filename ${GMP_HEADERS})
file(READ "${gmp_header_filename}" _gmp_version_header)
string(REGEX MATCH
"define[ \t]+__GNU_MP_VERSION[ \t]+([0-9]+)" _gmp_major_version_match
"${_gmp_version_header}")
if(_gmp_major_version_match)
set(GMP_MAJOR_VERSION "${CMAKE_MATCH_1}")
string(REGEX MATCH "define[ \t]+__GNU_MP_VERSION_MINOR[ \t]+([0-9]+)"
_gmp_minor_version_match "${_gmp_version_header}")
set(GMP_MINOR_VERSION "${CMAKE_MATCH_1}")
string(REGEX MATCH "define[ \t]+__GNU_MP_VERSION_PATCHLEVEL[ \t]+([0-9]+)"
_gmp_patchlevel_version_match "${_gmp_version_header}")
set(GMP_PATCHLEVEL_VERSION "${CMAKE_MATCH_1}")
set(GMP_VERSION
${GMP_MAJOR_VERSION}.${GMP_MINOR_VERSION}.${GMP_PATCHLEVEL_VERSION})
endif()
endforeach()

# Check whether found version exists and exceeds the minimum requirement
if(NOT GMP_VERSION)
set(GMP_VERSION_OK FALSE)
message(STATUS "GMP version was not detected")
elseif(${GMP_VERSION} VERSION_LESS ${GMP_FIND_VERSION})
set(GMP_VERSION_OK FALSE)
message(STATUS "GMP version ${GMP_VERSION} found in ${GMP_INCLUDES}, "
"but at least version ${GMP_FIND_VERSION} is required")
else()
set(GMP_VERSION_OK TRUE)
endif()
endif()

find_library(GMP_LIBRARIES gmp PATHS $ENV{GMPDIR} ${LIB_INSTALL_DIR})

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(GMP DEFAULT_MSG
GMP_INCLUDES GMP_LIBRARIES GMP_VERSION_OK)
mark_as_advanced(GMP_INCLUDES GMP_LIBRARIES)

+ 25
- 0
cmake/Modules/FindValgrind.cmake View File

@@ -0,0 +1,25 @@
# Find Valgrind.
#
# This module defines:
# VALGRIND_INCLUDE_DIR, where to find valgrind/memcheck.h, etc.
# VALGRIND_PROGRAM, the valgrind executable.
# VALGRIND_FOUND, If false, do not try to use valgrind.
#
# If you have valgrind installed in a non-standard place, you can define
# VALGRIND_PREFIX to tell cmake where it is.
#
# NOTE: Copied from the opencog project, where it is distributed under the
# terms of the New BSD License.

message(STATUS "Valgrind Prefix: ${VALGRIND_PREFIX}")

find_path(VALGRIND_INCLUDE_DIR valgrind/memcheck.h
/usr/include /usr/local/include ${VALGRIND_PREFIX}/include)
find_program(VALGRIND_PROGRAM NAMES valgrind PATH
/usr/bin /usr/local/bin ${VALGRIND_PREFIX}/bin)

find_package_handle_standard_args(VALGRIND DEFAULT_MSG
VALGRIND_INCLUDE_DIR
VALGRIND_PROGRAM)

mark_as_advanced(VALGRIND_INCLUDE_DIR VALGRIND_PROGRAM)

+ 47
- 0
cmake/Modules/GenerateCccc.cmake View File

@@ -0,0 +1,47 @@
INCLUDE(CheckParent)
# search for CCCC binary
FIND_PROGRAM(CCCC cccc )

#
# check if the GENERATE_CCCC function has already been defined
#
get_property(_GENERATE_CCCC GLOBAL PROPERTY _GENERATE_CCCC)
IF (NOT _GENERATE_CCCC)

# set that we have defined GENERATE_CCCC
set_property(GLOBAL PROPERTY _GENERATE_CCCC "YES")


FUNCTION(GENERATE_CCCC)
IF(CCCC)
CMAKE_PARSE_ARGUMENTS(ARG "" "" "TARGETS" ${ARGN})
get_property(_ccccfiles GLOBAL PROPERTY _ccccfiles)
foreach(_target ${ARG_TARGETS})
get_target_property(_sources ${_target} SOURCES)
get_target_property(_source_dir ${_target} SOURCE_DIR)

foreach(_source ${_sources})
set(_fullsource "${_source_dir}/${_source}")
list(APPEND _ccccfiles "${_fullsource}")
endforeach()
endforeach()
set_property(GLOBAL PROPERTY _ccccfiles ${_ccccfiles})
ENDIF()
ENDFUNCTION()

FUNCTION(RESET_CCCC)
set_property(GLOBAL PROPERTY _ccccfiles "")
ENDFUNCTION()

FUNCTION(GENERATE_CCCC_TARGET)
IF (NOT hasParent AND CCCC)
get_property(_targetccccfiles GLOBAL PROPERTY _ccccfiles)

ADD_CUSTOM_TARGET(cccc
COMMAND ${CCCC} --outdir=cccc ${_targetccccfiles}
COMMENT "Generating cccc result")
ENDIF()
ENDFUNCTION()


ENDIF()

+ 74
- 0
cmake/Modules/GenerateCppCheck.cmake View File

@@ -0,0 +1,74 @@
INCLUDE(CheckParent)
find_program(CPPCHECK NAMES cppcheck)

#
# check if the GENERATE_CPPCHECK function has already been defined
#
get_property(_GENERATE_CPPCHECK GLOBAL PROPERTY _GENERATE_CPPCHECK)
IF (NOT _GENERATE_CPPCHECK)

# set that we have defined GENERATE_CCCC
set_property(GLOBAL PROPERTY _GENERATE_CPPCHECK "YES")

FUNCTION(GENERATE_CPPCHECK)
IF(NOT TARGET cppcheck)
IF(CPPCHECK)
CMAKE_PARSE_ARGUMENTS(ARG "" "" "TARGETS" ${ARGN})
get_property(_cppcheckfiles GLOBAL PROPERTY _cppcheckfiles)
get_property(_cppcheckincludedirs GLOBAL PROPERTY _cppcheckincludedirs)

foreach(_target ${ARG_TARGETS})
get_target_property(_sources ${_target} SOURCES)
get_target_property(_source_dir ${_target} SOURCE_DIR)
get_target_property(_include_dir ${_target} INCLUDE_DIRECTORIES)
string(REPLACE "$<" ";" _include_dirs ${_include_dir})

foreach(_dir ${_include_dirs})
list(APPEND _cppcheckincludedirs -I${_include_dir})
endforeach()

foreach(_source ${_sources})
set(_fullsource "${_source_dir}/${_source}")
list(APPEND _cppcheckfiles ${_fullsource})
endforeach()
endforeach()
set_property(GLOBAL PROPERTY _cppcheckfiles ${_cppcheckfiles})
set_property(GLOBAL PROPERTY _cppcheckincludedirs ${_cppcheckincludedirs})
ENDIF()
ENDIF()
ENDFUNCTION()

FUNCTION(RESET_CPPCHECK)
set_property(GLOBAL PROPERTY _cppcheckfiles "")
set_property(GLOBAL PROPERTY _cppcheckincludedirs "")
ENDFUNCTION()


FUNCTION(GENERATE_CPPCHECK_TARGET)
IF ( NOT hasParent AND CPPCHECK)
message("generate cppcheck target")
get_property(_targetcppcheckfiles GLOBAL PROPERTY _cppcheckfiles)
get_property(_targetcppcheckincludedirs GLOBAL PROPERTY _cppcheckincludedirs)

add_custom_target(cppcheck
COMMAND
${CPPCHECK}
--xml
--xml-version=2
--enable=all
--inconclusive
--force
--inline-suppr
${_targetcppcheckincludedirs}
${_targetcppcheckfiles}
2> cppcheck.xml
WORKING_DIRECTORY
${CMAKE_CURRENT_BINARY_DIR}
COMMENT
"cppcheck: Running cppcheck on target ${_targetname}..."
VERBATIM)

ENDIF()
ENDFUNCTION()

ENDIF()

+ 23
- 0
cmake/Modules/ProcessDOXYGEN.cmake View File

@@ -0,0 +1,23 @@
INCLUDE(CheckParent)

IF(NOT hasParent)
find_package(Doxygen)


IF (DOXYGEN_FOUND)
# set input and output files
set(DOXYGEN_IN ${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile.in)
set(DOXYGEN_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)

# request to configure the file
configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT} @ONLY)

# note the option ALL which allows to build the docs together with the application
add_custom_target( doxygen
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating API documentation with Doxygen"
VERBATIM )
ENDIF()

ENDIF()

+ 17
- 0
cmake/Modules/ProcessGIT.cmake View File

@@ -0,0 +1,17 @@
if (GIT_FOUND)
execute_process(
COMMAND git rev-parse --abbrev-ref HEAD
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_BRANCH
OUTPUT_STRIP_TRAILING_WHITESPACE
)

# Get the latest abbreviated commit hash of the working branch
execute_process(
COMMAND git log -1 --format=%h
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
)

endif()

+ 22
- 0
cmake/Modules/add_my_test.cmake View File

@@ -0,0 +1,22 @@
get_property(_ADD_MY_TEST GLOBAL PROPERTY _ADD_MY_TEST)
IF (NOT _ADD_MY_TEST)

# set that we have defined GENERATE_CCCC
set_property(GLOBAL PROPERTY _ADD_MY_TEST "YES")


FUNCTION(ADD_MY_TEST)
CMAKE_PARSE_ARGUMENTS(ARG "" "TEST" "SOURCES;LIBS" ${ARGN})
get_property(_mytests GLOBAL PROPERTY _mytests)

list(APPEND _mytests "${ARG_TEST}")

add_executable(${ARG_TEST} ${ARG_SOURCES})
target_link_libraries(${ARG_TEST} ${ARG_LIBS})
add_test(${ARG_TEST} ${ARG_TEST})

set_property(GLOBAL PROPERTY _mytests ${_mytests})
ENDFUNCTION()


ENDIF()

+ 66
- 0
cmake/Modules/c++-standards.cmake View File

@@ -0,0 +1,66 @@
#
# 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 the compiler standard to C++11
macro(cxx_11)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

if(MSVC_VERSION GREATER_EQUAL "1900" AND CMAKE_VERSION LESS 3.10)
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag("/std:c++11" _cpp_latest_flag_supported)
if(_cpp_latest_flag_supported)
add_compile_options("/std:c++11")
endif()
endif()
endmacro()

# Set the compiler standard to C++14
macro(cxx_14)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

if(MSVC_VERSION GREATER_EQUAL "1900" AND CMAKE_VERSION LESS 3.10)
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag("/std:c++14" _cpp_latest_flag_supported)
if(_cpp_latest_flag_supported)
add_compile_options("/std:c++14")
endif()
endif()
endmacro()

# Set the compiler standard to C++17
macro(cxx_17)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

if(MSVC_VERSION GREATER_EQUAL "1900" AND CMAKE_VERSION LESS 3.10)
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag("/std:c++17" _cpp_latest_flag_supported)
if(_cpp_latest_flag_supported)
add_compile_options("/std:c++17")
endif()
endif()
endmacro()

# Set the compiler standard to C++20
macro(cxx_20)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
endmacro()

+ 588
- 0
cmake/Modules/code-coverage.cmake View File

@@ -0,0 +1,588 @@
#
# 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 NAMES llvm-cov llvm-cov-8 llvm-cov-7 llvm-cov-6)
find_program(LLVM_PROFDATA_PATH NAMES llvm-profdata llvm-profdata-8 llvm-profdata-7 llvm-profdata-6)
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 "(Apple)?[Cc]lang"
OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[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' compatability
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_COMPILER_IS_GNUCXX)
# 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()
message(FATAL_ERROR "Code coverage requires Clang or GCC. Aborting.")
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 "(Apple)?[Cc]lang"
OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[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_COMPILER_IS_GNUCXX)
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 "(Apple)?[Cc]lang"
OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[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 "(Apple)?[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_COMPILER_IS_GNUCXX)
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()

# Generates HTML output of the coverage information for perusal
add_custom_target(
ccov-${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}
COMMAND ${GENHTML_PATH}
-o
${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/${TARGET_NAME}
${COVERAGE_INFO}
DEPENDS ccov-preprocessing ${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 "(Apple)?[Cc]lang"
OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang")
add_compile_options(-fprofile-instr-generate -fcoverage-mapping)
add_link_options(-fprofile-instr-generate -fcoverage-mapping)
elseif(CMAKE_COMPILER_IS_GNUCXX)
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.
# ~~~
# 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 "(Apple)?[Cc]lang"
OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[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_COMPILER_IS_GNUCXX)
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()

# Generates HTML output of all targets for perusal
add_custom_target(ccov-all
COMMAND ${LCOV_PATH}
--directory
${CMAKE_BINARY_DIR}
--capture
--output-file
${COVERAGE_INFO}
COMMAND ${EXCLUDE_COMMAND}
COMMAND ${GENHTML_PATH}
-o
${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged
${COVERAGE_INFO}
COMMAND ${CMAKE_COMMAND}
-E
remove
${COVERAGE_INFO}
DEPENDS ccov-all-processing)

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()

+ 99
- 0
cmake/Modules/codecheck.cmake View File

@@ -0,0 +1,99 @@
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
#
option(CODECHECKER "Turns on codecheck processing if it is found." OFF)
option(CODECHECKER_STORE "Store results on central codechecker server" OFF)
option(CODECHECKER_RUN "Name of the codechecker run" "run-1")
option(CODECHECKER_URL "URL and product link to codechecker server" "http://localhost:8001/Default")

find_program(CODECHECKER_VENV_PATH
NAME activate
PATHS ~/Apps/codechecker/venv/bin/
~/codechecker/venv/bin/
/usr/src/codechecker/venv/bin/
)

find_program(CODECHECKER_PATH
NAME CodeChecker
PATHS ~/Apps/codechecker/build/CodeChecker/bin/
~/codechecker/build/CodeChecker/bin/
/usr/src/~/codechecker/build/CodeChecker/bin/
)


execute_process(
COMMAND git rev-parse --abbrev-ref HEAD
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE CODECHECK_GIT_BRANCH
OUTPUT_STRIP_TRAILING_WHITESPACE
)



if (CODECHECKER_PATH AND CODECHECKER_VENV_PATH)
message(STATUS "CodeChecker found")
else()
message(STATUS "CodeChecker not found")
endif()

# export compile commands to json file to be used by atom c++ ide (clangd)
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
set(CODECHECKER_COMPILE_COMMANDS "${CMAKE_BINARY_DIR}/compile_commands.json")

# check if a skip file exists
if(EXISTS ${CMAKE_SOURCE_DIR}/codecheck.skip)
set(CODECHECKER_SKIP "-i${CMAKE_SOURCE_DIR}/codecheck.skip")
endif()


# output directory for codecheck analysis
set(CODECHECKER_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/codechecker_results)

# html output directory
set(CODECHECKER_HTML_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/codechecker_html)

# Common initialization/checks
if(CODECHECKER AND CODECHECKER_PATH AND CODECHECKER_VENV_PATH AND NOT CODECHECKER_ADDED)
set(CODECHECKER_ADDED ON)

add_custom_target(codechecker
COMMAND . ${CODECHECKER_VENV_PATH}\;
${CODECHECKER_PATH}
analyze
${CODECHECKER_SKIP}
-e sensitive
-j 4
-o ${CODECHECKER_OUTPUT_DIRECTORY}
${CODECHECKER_COMPILE_COMMANDS}
)

add_custom_target(codechecker-clean
COMMAND rm -rf ${CODECHECKER_OUTPUT_DIRECTORY}
)


add_custom_target(codechecker-html
COMMAND . ${CODECHECKER_VENV_PATH}\;
${CODECHECKER_PATH}
parse
${CODECHECKER_OUTPUT_DIRECTORY}
-e html
-o ${CODECHECKER_HTML_OUTPUT_DIRECTORY}
)

if (CODECHECKER_STORE)
add_custom_target(codechecker-store
COMMAND . ${CODECHECKER_VENV_PATH}\;
${CODECHECKER_PATH}
store
--tag ${CODECHECK_GIT_BRANCH}
-n ${CODECHECKER_RUN}
--url ${CODECHECKER_URL}
${CODECHECKER_OUTPUT_DIRECTORY}
)
endif()


endif()

+ 46
- 0
cmake/Modules/compiler-options.cmake View File

@@ -0,0 +1,46 @@
#
# 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(ENABLE_ALL_WARNINGS "Compile with all warnings for the major compilers."
OFF)
option(ENABLE_EFFECTIVE_CXX "Enable Effective C++ warnings." OFF)

if(ENABLE_ALL_WARNINGS)
if(CMAKE_COMPILER_IS_GNUCXX)
# GCC
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
elseif("${CMAKE_C_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang"
OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang")
# Clang
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
elseif(MSVC)
# MSVC
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
endif()
endif()

if(ENABLE_EFFECTIVE_CXX)
if(CMAKE_COMPILER_IS_GNUCXX)
# GCC
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Weffc++")
elseif("${CMAKE_C_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang"
OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang")
# Clang
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Weffc++")
endif()
endif()

+ 13
- 0
cmake/Modules/defaultIncludes.cmake View File

@@ -0,0 +1,13 @@
include(c++-standards)
include(compiler-options)
include(sanitizers)
include(codecheck)
include(code-coverage)
include(tools)
include(GNUInstallDirs)
include(CTest)
include(doxygen)
include(ProcessGIT)
include(CheckParent)
include(add_my_test)
include(TestBigEndian)

+ 11
- 0
cmake/Modules/defaultOptions.cmake View File

@@ -0,0 +1,11 @@
include(defaultIncludes)
find_package(Git)


enable_testing()
cxx_14()
build_docs(PROCESS_DOXYFILE DOXYFILE_PATH "docs/Doxyfile.in" )
cppcheck("--enable=warning,performance,portability,missingInclude;--template=\"[{severity}][{id}] {message} {callstack} \(On {file}:{line}\)\";--suppress=missingIncludeSystem;--suppress=*:${PROJECT_SOURCE_DIR}/libs/*;--quiet;--verbose;--force")

add_code_coverage_all_targets(EXCLUDE ${PROJECT_SOURCE_DIR}/libs/* ${PROJECT_SOURCE_DIR}/test/*)
TEST_BIG_ENDIAN(IS_BIG_ENDIAN)

+ 132
- 0
cmake/Modules/doxygen.cmake View File

@@ -0,0 +1,132 @@
#
# 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.

find_package(Doxygen)

option(BUILD_DOCUMENTATION "Build API documentation using Doxygen. (make doc)"
${DOXYGEN_FOUND})

# 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')
# ~~~
function(build_docs)
set(OPTIONS ADD_TO_DOC INSTALLABLE PROCESS_DOXYFILE)
set(SINGLE_VALUE_KEYWORDS
TARGET_NAME
INSTALL_PATH
DOXYFILE_PATH
OUTPUT_DIR)
set(MULTI_VALUE_KEYWORDS)
cmake_parse_arguments(build_docs
"${OPTIONS}"
"${SINGLE_VALUE_KEYWORDS}"
"${MULTI_VALUE_KEYWORDS}"
${ARGN})

if(BUILD_DOCUMENTATION)
if(NOT DOXYGEN_FOUND)
message(FATAL_ERROR "Doxygen is needed to build the documentation.")
endif()

if(NOT build_docs_DOXYFILE_PATH)
set(DOXYFILE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile)
elseif(EXISTS ${build_docs_DOXYFILE_PATH})
set(DOXYFILE_PATH ${build_docs_DOXYFILE_PATH})
else()
set(DOXYFILE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${build_docs_DOXYFILE_PATH})
endif()

if(NOT EXISTS ${DOXYFILE_PATH})
message(
SEND_ERROR
"Could not find Doxyfile to use for procesing documentation at: ${DOXYFILE_PATH}"
)
return()
endif()

if(build_docs_PROCESS_DOXYFILE)
set(DOXYFILE ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
configure_file(${DOXYFILE_PATH} ${DOXYFILE} @ONLY)
else()
set(DOXYFILE ${DOXYFILE_PATH})
endif()

if(build_docs_OUTPUT_DIR)
set(OUT_DIR ${build_docs_OUTPUT_DIR})
else()
set(OUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/doc)
endif()

file(MAKE_DIRECTORY ${OUT_DIR})

if(build_docs_TARGET_NAME)
set(TARGET_NAME ${build_docs_TARGET_NAME})
else()
set(TARGET_NAME doc-${PROJECT_NAME})
endif()

add_custom_target(${TARGET_NAME}
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE}
WORKING_DIRECTORY ${OUT_DIR}
VERBATIM)

if(build_docs_ADD_TO_DOC)
if(NOT TARGET doc)
add_custom_target(doc)
endif()

add_dependencies(doc ${TARGET_NAME})
endif()

if(build_docs_INSTALLABLE)
if(NOT build_docs_INSTALL_PATH)
set(build_docs_INSTALL_PATH share/${PROJECT_NAME})
endif()
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc/
COMPONENT documentation
DESTINATION ${build_docs_INSTALL_PATH})
endif()
endif()
endfunction()

+ 87
- 0
cmake/Modules/sanitizers.cmake View File

@@ -0,0 +1,87 @@
#
# 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)
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)
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)
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()
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()
elseif(USE_SANITIZER MATCHES "([Tt]hread)")
message(STATUS "Building with Thread sanitizer")
append("-fsanitize=thread" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
elseif(USE_SANITIZER MATCHES "([Ll]eak)")
message(STATUS "Building with Leak sanitizer")
append("-fsanitize=leak" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
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()

+ 94
- 0
cmake/Modules/tools.cmake View File

@@ -0,0 +1,94 @@
#
# 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};${ARGN}")
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};${ARGN}")
endif()
endmacro()

find_program(CLANG_TIDY_EXE NAMES clang-tidy clang-tidy-8 clang-tidy-7 clang-tidy-6)
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(CPPCHECK)
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()

+ 16
- 0
cmake/Toolchains/Toolchain-mingw64.cmake View File

@@ -0,0 +1,16 @@
# the name of the target operating system
SET(CMAKE_SYSTEM_NAME Windows)

# which compilers to use for C and C++
SET(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
SET(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++)

# here is the target environment located
SET(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32)

# adjust the default behaviour of the FIND_XXX() commands:
# search headers and libraries in the target environment, search
# programs in the host environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

Loading…
Cancel
Save