Skip to content

Commit

Permalink
Fix #1207, Add wrapper targets to simplify app builds
Browse files Browse the repository at this point in the history
Adds the following functions to simplify tracking of dependencies
and use of interface libraries provided by CFE.

The goal is to reduce/eliminate the need to directly specify any
include paths or compile definitions for dependencies, relying
on target properties to do this instead.
  • Loading branch information
jphickey committed Mar 4, 2021
1 parent 605cdd2 commit a2b270c
Showing 1 changed file with 218 additions and 30 deletions.
248 changes: 218 additions & 30 deletions cmake/arch_build.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@
#
##################################################################

# define a custom property to track dependencies on CFE module targets.
# users should not typically maniplate this directly
define_property(TARGET PROPERTY CFE_MODULE_DEPENDENCIES
BRIEF_DOCS
"A set of CFE module dependencies"
FULL_DOCS
"This is a CFE-specific target property that is added to CFE modules that contains the module dependencies"
)


##################################################################
#
Expand Down Expand Up @@ -97,6 +106,38 @@ function(add_cfe_app APP_NAME APP_SRC_FILES)

endfunction(add_cfe_app)

##################################################################
#
# FUNCTION: add_cfe_app_dependency
#
# Adds a library dependency to a previously-created
# app/library target
#
# it adds the interface include directories and compile definitions
# of the dependency into the compilation for the module.
#
function(add_cfe_app_dependency MODULE_NAME DEPENDENCY_MODULE)

# assemble a list of include directories and compile definitions
set(INCLUDE_LIST)
set(COMPILE_DEF_LIST)
foreach(DEP ${DEPENDENCY_MODULE} ${ARGN})
list(APPEND INCLUDE_LIST "$<TARGET_PROPERTY:${DEPENDENCY_MODULE},INTERFACE_INCLUDE_DIRECTORIES>")
list(APPEND COMPILE_DEF_LIST "$<TARGET_PROPERTY:${DEPENDENCY_MODULE},INTERFACE_COMPILE_DEFINITIONS>")
endforeach()

target_include_directories(${MODULE_NAME} PUBLIC
${INCLUDE_LIST}
)
target_compile_definitions(${MODULE_NAME} PUBLIC
${COMPILE_DEF_LIST}
)

# append to the custom property to track this dependency (this helpful for UT)
set_property(TARGET ${MODULE_NAME} APPEND PROPERTY CFE_MODULE_DEPENDENCIES ${DEPENDENCY_MODULE} ${ARGN})

endfunction(add_cfe_app_dependency)

##################################################################
#
# FUNCTION: add_cfe_tables
Expand Down Expand Up @@ -175,47 +216,194 @@ endfunction(add_cfe_tables)

##################################################################
#
# FUNCTION: add_unit_test_lib
# FUNCTION: add_cfe_coverage_dependency
#
# Adds a stub library dependency to a previously-created
# coverage test runner target
#
# Add a library for unit testing. This is basically the same as the
# normal CMake "add_library" but enables the code coverage compiler options.
# If a unit under test calls functions provided by another unit
# (such as a library) then the stubs from that library will be
# added to the LINK_LIBRARIES of the coverage test.
#
function(add_unit_test_lib UT_NAME UT_SRCS)
add_library(utl_${UT_NAME} STATIC ${UT_SRCS} ${ARGN})
set_target_properties(utl_${UT_NAME} PROPERTIES COMPILE_FLAGS "${CMAKE_C_FLAGS} -pg --coverage")
endfunction(add_unit_test_lib)
function(add_cfe_coverage_dependency MODULE_NAME UNIT_NAME DEPENDENCY_MODULE)

# the stub library correlating to the module should be named:
# coverage-${MODULE_NAME}-stubs
# (assuming it was added by the add_cfe_coverage_stubs above)
set(DEP_LIST)
foreach(DEP ${DEPENDENCY_MODULE} ${ARGN})
list(APPEND DEP_LIST "coverage-${DEP}-stubs")
endforeach()

target_link_libraries(coverage-${MODULE_NAME}-${UNIT_NAME}-testrunner
${DEP_LIST}
)

endfunction(add_cfe_coverage_dependency)


##################################################################
#
# FUNCTION: add_unit_test_exe
# FUNCTION: add_cfe_coverage_test
#
# Add executable target for coverage testing. This builds the target
# units with extra compiler flags for coverage instrumentation, along with
# a "testrunner" executable to run the tests. It also registers
# that testrunner with ctest via the add_test() function.
#
# NOTE: The first argument (MODULE_NAME) must match the name that was previously
# passed to the add_cfe_app() function - as this references that previous
# target to use the same compile definitions and include paths.
#
# Create unit test executable. This links the UT main executive with
# a library that is placed under test (created via add_unit_test_lib)
# It also registers the final executable target with ctest so it will
# be run during the "make test" target or when ctest is run.
# The executable target name follows the pattern:
# "coverage-${MODULE_NAME}-${UNIT_NAME}-testrunner"
#
function(add_unit_test_exe UT_NAME UT_SRCS)
add_executable(${UT_NAME} ${utexec_MISSION_DIR}/src/utexec.c ${UT_SRCS} ${ARGN})
# The calling script may call target_link_libraries() (or other target functions)
# to customize this target as needed.
#
function(add_cfe_coverage_test MODULE_NAME UNIT_NAME TESTCASE_SRC UT_SRCS)

# A consistent name convention for all targets generated by this funtion
set(TEST_NAME "coverage-${MODULE_NAME}-${UNIT_NAME}")
set(OBJECT_TARGET "${TEST_NAME}-object")
set(RUNNER_TARGET "${TEST_NAME}-testrunner")

# Compile the source unit(s) under test as a separate library
# This is done so that special coverage-specific compile flags can be used on these files
add_library(${OBJECT_TARGET} OBJECT
${UT_SRCS}
)

get_target_property(UTCDEFS ${UT_NAME} COMPILE_DEFINITIONS)
list(APPEND UTCDEFS "DEFAULT_REF_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}\"")
# Apply the UT_COVERAGE_COMPILE_FLAGS to the units under test
# This should enable coverage analysis on platforms that support this
target_compile_options(${OBJECT_TARGET} PRIVATE
${UT_COVERAGE_COMPILE_FLAGS}
)

# Include the same set of include dirs/definitions that is used from the app target
target_include_directories(${OBJECT_TARGET} PUBLIC
$<TARGET_PROPERTY:${MODULE_NAME},INCLUDE_DIRECTORIES>
)
target_compile_definitions(${OBJECT_TARGET} PUBLIC
$<TARGET_PROPERTY:${MODULE_NAME},COMPILE_DEFINITIONS>
)

# Compile a test runner application, which contains the
# actual coverage test code (test cases) and the unit under test
add_executable(${RUNNER_TARGET}
${TESTCASE_SRC}
$<TARGET_OBJECTS:${OBJECT_TARGET}>
)

get_target_property(UTCFLAGS ${UT_NAME} COMPILE_FLAGS)
if (UTCFLAGS STREQUAL "UTCFLAGS-NOTFOUND")
set(UTCFLAGS)
endif()
set(UTCFLAGS "${UTCFLAGS} -I${utexec_MISSION_DIR}/inc -I${CMAKE_CURRENT_SOURCE_DIR}")
# Include the same set of include dirs/definitions that is used from the app target
target_include_directories(${RUNNER_TARGET} PUBLIC
$<TARGET_PROPERTY:${MODULE_NAME},INCLUDE_DIRECTORIES>
)
target_compile_definitions(${RUNNER_TARGET} PUBLIC
$<TARGET_PROPERTY:${MODULE_NAME},COMPILE_DEFINITIONS>
)

# This also needs to be linked with UT_COVERAGE_LINK_FLAGS (for coverage)
# This is also linked with any other stub libraries needed,
# as well as the UT assert framework
target_link_libraries(${RUNNER_TARGET}
${UT_COVERAGE_LINK_FLAGS}
ut_cfe-core_stubs
ut_assert
)

get_target_property(UTLFLAGS ${UT_NAME} LINK_FLAGS)
if (UTLFLAGS STREQUAL "UTLFLAGS-NOTFOUND")
set(UTLFLAGS)
# for whatever app/lib dependencies the real FSW app had, the unit test
# should have the same dependencies but on the stubs instead.
get_target_property(MODULE_DEPENDENCIES ${MODULE_NAME} CFE_MODULE_DEPENDENCIES)
if (MODULE_DEPENDENCIES)
add_cfe_coverage_dependency(${MODULE_NAME} ${UNIT_NAME} ${MODULE_DEPENDENCIES})
endif(MODULE_DEPENDENCIES)

# Add it to the set of tests to run as part of "make test"
add_test(${TEST_NAME} ${RUNNER_TARGET})
foreach(TGT ${INSTALL_TARGET_LIST})
install(TARGETS ${RUNNER_TARGET} DESTINATION ${TGT}/${UT_INSTALL_SUBDIR})
endforeach()

endfunction(add_cfe_coverage_test)


##################################################################
#
# FUNCTION: add_cfe_coverage_unit_include
#
# Add an "override" include directory for a specific unit test
#
# This can be used if a coverage test needs to override certain
# C library header files only for a specific unit under test. The
# include path is added only for the particular source files in the
# specified coverage test unit. (Not for the coverage test itself).
#
# The executable target name follows the pattern:
# "coverage-${MODULE_NAME}-${UNIT_NAME}-testrunner"
#
function(add_cfe_coverage_unit_include MODULE_NAME UNIT_NAME OVERRIDE_INCLUDE_DIRS)
# For the object target only, the "override" includes should be injected
# into the include path. Note it is important that this is only included
# for the specific unit under test (object lib) not the coverage
# test executable or test cases, since these typically need the real
# version of these functions.
target_include_directories(coverage-${MODULE_NAME}-${UNIT_NAME}-object PRIVATE
${OVERRIDE_INCLUDE_DIRS} ${ARGN}
)

endfunction(add_cfe_coverage_unit_include)


##################################################################
#
# FUNCTION: add_cfe_coverage_stubs
#
# Add stub library target for coverage testing. The stub library should
# contain a stub implementation for every function defined in the public
# API of the current module.
#
# NOTE: The first argument (MODULE_NAME) should match a name that was previously
# passed to the add_cfe_app() function - as this references that previous
# target to use the same compile definitions and include paths.
# (however this does also allow extra stub libs to be created that are not
# related to an existing module)
#
# The stub library target name follows the pattern:
# "coverage-${MODULE_NAME}-stubs"
#
# The calling script may call target_link_libraries() (or other target functions)
# to customize this target as needed.
#
# NOTE: To simplify linking and avoid possible problems there should ideally be a 1:1
# relationship between module source files and the stub files. Each stub file
# should provide the same set of functions that the fsw source file provides.
# (although its is not strictly required, it does help keep things more manageable).
#
function(add_cfe_coverage_stubs MODULE_NAME STUB_SRCS)

set(STUB_TARGET "coverage-${MODULE_NAME}-stubs")

add_library(${STUB_TARGET} STATIC
${STUB_SRCS} ${ARGN}
)

# If the MODULE_NAME refers to an existing CFE APP/LIB target, then
# use the same set of include dirs/definitions that is used from the app target
# This is not required; "extra" stub libs may be created that are not
# directly associated with an existing module.
if (TARGET ${MODULE_NAME})
target_include_directories(${STUB_TARGET} PUBLIC
$<TARGET_PROPERTY:${MODULE_NAME},INCLUDE_DIRECTORIES>
)
target_compile_definitions(${STUB_TARGET} PUBLIC
$<TARGET_PROPERTY:${MODULE_NAME},COMPILE_DEFINITIONS>
)
endif()
set(UTLFLAGS "${UTLFLAGS} -pg --coverage")

set_target_properties(${UT_NAME} PROPERTIES LINK_FLAGS "${UTLFLAGS}" COMPILE_DEFINITIONS "${UTCDEFS}" COMPILE_FLAGS "${UTCFLAGS}")
target_link_libraries(${UT_NAME} utl_${UT_NAME})
add_test(${UT_NAME} ${UT_NAME})
endfunction(add_unit_test_exe)

target_link_libraries(${STUB_TARGET} ut_assert)

endfunction(add_cfe_coverage_stubs)


##################################################################
Expand Down

0 comments on commit a2b270c

Please sign in to comment.