Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add hook to create ccov target each time that add_ex.. and add_lib...… #35

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ This is a collection of quite useful scripts that expand the possibilities for b
- [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)
- [Example 4: Hook all targets](#example-4-hook-all-targets)
- [AFL Fuzzing Instrumentation `afl-fuzzing.cmake`](#afl-fuzzing-instrumentation-afl-fuzzingcmake)
- [Usage](#usage-1)
- [Compiler Options `compiler-options.cmake`](#compiler-options-compiler-optionscmake)
Expand Down Expand Up @@ -136,6 +137,7 @@ To enable any code coverage instrumentation/targets, the single CMake option of
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.
3. Automatically add coverage for each target with `-DCCOV_TARGETS_HOOK=On` and `-DCCOV_TARGETS_HOOK_ARGS=...` for default values, requires `add_code_coverage()` or similar.

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.

Expand Down Expand Up @@ -184,6 +186,20 @@ 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.
```

#### Example 4: Hook all targets
```
# this could be as well command line argument
set(CCOV_TARGETS_HOOK ON) # enable 'add_executable' and 'add_library' hooks
set(CCOV_TARGETS_HOOK_ARGS ALL AUTO) # set default arguments for coverage

add_code_coverage() # Adds instrumentation to all targets

add_library(theLib lib.cpp) # ccov-theLib target will be add

add_executable(theExe main.cpp) # ccov-theExe target will be add
target_link_libraries(theExe PRIVATE theLib)
```

## AFL Fuzzing Instrumentation [`afl-fuzzing.cmake`](afl-fuzzing.cmake)

> American fuzzy lop is a security-oriented fuzzer that employs a novel type of compile-time instrumentation and genetic algorithms to automatically discover clean, interesting test cases that trigger new internal states in the targeted binary. This substantially improves the functional coverage for the fuzzed code. The compact synthesized corpora produced by the tool are also useful for seeding other, more labor- or resource-intensive testing regimes down the road.
Expand Down
74 changes: 72 additions & 2 deletions code-coverage.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,35 @@
# 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.
# ~~~
#
# Example 4: Hook all targets
#
# ~~~
# set(CCOV_TARGETS_HOOK ON) # enable 'add_executable' and 'add_library' hooks
# set(CCOV_TARGETS_HOOK_ARGS ALL AUTO) # set default arguments for coverage
#
# add_code_coverage() # Adds instrumentation to all targets
#
# add_library(theLib lib.cpp) # ccov-theLib target will be add
#
# add_executable(theExe main.cpp) # ccov-theExe target will be add
# target_link_libraries(theExe PRIVATE theLib)
# ~~~

# Options
option(
CODE_COVERAGE
"Builds targets with code coverage instrumentation. (Requires GCC or Clang)"
OFF)

option(
CCOV_TARGETS_HOOK
"Autocapture all new targets."
OFF)

set(CCOV_TARGETS_HOOK_ARGS "" CACHE STRING
"Default arguments for all hooked targets.")

# Programs
find_program(LLVM_COV_PATH llvm-cov)
find_program(LLVM_PROFDATA_PATH llvm-profdata)
Expand Down Expand Up @@ -181,6 +203,47 @@ if(CODE_COVERAGE AND NOT CODE_COVERAGE_ADDED)
else()
message(FATAL_ERROR "Code coverage requires Clang or GCC. Aborting.")
endif()

if (CCOV_TARGETS_HOOK)
if (COMMAND _add_executable)
message(FATAL_ERROR "add_executable was already redefined. Only one redefinitions is allowed.")
endif()

set(CCOV_TARGETS_HOOK_LIST ${CCOV_TARGETS_HOOK_ARGS})
separate_arguments(CCOV_TARGETS_HOOK_LIST)

macro(add_executable target_name)
_add_executable(${target_name} ${ARGN})
if (${ARGC} GREATER 1)
string(TOUPPER ${ARGV1} TARGET_TYPE)
endif()
string(COMPARE NOTEQUAL "${TARGET_TYPE}" IMPORTED IS_NOT_IMPORTED)

if (IS_NOT_IMPORTED)
target_code_coverage(${target_name} ${CCOV_TARGETS_HOOK_LIST})
endif()
endmacro(add_executable)

if (COMMAND _add_library)
message(FATAL_ERROR "add_library was already redefined. Only one redefinitions is allowed.")
endif()
macro(add_library target_name)
_add_library(${target_name} ${ARGN})
if (${ARGC} GREATER 1)
string(TOUPPER "${ARGV1}" TARGET_TYPE)
endif()
if (${ARGC} GREATER 2)
string(TOUPPER "${ARGV2}" IMPORTED_TYPE)
endif()
string(COMPARE NOTEQUAL "${TARGET_TYPE}" ALIAS IS_NOT_ALIAS)
string(COMPARE NOTEQUAL "${IMPORTED_TYPE}" IMPORTED IS_NOT_IMPORTED)

if (IS_NOT_ALIAS AND IS_NOT_IMPORTED)
target_code_coverage(${target_name} ${CCOV_TARGETS_HOOK_LIST})
endif()
endmacro(add_library)
endif (CCOV_TARGETS_HOOK)

endif()

# Adds code coverage instrumentation to a library, or instrumentation/targets
Expand Down Expand Up @@ -208,6 +271,7 @@ endif()
# Optional:
# PUBLIC - Sets the visibility for added compile options to targets to PUBLIC instead of the default of PRIVATE.
# INTERFACE - Sets the visibility for added compile options to targets to INTERFACE instead of the default of PRIVATE.
# PLAIN - Do not set any target visibility (backward compatibility with old cmake projects)
# 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
Expand All @@ -218,7 +282,7 @@ endif()
# ~~~
function(target_code_coverage TARGET_NAME)
# Argument parsing
set(options AUTO ALL EXTERNAL PUBLIC INTERFACE)
set(options AUTO ALL EXTERNAL PUBLIC INTERFACE PLAIN)
set(single_value_keywords COVERAGE_TARGET_NAME)
set(multi_value_keywords EXCLUDE OBJECTS ARGS)
cmake_parse_arguments(
Expand All @@ -229,10 +293,16 @@ function(target_code_coverage TARGET_NAME)
# PRIVATE.
if(target_code_coverage_PUBLIC)
set(TARGET_VISIBILITY PUBLIC)
set(TARGET_LINK_VISIBILITY PUBLIC)
elseif(target_code_coverage_INTERFACE)
set(TARGET_VISIBILITY INTERFACE)
set(TARGET_LINK_VISIBILITY INTERFACE)
elseif(target_code_coverage_PLAIN)
set(TARGET_VISIBILITY PUBLIC)
set(TARGET_LINK_VISIBILITY)
else()
set(TARGET_VISIBILITY PRIVATE)
set(TARGET_LINK_VISIBILITY PRIVATE)
endif()

if(NOT target_code_coverage_COVERAGE_TARGET_NAME)
Expand All @@ -253,7 +323,7 @@ function(target_code_coverage TARGET_NAME)
"GNU")
target_compile_options(${TARGET_NAME} ${TARGET_VISIBILITY} -fprofile-arcs
-ftest-coverage)
target_link_libraries(${TARGET_NAME} ${TARGET_VISIBILITY} gcov)
target_link_libraries(${TARGET_NAME} ${TARGET_LINK_VISIBILITY} gcov)
endif()

# Targets
Expand Down
31 changes: 31 additions & 0 deletions example/code-coverage-hook/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
cmake_minimum_required(VERSION 3.10)
project(code-coverage-hook C CXX)

# Set the searching location for cmake 'include' locations
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/../..;")
# Include the code coverage module
cmake_policy(SET CMP0077 NEW)

set(CCOV_TARGETS_HOOK ON)
set(CCOV_TARGETS_HOOK_ARGS "ALL")

include(code-coverage)

# Require C++11
include(c++-standards)
cxx_11()
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)

# This introduces the 'ccov-all' targets Also excludes the main file via a regex
add_code_coverage_all_targets(EXCLUDE coverage.main.cpp)

# The library
add_library(lib ../src/coverage.cpp)

# The executable
add_executable(main ../src/coverage.main.cpp)
target_link_libraries(main PUBLIC lib)

# The second executable
add_executable(main2 ../src/coverage.main.cpp)
target_link_libraries(main2 PUBLIC lib)