2020-01-02 15:53:39 +00:00
|
|
|
# Copyright 2020 The Pigweed Authors
|
|
|
|
#
|
|
|
|
# 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
|
|
|
|
#
|
|
|
|
# https://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.
|
|
|
|
include_guard(GLOBAL)
|
|
|
|
|
|
|
|
# Create an empty, dummy source file for use by non-INTERFACE libraries, which
|
|
|
|
# require at least one source file.
|
|
|
|
set(_pw_empty_source_file "${CMAKE_BINARY_DIR}/pw_empty_source_file.cc")
|
|
|
|
file(WRITE "${_pw_empty_source_file}" "")
|
|
|
|
|
|
|
|
# Automatically creates a library and test targets for the files in a module.
|
|
|
|
# This function is only suitable for simple modules that meet the following
|
|
|
|
# requirements:
|
|
|
|
#
|
|
|
|
# - The module exposes exactly one library.
|
|
|
|
# - All source files in the module directory are included in the library.
|
2020-01-09 20:24:24 +00:00
|
|
|
# - Each test in the module has
|
|
|
|
# - exactly one source .cc file,
|
|
|
|
# - optionally, one .c source with the same base name as the .cc file,
|
|
|
|
# - only a dependency on the main module library.
|
2020-01-02 15:53:39 +00:00
|
|
|
# - The module is not a facade.
|
|
|
|
#
|
|
|
|
# Modules that do not meet these requirements may not use
|
|
|
|
# pw_auto_add_simple_module. Instead, define the module's libraries and tests
|
|
|
|
# with pw_add_module_library, pw_add_facade, pw_add_test, and the standard CMake
|
|
|
|
# functions, such as add_library, target_link_libraries, etc.
|
|
|
|
#
|
|
|
|
# This function does the following:
|
|
|
|
#
|
|
|
|
# 1. Find all .c and .cc files in the module's root directory.
|
|
|
|
# 2. Create a library with the module name using pw_add_module_library with
|
|
|
|
# all source files that do not end with _test.cc.
|
|
|
|
# 3. Declare a test for each source file that ends with _test.cc.
|
|
|
|
#
|
|
|
|
# Args:
|
|
|
|
# IMPLEMENTS_FACADE: this module implements the specified facade
|
|
|
|
#
|
|
|
|
# All other arguments are forwarded to pw_add_module_library.
|
|
|
|
function(pw_auto_add_simple_module MODULE)
|
|
|
|
cmake_parse_arguments(PARSE_ARGV 1 arg "" "IMPLEMENTS_FACADE" "")
|
|
|
|
|
|
|
|
file(GLOB all_sources *.cc *.c)
|
|
|
|
|
|
|
|
# Create a library with all source files not ending in _test.
|
|
|
|
set(sources "${all_sources}")
|
|
|
|
list(FILTER sources EXCLUDE REGEX "_test.cc$")
|
|
|
|
|
|
|
|
file(GLOB_RECURSE headers *.h)
|
|
|
|
|
|
|
|
if(arg_IMPLEMENTS_FACADE)
|
|
|
|
set(groups backends)
|
|
|
|
set(deps PUBLIC_DEPS "${arg_IMPLEMENTS_FACADE}.facade")
|
|
|
|
else()
|
|
|
|
set(groups modules "${MODULE}")
|
|
|
|
endif()
|
|
|
|
|
|
|
|
pw_add_module_library("${MODULE}"
|
|
|
|
${arg_UNPARSED_ARGUMENTS}
|
|
|
|
SOURCES
|
|
|
|
${sources}
|
|
|
|
HEADERS
|
|
|
|
${headers}
|
|
|
|
${deps}
|
|
|
|
)
|
|
|
|
|
|
|
|
# Create a test for each source file ending in _test. Tests with mutliple .cc
|
|
|
|
# files or different dependencies than the module will not work correctly.
|
|
|
|
set(tests "${all_sources}")
|
|
|
|
list(FILTER tests INCLUDE REGEX "_test.cc$")
|
|
|
|
|
|
|
|
foreach(test IN LISTS tests)
|
2020-01-08 00:19:02 +00:00
|
|
|
get_filename_component(test_name "${test}" NAME_WE)
|
2020-01-09 20:24:24 +00:00
|
|
|
|
|
|
|
# Find a .c test corresponding with the test .cc file, if any.
|
|
|
|
list(FILTER c_test INCLUDE REGEX "^${test_name}.c$")
|
|
|
|
|
2020-01-08 00:19:02 +00:00
|
|
|
pw_add_test("${MODULE}.${test_name}"
|
|
|
|
SOURCES
|
|
|
|
"${test}"
|
2020-01-09 20:24:24 +00:00
|
|
|
${c_test}
|
2020-01-02 15:53:39 +00:00
|
|
|
DEPS
|
|
|
|
"${MODULE}"
|
|
|
|
GROUPS
|
|
|
|
"${groups}"
|
|
|
|
)
|
|
|
|
endforeach()
|
|
|
|
endfunction(pw_auto_add_simple_module)
|
|
|
|
|
|
|
|
# Creates a library in a module. The library has access to the public/ include
|
|
|
|
# directory.
|
|
|
|
#
|
|
|
|
# Args:
|
|
|
|
# SOURCES: source files for this library
|
|
|
|
# HEADERS: header files for this library
|
|
|
|
# PUBLIC_DEPS: public target_link_libraries arguments
|
|
|
|
# PRIVATE_DEPS: private target_link_libraries arguments
|
|
|
|
function(pw_add_module_library NAME)
|
|
|
|
set(list_args SOURCES HEADERS PUBLIC_DEPS PRIVATE_DEPS)
|
|
|
|
cmake_parse_arguments(PARSE_ARGV 1 arg "" "" "${list_args}")
|
|
|
|
|
|
|
|
# Check that the library's name is prefixed by the module name.
|
|
|
|
get_filename_component(module "${CMAKE_CURRENT_SOURCE_DIR}" NAME)
|
|
|
|
|
|
|
|
if(NOT "${NAME}" MATCHES "^${module}(\\.[^\\.]+)?$")
|
|
|
|
message(FATAL_ERROR
|
|
|
|
"Module libraries must match the module name or be in the form "
|
|
|
|
"'MODULE_NAME.LIBRARY_NAME'. "
|
|
|
|
"The library '${NAME}' does not match the module '${module}'."
|
|
|
|
)
|
|
|
|
endif()
|
|
|
|
|
|
|
|
add_library("${NAME}" EXCLUDE_FROM_ALL ${arg_HEADERS} ${arg_SOURCES})
|
|
|
|
target_include_directories("${NAME}" PUBLIC public/)
|
|
|
|
target_link_libraries("${NAME}"
|
|
|
|
PUBLIC
|
|
|
|
pw_build
|
|
|
|
${arg_PUBLIC_DEPS}
|
|
|
|
PRIVATE
|
|
|
|
${arg_PRIVATE_DEPS}
|
|
|
|
)
|
|
|
|
|
|
|
|
# Libraries require at least one source file.
|
|
|
|
if(NOT arg_SOURCES)
|
|
|
|
target_sources("${NAME}" PRIVATE "${_pw_empty_source_file}")
|
|
|
|
endif()
|
|
|
|
endfunction(pw_add_module_library)
|
|
|
|
|
|
|
|
# Declares a module as a facade.
|
|
|
|
#
|
|
|
|
# Facades are declared as two libraries to avoid circular dependencies.
|
|
|
|
# Libraries that use the facade depend on a library named for the module. The
|
|
|
|
# module that implements the facade depends on a library named
|
|
|
|
# MODULE_NAME.facade.
|
|
|
|
#
|
|
|
|
# pw_add_facade accepts the same arguments as pw_add_module_library.
|
|
|
|
function(pw_add_facade MODULE)
|
|
|
|
pw_add_module_library("${MODULE}.facade" ${ARGN})
|
|
|
|
|
|
|
|
# Use a library with an empty source instead of an INTERFACE library so that
|
|
|
|
# the library can have a private dependency on the backend.
|
|
|
|
add_library("${MODULE}" OBJECT EXCLUDE_FROM_ALL "${_pw_empty_source_file}")
|
|
|
|
target_link_libraries("${MODULE}"
|
|
|
|
PUBLIC
|
|
|
|
"${MODULE}.facade"
|
|
|
|
PRIVATE
|
|
|
|
"${MODULE}.backend"
|
|
|
|
)
|
|
|
|
endfunction(pw_add_facade)
|
|
|
|
|
|
|
|
# Declares a unit test. Creates two targets:
|
|
|
|
#
|
|
|
|
# - <TEST_NAME>: the test executable
|
|
|
|
# - <TEST_NAME>_run: builds and runs the test
|
|
|
|
#
|
|
|
|
# Args:
|
2020-01-08 00:19:02 +00:00
|
|
|
# NAME: name to use for the target
|
|
|
|
# SOURCES: source files for this test
|
2020-01-02 15:53:39 +00:00
|
|
|
# DEPS: libraries on which this test depends
|
|
|
|
# GROUPS: groups to which to add this test; if none are specified, the test is
|
|
|
|
# added to the default and all groups
|
2020-01-08 00:19:02 +00:00
|
|
|
function(pw_add_test NAME)
|
|
|
|
cmake_parse_arguments(PARSE_ARGV 1 arg "" "" "SOURCES;DEPS;GROUPS")
|
2020-01-02 15:53:39 +00:00
|
|
|
|
2020-01-08 00:19:02 +00:00
|
|
|
add_executable("${NAME}" EXCLUDE_FROM_ALL ${arg_SOURCES})
|
|
|
|
target_link_libraries("${NAME}"
|
2020-01-02 15:53:39 +00:00
|
|
|
PRIVATE
|
|
|
|
pw_unit_test
|
|
|
|
pw_unit_test.main
|
|
|
|
${arg_DEPS}
|
|
|
|
)
|
|
|
|
|
|
|
|
# Define a target for running the test. The target creates a stamp file to
|
|
|
|
# indicate successful test completion. This allows running tests in parallel
|
|
|
|
# with Ninja's full dependency resolution.
|
|
|
|
add_custom_command(
|
|
|
|
COMMAND
|
|
|
|
# TODO(hepler): This only runs local test binaries. Execute a test runner
|
|
|
|
# instead to support device test runs.
|
2020-01-08 00:19:02 +00:00
|
|
|
"$<TARGET_FILE:${NAME}>"
|
2020-01-02 15:53:39 +00:00
|
|
|
COMMAND
|
2020-01-08 00:19:02 +00:00
|
|
|
"${CMAKE_COMMAND}" -E touch "${NAME}.stamp"
|
2020-01-02 15:53:39 +00:00
|
|
|
DEPENDS
|
2020-01-08 00:19:02 +00:00
|
|
|
"${NAME}"
|
2020-01-02 15:53:39 +00:00
|
|
|
OUTPUT
|
2020-01-08 00:19:02 +00:00
|
|
|
"${NAME}.stamp"
|
2020-01-02 15:53:39 +00:00
|
|
|
)
|
2020-01-08 00:19:02 +00:00
|
|
|
add_custom_target("${NAME}_run" DEPENDS "${NAME}.stamp")
|
2020-01-02 15:53:39 +00:00
|
|
|
|
|
|
|
# Always add tests to the "all" group. If no groups are provided, add the
|
|
|
|
# test to the "default" group.
|
|
|
|
if(arg_GROUPS)
|
|
|
|
set(groups all ${arg_GROUPS})
|
|
|
|
else()
|
|
|
|
set(groups all default)
|
|
|
|
endif()
|
|
|
|
|
|
|
|
list(REMOVE_DUPLICATES groups)
|
2020-01-08 00:19:02 +00:00
|
|
|
pw_add_test_to_groups("${NAME}" ${groups})
|
2020-01-02 15:53:39 +00:00
|
|
|
endfunction(pw_add_test)
|
|
|
|
|
|
|
|
# Adds a test target to the specified test groups. Test groups can be built with
|
|
|
|
# the pw_tests_GROUP_NAME target or executed with the pw_run_tests_GROUP_NAME
|
|
|
|
# target.
|
|
|
|
function(pw_add_test_to_groups TEST_NAME)
|
|
|
|
foreach(group IN LISTS ARGN)
|
2020-01-08 22:23:26 +00:00
|
|
|
if(NOT TARGET "pw_tests.${group}")
|
|
|
|
add_custom_target("pw_tests.${group}")
|
|
|
|
add_custom_target("pw_run_tests.${group}")
|
2020-01-02 15:53:39 +00:00
|
|
|
endif()
|
|
|
|
|
2020-01-08 22:23:26 +00:00
|
|
|
add_dependencies("pw_tests.${group}" "${TEST_NAME}")
|
|
|
|
add_dependencies("pw_run_tests.${group}" "${TEST_NAME}_run")
|
2020-01-02 15:53:39 +00:00
|
|
|
endforeach()
|
|
|
|
endfunction(pw_add_test_to_groups)
|
|
|
|
|
|
|
|
# Declare top-level targets for tests.
|
2020-01-08 22:23:26 +00:00
|
|
|
add_custom_target(pw_tests.default)
|
|
|
|
add_custom_target(pw_run_tests.default)
|
2020-01-02 15:53:39 +00:00
|
|
|
|
2020-01-08 22:23:26 +00:00
|
|
|
add_custom_target(pw_tests DEPENDS pw_tests.default)
|
|
|
|
add_custom_target(pw_run_tests DEPENDS pw_run_tests.default)
|
2020-01-02 15:53:39 +00:00
|
|
|
|
|
|
|
# Define the standard Pigweed compile options.
|
|
|
|
add_library(_pw_reduced_size_copts INTERFACE)
|
|
|
|
target_compile_options(_pw_reduced_size_copts
|
|
|
|
INTERFACE
|
|
|
|
"-fno-common"
|
|
|
|
"-fno-exceptions"
|
|
|
|
"-ffunction-sections"
|
|
|
|
"-fdata-sections"
|
2020-01-08 00:19:02 +00:00
|
|
|
$<$<COMPILE_LANGUAGE:CXX>:-fno-rtti>
|
2020-01-02 15:53:39 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
add_library(_pw_strict_warnings_copts INTERFACE)
|
|
|
|
target_compile_options(_pw_strict_warnings_copts
|
|
|
|
INTERFACE
|
|
|
|
"-Wall"
|
|
|
|
"-Wextra"
|
|
|
|
# Make all warnings errors, except for the exemptions below.
|
|
|
|
"-Werror"
|
|
|
|
"-Wno-error=cpp" # preprocessor #warning statement
|
|
|
|
"-Wno-error=deprecated-declarations" # [[deprecated]] attribute
|
2020-01-08 00:19:02 +00:00
|
|
|
$<$<COMPILE_LANGUAGE:CXX>:-Wnon-virtual-dtor>
|
2020-01-02 15:53:39 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
add_library(_pw_cpp17_copts INTERFACE)
|
|
|
|
target_compile_options(_pw_cpp17_copts
|
|
|
|
INTERFACE
|
2020-01-08 00:19:02 +00:00
|
|
|
$<$<COMPILE_LANGUAGE:CXX>:-std=c++17>
|
2020-01-02 15:53:39 +00:00
|
|
|
# Allow uses of the register keyword, which may appear in C headers.
|
2020-01-08 00:19:02 +00:00
|
|
|
$<$<COMPILE_LANGUAGE:CXX>:-Wno-register>
|
2020-01-02 15:53:39 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
# Target that specifies the standard Pigweed build options.
|
|
|
|
add_library(pw_build INTERFACE)
|
|
|
|
target_link_libraries(pw_build
|
|
|
|
INTERFACE
|
|
|
|
_pw_reduced_size_copts
|
|
|
|
_pw_strict_warnings_copts
|
|
|
|
_pw_cpp17_copts
|
|
|
|
)
|
2020-01-08 22:23:26 +00:00
|
|
|
target_compile_options(pw_build
|
|
|
|
INTERFACE
|
|
|
|
# Force the compiler use colorized output. This is required for Ninja.
|
|
|
|
$<$<CXX_COMPILER_ID:Clang>:-fcolor-diagnostics>
|
|
|
|
$<$<CXX_COMPILER_ID:GNU>:-fdiagnostics-color=always>
|
|
|
|
)
|