blob: 2869a77260045052c95c677d1181e0a54644e9dc [file] [log] [blame] [edit]
# Copyright 2023 Google LLC
#
# 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.
include(CMakeParseArguments)
# fuzztest_cc_library()
#
# CMake function to imitate Bazel's cc_library rule.
#
# Parameters:
#
# NAME: Name of target (see Note)
# HDRS: List of public header files for the library
# SRCS: List of source files for the library
# DEPS: List of other libraries to be linked in to the binary targets
# COPTS: List of private compile options
# DEFINES: List of public defines
# LINKOPTS: List of link options
# PUBLIC: Add this so that this library will be exported under fuzztest::
# TESTONLY: When added, this target will only be built if both
# BUILD_TESTING=ON and FUZZTEST_BUILD_TESTING=ON.
#
# Note:
#
# By default, fuzztest_cc_library will always create a library named
# fuzztest_${NAME}, and alias target fuzztest::${NAME}. The fuzztest:: form
# should always be used. This is to reduce namespace pollution.
#
# Usage:
#
# fuzztest_cc_library(
# NAME
# awesome
# HDRS
# "a.h"
# SRCS
# "a.cc"
# )
# fuzztest_cc_library(
# NAME
# fantastic_lib
# SRCS
# "b.cc"
# DEPS
# fuzztest::awesome # not "awesome" !
# PUBLIC
# )
#
# fuzztest_cc_library(
# NAME
# main_lib
# ...
# DEPS
# fuzztest::fantastic_lib
# )
#
function(fuzztest_cc_library)
cmake_parse_arguments(
FUZZTEST_CC_LIB
"PUBLIC;TESTONLY"
"NAME"
"HDRS;SRCS;COPTS;DEFINES;LINKOPTS;DEPS"
${ARGN}
)
if(FUZZTEST_CC_LIB_TESTONLY AND NOT (BUILD_TESTING AND FUZZTEST_BUILD_TESTING))
return()
endif()
set(_NAME "fuzztest_${FUZZTEST_CC_LIB_NAME}")
# Check if this is a header-only library
# TODO: Use list(FILTER...)
set(FUZZTEST_CC_SRCS "${FUZZTEST_CC_LIB_SRCS}")
foreach(src_file IN LISTS FUZZTEST_CC_SRCS)
if(${src_file} MATCHES ".*\\.(h|inc)")
list(REMOVE_ITEM FUZZTEST_CC_SRCS "${src_file}")
endif()
endforeach()
if(FUZZTEST_CC_SRCS STREQUAL "")
set(FUZZTEST_CC_LIB_IS_INTERFACE 1)
else()
set(FUZZTEST_CC_LIB_IS_INTERFACE 0)
endif()
if(NOT FUZZTEST_CC_LIB_IS_INTERFACE)
add_library(${_NAME} "")
target_sources(
${_NAME}
PRIVATE
${FUZZTEST_CC_LIB_SRCS}
${FUZZTEST_CC_LIB_HDRS}
)
target_link_libraries(
${_NAME}
PUBLIC
${FUZZTEST_CC_LIB_DEPS}
PRIVATE
${FUZZTEST_CC_LIB_LINKOPTS}
${FUZZTEST_DEFAULT_LINKOPTS}
)
set_property(
TARGET ${_NAME}
PROPERTY LINKER_LANGUAGE "CXX")
target_include_directories(
${_NAME}
PUBLIC
"$<BUILD_INTERFACE:${fuzztest_SOURCE_DIR}>"
"$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_INCLUDEDIR}>"
)
target_compile_options(
${_NAME}
PRIVATE
${FUZZTEST_CC_LIB_COPTS}
)
target_compile_definitions(
${_NAME}
PUBLIC
${FUZZTEST_CC_LIB_DEFINES}
)
else()
# Header-only library.
add_library(
${_NAME}
INTERFACE
)
target_include_directories(
${_NAME}
INTERFACE
"$<BUILD_INTERFACE:${fuzztest_SOURCE_DIR}>"
"$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_INCLUDEDIR}>"
)
target_link_libraries(
${_NAME}
INTERFACE
${FUZZTEST_CC_LIB_DEPS}
${FUZZTEST_CC_LIB_LINKOPTS}
${FUZZTEST_DEFAULT_LINKOPTS}
)
target_compile_definitions(
${_NAME}
INTERFACE
${FUZZTEST_CC_LIB_DEFINES})
endif()
add_library(fuzztest::${FUZZTEST_CC_LIB_NAME} ALIAS ${_NAME})
endfunction()
# fuzztest_cc_test()
#
# CMake function to imitate Bazel's cc_test rule.
#
# Parameters:
#
# NAME: name of target (see Usage below)
# SRCS: List of source files for the binary
# DEPS: List of other libraries to be linked in to the binary targets
# COPTS: List of private compile options
# DEFINES: List of public defines
# LINKOPTS: List of link options
#
# Note:
#
# By default, fuzztest_cc_test will always create a binary named
# fuzztest_${NAME}. This will also add it to ctest list as fuzztest_${NAME}.
#
# Usage:
#
# fuzztest_cc_library(
# NAME
# awesome
# HDRS
# "a.h"
# SRCS
# "a.cc"
# PUBLIC
# )
#
# fuzztest_cc_test(
# NAME
# awesome_test
# SRCS
# "awesome_test.cc"
# DEPS
# fuzztest::awesome
# GTest::gmock
# GTest::gtest_main
# )
#
function(fuzztest_cc_test)
if(NOT (BUILD_TESTING AND FUZZTEST_BUILD_TESTING))
return()
endif()
cmake_parse_arguments(FUZZTEST_CC_TEST
""
"NAME"
"SRCS;COPTS;DEFINES;LINKOPTS;DEPS"
${ARGN}
)
set(_NAME "fuzztest_${FUZZTEST_CC_TEST_NAME}")
add_executable(
${_NAME}
""
)
target_sources(
${_NAME}
PRIVATE
${FUZZTEST_CC_TEST_SRCS}
)
target_include_directories(
${_NAME}
PUBLIC
"$<BUILD_INTERFACE:${fuzztest_SOURCE_DIR}>"
)
target_compile_definitions(
${_NAME}
PUBLIC
${FUZZTEST_CC_TEST_DEFINES}
)
target_compile_options(
${_NAME}
PRIVATE
${FUZZTEST_CC_TEST_COPTS}
)
target_link_libraries(
${_NAME}
PUBLIC
${FUZZTEST_CC_TEST_DEPS}
PRIVATE
${FUZZTEST_CC_TEST_LINKOPTS}
)
add_test(NAME ${_NAME} COMMAND ${_NAME})
endfunction()
# fuzztest_proto_library()
#
# CMake function to imitate Bazel's proto_library rule.
#
# Parameters:
#
# NAME: Name of target (see Note)
# SRCS: List of source files for the proto library
# PUBLIC: Add this so that this library will be exported under fuzztest::
# TESTONLY: When added, this target will only be built if both
# BUILD_TESTING=ON and FUZZTEST_BUILD_TESTING=ON.
#
# Usage:
#
# fuzztest_proto_library(
# NAME
# awesome_proto
# SRCS
# "awesome.proto"
# )
#
# Reference:
#
# https://github.com/protocolbuffers/protobuf/blob/main/docs/cmake_protobuf_generate.md
#
function(fuzztest_proto_library)
cmake_parse_arguments(
FUZZTEST_PROTO_LIB
"PUBLIC;TESTONLY"
"NAME"
"SRCS"
${ARGN}
)
if(FUZZTEST_PROTO_LIB_TESTONLY AND NOT (BUILD_TESTING AND FUZZTEST_BUILD_TESTING))
return()
endif()
set(_NAME "fuzztest_${FUZZTEST_PROTO_LIB_NAME}")
add_library(
${_NAME}
OBJECT
${FUZZTEST_PROTO_LIB_SRCS}
)
target_link_libraries(
${_NAME}
PUBLIC
protobuf::libprotobuf
)
target_include_directories(
${_NAME}
PUBLIC
"$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}>"
)
protobuf_generate(
TARGET
${_NAME}
IMPORT_DIRS
${CMAKE_CURRENT_LIST_DIR}
PROTOC_OUT_DIR
${CMAKE_CURRENT_BINARY_DIR}
)
add_library(fuzztest::${FUZZTEST_PROTO_LIB_NAME} ALIAS ${_NAME})
endfunction()
# fuzztest_flatbuffers_generate_headers()
#
# Modified version of `flatbuffers_generate_headers`
# from https://github.com/google/flatbuffers/blob/master/CMake/BuildFlatBuffers.cmake
# Supports having the embedded schema header in the output set.
#
# Creates a target that can be linked against that generates flatbuffer headers.
#
# This function takes a target name and a list of schemas. You can also specify
# other flagc flags using the FLAGS option to change the behavior of the flatc
# tool.
#
# When the target_link_libraries is done within a different directory than
# flatbuffers_generate_headers is called, then the target should also be dependent
# the custom generation target called fuzztest_GENERATE_<TARGET>.
#
# Arguments:
# TARGET: The name of the target to generate.
# SCHEMAS: The list of schema files to generate code for.
# BINARY_SCHEMAS_DIR: Optional. The directory in which to generate binary
# schemas. Binary schemas will only be generated if a path is provided.
# INCLUDE: Optional. Search for includes in the specified paths. (Use this
# instead of "-I <path>" and the FLAGS option so that CMake is aware of
# the directories that need to be searched).
# INCLUDE_PREFIX: Optional. The directory in which to place the generated
# files. Use this instead of the --include-prefix option.
# FLAGS: Optional. A list of any additional flags that you would like to pass
# to flatc.
# TESTONLY: When added, this target will only be built if both
# BUILD_TESTING=ON and FUZZTEST_BUILD_TESTING=ON.
#
# Example:
#
# fuzztest_flatbuffers_library(
# TARGET my_generated_headers_target
# INCLUDE_PREFIX ${MY_INCLUDE_PREFIX}"
# SCHEMAS ${MY_SCHEMA_FILES}
# BINARY_SCHEMAS_DIR "${MY_BINARY_SCHEMA_DIRECTORY}"
# FLAGS --gen-object-api)
#
# target_link_libraries(MyExecutableTarget
# PRIVATE fuzztest_my_generated_headers_target
# )
#
# Optional (only needed within different directory):
# add_dependencies(app fuzztest_GENERATE_my_generated_headers_target)
function(fuzztest_flatbuffers_generate_headers)
# Parse function arguments.
set(options TESTONLY)
set(one_value_args
"TARGET"
"INCLUDE_PREFIX"
"BINARY_SCHEMAS_DIR")
set(multi_value_args
"SCHEMAS"
"INCLUDE"
"FLAGS")
cmake_parse_arguments(
PARSE_ARGV 0
FLATBUFFERS_GENERATE_HEADERS
"${options}"
"${one_value_args}"
"${multi_value_args}")
if(FLATBUFFERS_GENERATE_HEADERS_TESTONLY AND NOT (BUILD_TESTING AND FUZZTEST_BUILD_TESTING))
return()
endif()
# Test if including from FindFlatBuffers
if(FLATBUFFERS_FLATC_EXECUTABLE)
set(FLATC_TARGET "")
set(FLATC ${FLATBUFFERS_FLATC_EXECUTABLE})
elseif(TARGET flatbuffers::flatc)
set(FLATC_TARGET flatbuffers::flatc)
set(FLATC flatbuffers::flatc)
else()
set(FLATC_TARGET flatc)
set(FLATC flatc)
endif()
set(working_dir "${CMAKE_CURRENT_SOURCE_DIR}")
# Generate the include files parameters.
set(include_params "")
foreach (include_dir ${FLATBUFFERS_GENERATE_HEADERS_INCLUDE})
set(include_params -I ${include_dir} ${include_params})
endforeach()
# Create a directory to place the generated code.
set(generated_target_dir "${CMAKE_CURRENT_BINARY_DIR}")
set(generated_include_dir "${generated_target_dir}")
if (NOT ${FLATBUFFERS_GENERATE_HEADERS_INCLUDE_PREFIX} STREQUAL "")
set(generated_include_dir "${generated_include_dir}/${FLATBUFFERS_GENERATE_HEADERS_INCLUDE_PREFIX}")
list(APPEND FLATBUFFERS_GENERATE_HEADERS_FLAGS
"--include-prefix" ${FLATBUFFERS_GENERATE_HEADERS_INCLUDE_PREFIX})
endif()
set(generated_custom_commands)
# Create rules to generate the code for each schema.
foreach(schema ${FLATBUFFERS_GENERATE_HEADERS_SCHEMAS})
get_filename_component(filename ${schema} NAME_WE)
set(generated_include "${generated_include_dir}/${filename}_generated.h")
# Add the embedded schema header in the output set if requested.
if("${FLATBUFFERS_GENERATE_HEADERS_FLAGS}" MATCHES "--bfbs-gen-embed")
list(APPEND generated_include "${generated_include_dir}/${filename}_bfbs_generated.h")
endif()
# Generate files for grpc if needed
set(generated_source_file)
if("${FLATBUFFERS_GENERATE_HEADERS_FLAGS}" MATCHES "--grpc")
# Check if schema file contain a rpc_service definition
file(STRINGS ${schema} has_grpc REGEX "rpc_service")
if(has_grpc)
list(APPEND generated_include "${generated_include_dir}/${filename}.grpc.fb.h")
set(generated_source_file "${generated_include_dir}/${filename}.grpc.fb.cc")
endif()
endif()
add_custom_command(
OUTPUT ${generated_include} ${generated_source_file}
COMMAND ${FLATC} ${FLATC_ARGS}
-o ${generated_include_dir}
${include_params}
-c ${schema}
${FLATBUFFERS_GENERATE_HEADERS_FLAGS}
DEPENDS ${FLATC_TARGET} ${schema}
WORKING_DIRECTORY "${working_dir}"
COMMENT "Building ${schema} flatbuffers...")
list(APPEND all_generated_header_files ${generated_include})
list(APPEND all_generated_source_files ${generated_source_file})
list(APPEND generated_custom_commands "${generated_include}" "${generated_source_file}")
# Generate the binary flatbuffers schemas if instructed to.
if (NOT ${FLATBUFFERS_GENERATE_HEADERS_BINARY_SCHEMAS_DIR} STREQUAL "")
set(binary_schema
"${FLATBUFFERS_GENERATE_HEADERS_BINARY_SCHEMAS_DIR}/${filename}.bfbs")
add_custom_command(
OUTPUT ${binary_schema}
COMMAND ${FLATC} -b --schema
-o ${FLATBUFFERS_GENERATE_HEADERS_BINARY_SCHEMAS_DIR}
${include_params}
${schema}
DEPENDS ${FLATC_TARGET} ${schema}
WORKING_DIRECTORY "${working_dir}")
list(APPEND generated_custom_commands "${binary_schema}")
list(APPEND all_generated_binary_files ${binary_schema})
endif()
endforeach()
# Create an additional target as add_custom_command scope is only within same directory (CMakeFile.txt)
set(generate_target fuzztest_GENERATE_${FLATBUFFERS_GENERATE_HEADERS_TARGET})
add_custom_target(${generate_target} ALL
DEPENDS ${generated_custom_commands}
COMMENT "Generating flatbuffer target fuzztest_${FLATBUFFERS_GENERATE_HEADERS_TARGET}")
# Set up interface library
add_library(fuzztest_${FLATBUFFERS_GENERATE_HEADERS_TARGET} INTERFACE)
add_dependencies(
fuzztest_${FLATBUFFERS_GENERATE_HEADERS_TARGET}
${FLATC}
${FLATBUFFERS_GENERATE_HEADERS_SCHEMAS})
target_include_directories(
fuzztest_${FLATBUFFERS_GENERATE_HEADERS_TARGET}
INTERFACE ${generated_target_dir})
# Organize file layout for IDEs.
source_group(
TREE "${generated_target_dir}"
PREFIX "Flatbuffers/Generated/Headers Files"
FILES ${all_generated_header_files})
source_group(
TREE "${generated_target_dir}"
PREFIX "Flatbuffers/Generated/Source Files"
FILES ${all_generated_source_files})
source_group(
TREE ${working_dir}
PREFIX "Flatbuffers/Schemas"
FILES ${FLATBUFFERS_GENERATE_HEADERS_SCHEMAS})
if (NOT ${FLATBUFFERS_GENERATE_HEADERS_BINARY_SCHEMAS_DIR} STREQUAL "")
source_group(
TREE "${FLATBUFFERS_GENERATE_HEADERS_BINARY_SCHEMAS_DIR}"
PREFIX "Flatbuffers/Generated/Binary Schemas"
FILES ${all_generated_binary_files})
endif()
endfunction()